From 28ae70d88ad6a11f4decc69d25aa58379baca54b Mon Sep 17 00:00:00 2001 From: abhishkk Date: Mon, 26 Feb 2018 16:21:59 +0530 Subject: [PATCH 1/3] Fix: Design mode clients hang for errors --- .../Parallel/ParallelProxyDiscoveryManager.cs | 34 +++++-- .../Parallel/ParallelProxyExecutionManager.cs | 28 ++++-- .../Client/ProxyDiscoveryManager.cs | 10 +- .../Client/ProxyExecutionManager.cs | 8 +- .../ParallelProxyDiscoveryManagerTests.cs | 46 ++++++++++ .../ParallelProxyExecutionManagerTests.cs | 49 ++++++++++ .../Client/ProxyDiscoveryManagerTests.cs | 92 +++++++++++++++++-- .../Client/ProxyExecutionManagerTests.cs | 83 +++++++++++++++-- 8 files changed, 317 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs index 8f43b5eba3..30e7876731 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs @@ -8,15 +8,21 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel using System.Linq; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; /// /// ParallelProxyDiscoveryManager that manages parallel discovery /// internal class ParallelProxyDiscoveryManager : ParallelOperationManager, IParallelProxyDiscoveryManager { + private IDataSerializer dataSerializer; + #region DiscoverySpecificData private int discoveryCompletedClients = 0; @@ -42,15 +48,21 @@ internal class ParallelProxyDiscoveryManager : ParallelOperationManager actualProxyManagerCreator, int parallelLevel, bool sharedHosts) + : this(requestData, actualProxyManagerCreator, JsonDataSerializer.Instance, parallelLevel, sharedHosts) + { + } + + internal ParallelProxyDiscoveryManager(IRequestData requestData, Func actualProxyManagerCreator, IDataSerializer dataSerializer, int parallelLevel, bool sharedHosts) : base(actualProxyManagerCreator, parallelLevel, sharedHosts) { this.requestData = requestData; + this.dataSerializer = dataSerializer; } #region IProxyDiscoveryManager - + /// public void Initialize() { @@ -61,12 +73,12 @@ public void Initialize() public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 eventHandler) { this.actualDiscoveryCriteria = discoveryCriteria; - + // Set the enumerator for parallel yielding of sources // Whenever a concurrent executor becomes free, it picks up the next source using this enumerator this.sourceEnumerator = discoveryCriteria.Sources.GetEnumerator(); this.availableTestSources = discoveryCriteria.Sources.Count(); - + if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose("ParallelProxyDiscoveryManager: Start discovery. Total sources: " + this.availableTestSources); @@ -210,19 +222,23 @@ private void DiscoverTestsOnConcurrentManager(IProxyDiscoveryManager proxyDiscov // Just in case, the actual discovery couldn't start for an instance. Ensure that // we call discovery complete since we have already fetched a source. Otherwise // discovery will not terminate - if (EqtTrace.IsWarningEnabled) + if (EqtTrace.IsErrorEnabled) { - EqtTrace.Warning("ParallelProxyDiscoveryManager: Failed to trigger discovery. Exception: " + t.Exception); + EqtTrace.Error("ParallelProxyDiscoveryManager: Failed to trigger discovery. Exception: " + t.Exception); } + var handler = this.GetHandlerForGivenManager(proxyDiscoveryManager); + var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = t.Exception.ToString() }; + handler.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); + handler.HandleLogMessage(TestMessageLevel.Error, t.Exception.ToString()); + // Send discovery complete. Similar logic is also used in ProxyDiscoveryManager.DiscoverTests. // Differences: // Total tests must be zero here since parallel discovery events handler adds the count // Keep `lastChunk` as null since we don't want a message back to the IDE (discovery didn't even begin) // Set `isAborted` as true since we want this instance of discovery manager to be replaced var discoveryCompleteEventsArgs = new DiscoveryCompleteEventArgs(-1, true); - - this.GetHandlerForGivenManager(proxyDiscoveryManager).HandleDiscoveryComplete(discoveryCompleteEventsArgs, null); + handler.HandleDiscoveryComplete(discoveryCompleteEventsArgs, null); }, TaskContinuationOptions.OnlyOnFaulted); } @@ -233,4 +249,4 @@ private void DiscoverTestsOnConcurrentManager(IProxyDiscoveryManager proxyDiscov } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs index 74dd0c7c4f..1828170e3b 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs @@ -11,16 +11,22 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; /// /// ParallelProxyExecutionManager that manages parallel execution /// internal class ParallelProxyExecutionManager : ParallelOperationManager, IParallelProxyExecutionManager { + private IDataSerializer dataSerializer; + #region TestRunSpecificData // This variable id to differentiate between implicit (abort requested by testPlatform) and explicit (test host aborted) abort. @@ -60,15 +66,20 @@ internal class ParallelProxyExecutionManager : ParallelOperationManager actualProxyManagerCreator, int parallelLevel) - : base(actualProxyManagerCreator, parallelLevel, true) + : this(requestData, actualProxyManagerCreator, JsonDataSerializer.Instance, parallelLevel, true) { - this.requestData = requestData; } public ParallelProxyExecutionManager(IRequestData requestData, Func actualProxyManagerCreator, int parallelLevel, bool sharedHosts) + : this(requestData, actualProxyManagerCreator, JsonDataSerializer.Instance, parallelLevel, sharedHosts) + { + } + + internal ParallelProxyExecutionManager(IRequestData requestData, Func actualProxyManagerCreator, IDataSerializer dataSerializer, int parallelLevel, bool sharedHosts) : base(actualProxyManagerCreator, parallelLevel, sharedHosts) { this.requestData = requestData; + this.dataSerializer = dataSerializer; } #region IProxyExecutionManager @@ -325,18 +336,23 @@ private void StartTestRunOnConcurrentManager(IProxyExecutionManager proxyExecuti // Just in case, the actual execution couldn't start for an instance. Ensure that // we call execution complete since we have already fetched a source. Otherwise // execution will not terminate - if (EqtTrace.IsWarningEnabled) + if (EqtTrace.IsErrorEnabled) { - EqtTrace.Warning("ParallelProxyExecutionManager: Failed to trigger execution. Exception: " + t.Exception); + EqtTrace.Error("ParallelProxyExecutionManager: Failed to trigger execution. Exception: " + t.Exception); } + var handler = this.GetHandlerForGivenManager(proxyExecutionManager); + var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = t.Exception.ToString() }; + handler.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); + handler.HandleLogMessage(TestMessageLevel.Error, t.Exception.ToString()); + // Send a run complete to caller. Similar logic is also used in ProxyExecutionManager.StartTestRun // Differences: // Aborted is sent to allow the current execution manager replaced with another instance // Ensure that the test run aggregator in parallel run events handler doesn't add these statistics // (since the test run didn't even start) var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection(), TimeSpan.Zero); - this.GetHandlerForGivenManager(proxyExecutionManager).HandleTestRunComplete(completeArgs, null, null, null); + handler.HandleTestRunComplete(completeArgs, null, null, null); }, TaskContinuationOptions.OnlyOnFaulted); } @@ -347,4 +363,4 @@ private void StartTestRunOnConcurrentManager(IProxyExecutionManager proxyExecuti } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index c62c0cb4dd..741e8db236 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -122,8 +122,14 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve // and the test host is lost as well. this.HandleLogMessage(TestMessageLevel.Error, exception.ToString()); + var discoveryCompletePayload = new DiscoveryCompletePayload() + { + IsAborted = true, + LastDiscoveredTests = null, + TotalTests = -1 + }; + this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.DiscoveryComplete, discoveryCompletePayload)); var discoveryCompleteEventsArgs = new DiscoveryCompleteEventArgs(-1, true); - this.HandleDiscoveryComplete(discoveryCompleteEventsArgs, new List()); } } @@ -179,4 +185,4 @@ private void InitializeExtensions(IEnumerable sources) } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index af9ef23454..dbbc4a7223 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -152,13 +152,19 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH catch (Exception exception) { EqtTrace.Error("ProxyExecutionManager.StartTestRun: Failed to start test run: {0}", exception); + + // Log error message to design mode and CLI. + var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = exception.ToString() }; + this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); this.LogMessage(TestMessageLevel.Error, exception.ToString()); // Send a run complete to caller. Similar logic is also used in ParallelProxyExecutionManager.StartTestRunOnConcurrentManager // Aborted is `true`: in case of parallel run (or non shared host), an aborted message ensures another execution manager // created to replace the current one. This will help if the current execution manager is aborted due to irreparable error // and the test host is lost as well. - var completeArgs = new TestRunCompleteEventArgs(null, false, true, exception, new Collection(), TimeSpan.Zero); + var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection(), TimeSpan.Zero); + var testRunCompletePayload = new TestRunCompletePayload { TestRunCompleteArgs = completeArgs }; + this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.ExecutionComplete, testRunCompletePayload)); this.HandleTestRunComplete(completeArgs, null, null, null); } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs index a3de8cac8c..2e0272a58b 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs @@ -10,12 +10,14 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -134,6 +136,50 @@ public void DiscoveryTestsShouldProcessAllSourceIfOneDiscoveryManagerIsStarved() Assert.AreEqual(1, processedSources.Count, "All Sources must be processed."); } + [TestMethod] + public void DiscoveryTestsShouldCatchExceptionAndHandleLogMessageOfError() + { + // Ensure that second discovery manager never starts. Expect 10 total tests. + // Override DiscoveryComplete since overall aborted should be true + var parallelDiscoveryManager = this.SetupDiscoveryManager(this.proxyManagerFunc, 2, false, totalTests: 10); + this.createdMockManagers[1].Reset(); + this.createdMockManagers[1].Setup(dm => dm.DiscoverTests(It.IsAny(), It.IsAny())) + .Throws(); + this.mockHandler.Setup(mh => mh.HandleDiscoveryComplete(It.IsAny(), null)) + .Callback>((t, l) => { this.discoveryCompleted.Set(); }); + + Task.Run(() => + { + parallelDiscoveryManager.DiscoverTests(this.testDiscoveryCriteria, this.mockHandler.Object); + }); + + // Processed sources should be 1 since the 2nd source is never discovered + Assert.IsTrue(this.discoveryCompleted.Wait(ParallelProxyDiscoveryManagerTests.taskTimeout), "Test discovery not completed."); + mockHandler.Verify(s => s.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); + } + + [TestMethod] + public void DiscoveryTestsShouldCatchExceptionAndHandleRawMessageOfTestMessage() + { + // Ensure that second discovery manager never starts. Expect 10 total tests. + // Override DiscoveryComplete since overall aborted should be true + var parallelDiscoveryManager = this.SetupDiscoveryManager(this.proxyManagerFunc, 2, false, totalTests: 10); + this.createdMockManagers[1].Reset(); + this.createdMockManagers[1].Setup(dm => dm.DiscoverTests(It.IsAny(), It.IsAny())) + .Throws(); + this.mockHandler.Setup(mh => mh.HandleDiscoveryComplete(It.IsAny(), null)) + .Callback>((t, l) => { this.discoveryCompleted.Set(); }); + + Task.Run(() => + { + parallelDiscoveryManager.DiscoverTests(this.testDiscoveryCriteria, this.mockHandler.Object); + }); + + // Processed sources should be 1 since the 2nd source is never discovered + Assert.IsTrue(this.discoveryCompleted.Wait(ParallelProxyDiscoveryManagerTests.taskTimeout), "Test discovery not completed."); + mockHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.TestMessage)))); + } + [TestMethod] public void HandlePartialDiscoveryCompleteShouldCreateANewProxyDiscoveryManagerIfIsAbortedIsTrue() { diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs index 186f4ee97e..2980a629ce 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs @@ -12,6 +12,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; @@ -19,6 +20,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -120,6 +122,20 @@ public void StartTestRunShouldProcessAllSources() AssertMissingAndDuplicateSources(processedSources); } + [TestMethod] + public void StartTestRunShouldProcessAllSources1() + { + // Testcase filter should be passed to all parallel test run criteria. + this.testRunCriteriaWithSources.TestCaseFilter = "Name~Test"; + var parallelExecutionManager = this.SetupExecutionManager(this.proxyManagerFunc, 2); + + parallelExecutionManager.StartTestRun(testRunCriteriaWithSources, this.mockHandler.Object); + + Assert.IsTrue(this.executionCompleted.Wait(taskTimeout), "Test run not completed."); + Assert.AreEqual(this.sources.Count, processedSources.Count, "All Sources must be processed."); + AssertMissingAndDuplicateSources(processedSources); + } + [TestMethod] public void StartTestRunShouldProcessAllTestCases() { @@ -256,6 +272,39 @@ public void StartTestRunShouldProcessAllSourceIfOneDiscoveryManagerIsStarved() Assert.AreEqual(1, this.processedSources.Count, "All Sources must be processed."); } + [TestMethod] + public void StartTestRunShouldCatchExceptionAndHandleLogMessageOfError() + { + var parallelExecutionManager = this.SetupExecutionManager(this.proxyManagerFunc, 2); + this.createdMockManagers[1].Reset(); + this.createdMockManagers[1].Setup(em => em.StartTestRun(It.IsAny(), It.IsAny())) + .Throws(); + + Task.Run(() => + { + parallelExecutionManager.StartTestRun(this.testRunCriteriaWithSources, this.mockHandler.Object); + }); + + Assert.IsTrue(this.executionCompleted.Wait(taskTimeout), "Test run not completed."); + mockHandler.Verify(s => s.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); + } + + [TestMethod] + public void StartTestRunShouldCatchExceptionAndHandleRawMessageOfTestMessage() + { + var parallelExecutionManager = this.SetupExecutionManager(this.proxyManagerFunc, 2); + this.createdMockManagers[1].Reset(); + this.createdMockManagers[1].Setup(em => em.StartTestRun(It.IsAny(), It.IsAny())) + .Throws(); + + Task.Run(() => + { + parallelExecutionManager.StartTestRun(this.testRunCriteriaWithSources, this.mockHandler.Object); + }); + + Assert.IsTrue(this.executionCompleted.Wait(taskTimeout), "Test run not completed."); + mockHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.TestMessage)))); + } [TestMethod] public void StartTestRunShouldAggregateRunData() diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs index 2d417e5923..ca32c06ebf 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs @@ -268,6 +268,76 @@ public void DiscoverTestsShouldCatchExceptionAndCallHandleDiscoveryComplete() mockTestDiscoveryEventsHandler.Verify(s => s.HandleLogMessage(TestMessageLevel.Error, It.IsAny())); } + [TestMethod] + public void DiscoverTestsShouldCatchExceptionAndCallHandleRawMessageOfDiscoveryComplete() + { + // Setup mocks. + Mock mockTestDiscoveryEventsHandler = new Mock(); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.DiscoveryComplete, It.IsAny())).Returns(MessageType.DiscoveryComplete); + + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => + { + var messageType = rawMessage.Contains(MessageType.DiscoveryComplete) ? MessageType.DiscoveryComplete : MessageType.TestMessage; + var message = new Message + { + MessageType = messageType + }; + + return message; + }); + + // Act. + this.testDiscoveryManager.DiscoverTests(this.discoveryCriteria, mockTestDiscoveryEventsHandler.Object); + + // Verify + mockTestDiscoveryEventsHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.DiscoveryComplete))), Times.Once); + } + + [TestMethod] + public void DiscoverTestsShouldCatchExceptionAndCallHandleRawMessageOfTestMessage() + { + // Setup mocks. + Mock mockTestDiscoveryEventsHandler = new Mock(); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.DiscoveryComplete, It.IsAny())).Returns(MessageType.DiscoveryComplete); + + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => + { + var messageType = rawMessage.Contains(MessageType.DiscoveryComplete) ? MessageType.DiscoveryComplete : MessageType.TestMessage; + var message = new Message + { + MessageType = messageType + }; + + return message; + }); + + // Act. + this.testDiscoveryManager.DiscoverTests(this.discoveryCriteria, mockTestDiscoveryEventsHandler.Object); + + // Verify + mockTestDiscoveryEventsHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.TestMessage))), Times.Once); + } + + [TestMethod] + public void DiscoverTestsShouldCatchExceptionAndCallHandleLogMessageOfError() + { + // Setup mocks. + Mock mockTestDiscoveryEventsHandler = new Mock(); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + // Act. + this.testDiscoveryManager.DiscoverTests(this.discoveryCriteria, mockTestDiscoveryEventsHandler.Object); + + // Verify + mockTestDiscoveryEventsHandler.Verify(s => s.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); + } + [TestMethod] public void DiscoverTestsShouldInitiateServerDiscoveryLoop() { @@ -286,15 +356,19 @@ public void DiscoverTestsCloseTestHostIfRawMessageIsOfTypeDiscoveryComplete() { Mock mockTestDiscoveryEventsHandler = new Mock(); - this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns(() => - { - var message = new Message - { - MessageType = MessageType.DiscoveryComplete - }; + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.DiscoveryComplete, It.IsAny())).Returns(MessageType.DiscoveryComplete); - return message; - }); + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => + { + var messageType = rawMessage.Contains(MessageType.DiscoveryComplete) ? MessageType.DiscoveryComplete : MessageType.TestMessage; + var message = new Message + { + MessageType = messageType + }; + + return message; + }); // Act. this.testDiscoveryManager.DiscoverTests(this.discoveryCriteria, mockTestDiscoveryEventsHandler.Object); @@ -420,4 +494,4 @@ public void DiscoveryManagerShouldPassOnHandleLogMessage() // .Returns(returnPayload); //} } -} +} \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 694f81dfb0..8b95f69217 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -279,6 +279,73 @@ public void StartTestRunShouldCatchExceptionAndCallHandleTestRunComplete() mockTestRunEventsHandler.Verify(s => s.HandleTestRunComplete(It.Is(t => t.IsAborted == true), null, null, null)); } + [TestMethod] + public void StartTestRunShouldCatchExceptionAndCallHandleRawMessageOfTestRunComplete() + { + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny())).Returns(false); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.ExecutionComplete, It.IsAny())).Returns(MessageType.ExecutionComplete); + + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => + { + var messageType = rawMessage.Contains(MessageType.ExecutionComplete) ? MessageType.ExecutionComplete : MessageType.TestMessage; + var message = new Message + { + MessageType = messageType + }; + + return message; + }); + + Mock mockTestRunEventsHandler = new Mock(); + + this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, mockTestRunEventsHandler.Object); + + mockTestRunEventsHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.ExecutionComplete))), Times.Once); + } + + [TestMethod] + public void StartTestRunShouldCatchExceptionAndCallHandleRawMessageOfTestMessage() + { + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny())).Returns(false); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.ExecutionComplete, It.IsAny())).Returns(MessageType.ExecutionComplete); + + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => + { + var messageType = rawMessage.Contains(MessageType.ExecutionComplete) ? MessageType.ExecutionComplete : MessageType.TestMessage; + var message = new Message + { + MessageType = messageType + }; + + return message; + }); + + Mock mockTestRunEventsHandler = new Mock(); + + this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, mockTestRunEventsHandler.Object); + + mockTestRunEventsHandler.Verify(s => s.HandleRawMessage(It.Is(str => str.Contains(MessageType.TestMessage)))); + } + + [TestMethod] + public void StartTestRunShouldCatchExceptionAndCallHandleLogMessageOfError() + { + this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny())).Returns(false); + this.mockTestHostManager.Setup(tmh => tmh.LaunchTestHostAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false)); + + Mock mockTestRunEventsHandler = new Mock(); + + this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, mockTestRunEventsHandler.Object); + + mockTestRunEventsHandler.Verify(s => s.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); + } + [TestMethod] public void StartTestRunShouldCatchExceptionAndCallHandleRawMessageAndHandleLogMessage() { @@ -301,9 +368,9 @@ public void StartTestRunShouldInitiateTestRunForSourcesThroughTheServer() this.mockRequestSender.Setup(s => s.StartTestRun(It.IsAny(), this.testExecutionManager)) .Callback( (TestRunCriteriaWithSources criteria, ITestRunEventsHandler sink) => - { - testRunCriteriaPassed = criteria; - }); + { + testRunCriteriaPassed = criteria; + }); this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, null); @@ -399,11 +466,15 @@ public void ExecuteTestsCloseTestHostIfRawMessageIfOfTypeExecutionComplete() this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny())).Returns(false); - this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns(() => + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.TestMessage, It.IsAny())).Returns(MessageType.TestMessage); + this.mockDataSerializer.Setup(ds => ds.SerializePayload(MessageType.ExecutionComplete, It.IsAny())).Returns(MessageType.ExecutionComplete); + + this.mockDataSerializer.Setup(mds => mds.DeserializeMessage(It.IsAny())).Returns((string rawMessage) => { + var messageType = rawMessage.Contains(MessageType.ExecutionComplete) ? MessageType.ExecutionComplete : MessageType.TestMessage; var message = new Message { - MessageType = MessageType.ExecutionComplete + MessageType = messageType }; return message; @@ -598,4 +669,4 @@ private void SignalEvent(ManualResetEvent manualResetEvent) // this.mockDataSerializer.Setup(ds => ds.DeserializePayload(It.Is(m => m.MessageType.Equals(messageType)))).Returns(returnPayload); //} } -} +} \ No newline at end of file From 92a00c401346c4916f7178a193178eeae23ac563 Mon Sep 17 00:00:00 2001 From: abhishkk Date: Mon, 26 Feb 2018 16:29:44 +0530 Subject: [PATCH 2/3] spacing --- .../Client/Parallel/ParallelProxyDiscoveryManager.cs | 2 +- .../Client/Parallel/ParallelProxyExecutionManager.cs | 2 +- .../Client/ProxyDiscoveryManager.cs | 2 +- .../Client/ProxyExecutionManager.cs | 2 +- .../Client/Parallel/ParallelProxyDiscoveryManagerTests.cs | 2 +- .../Client/Parallel/ParallelProxyExecutionManagerTests.cs | 2 +- .../Client/ProxyDiscoveryManagerTests.cs | 2 +- .../Client/ProxyExecutionManagerTests.cs | 8 ++++---- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs index 30e7876731..e33b2a5c89 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs @@ -249,4 +249,4 @@ private void DiscoverTestsOnConcurrentManager(IProxyDiscoveryManager proxyDiscov } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs index 1828170e3b..0b6a814152 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs @@ -363,4 +363,4 @@ private void StartTestRunOnConcurrentManager(IProxyExecutionManager proxyExecuti } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index 741e8db236..3b45cfba29 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -185,4 +185,4 @@ private void InitializeExtensions(IEnumerable sources) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index dbbc4a7223..4e354117c8 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -268,4 +268,4 @@ private void InitializeExtensions(IEnumerable sources) } } } -} \ No newline at end of file +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs index 2e0272a58b..7731503470 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyDiscoveryManagerTests.cs @@ -250,4 +250,4 @@ private void AssertMissingAndDuplicateSources(List processedSources) } } } -} \ No newline at end of file +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs index 2980a629ce..0246084860 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/Parallel/ParallelProxyExecutionManagerTests.cs @@ -541,4 +541,4 @@ private void SetupMockManagers(List processedSources, bool isCanceled = } } } -} \ No newline at end of file +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs index ca32c06ebf..f71e2f7990 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs @@ -494,4 +494,4 @@ public void DiscoveryManagerShouldPassOnHandleLogMessage() // .Returns(returnPayload); //} } -} \ No newline at end of file +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 8b95f69217..ad6ae2ac06 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -368,9 +368,9 @@ public void StartTestRunShouldInitiateTestRunForSourcesThroughTheServer() this.mockRequestSender.Setup(s => s.StartTestRun(It.IsAny(), this.testExecutionManager)) .Callback( (TestRunCriteriaWithSources criteria, ITestRunEventsHandler sink) => - { - testRunCriteriaPassed = criteria; - }); + { + testRunCriteriaPassed = criteria; + }); this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, null); @@ -669,4 +669,4 @@ private void SignalEvent(ManualResetEvent manualResetEvent) // this.mockDataSerializer.Setup(ds => ds.DeserializePayload(It.Is(m => m.MessageType.Equals(messageType)))).Returns(returnPayload); //} } -} \ No newline at end of file +} From 7dc6f98f4a60d48adf6ce78ea32bffe99b60c251 Mon Sep 17 00:00:00 2001 From: Abhishek Kumawat Date: Mon, 26 Feb 2018 17:37:05 +0530 Subject: [PATCH 3/3] Update ProxyDiscoveryManager.cs --- .../Client/ProxyDiscoveryManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index 3b45cfba29..772fd417d7 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -130,6 +130,7 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve }; this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.DiscoveryComplete, discoveryCompletePayload)); var discoveryCompleteEventsArgs = new DiscoveryCompleteEventArgs(-1, true); + this.HandleDiscoveryComplete(discoveryCompleteEventsArgs, new List()); } }