From 1b56b78fe0c60a23d8684eac54edce0d424721ca Mon Sep 17 00:00:00 2001 From: Jakub Chocholowicz Date: Mon, 22 Jun 2020 12:19:58 +0200 Subject: [PATCH] Progress feature, compiling + unit tests --- .../MultiTestRunFinalizationEventsHandler.cs | 37 +++++++--- .../Messages/MessageType.cs | 5 ++ ...MultiTestRunFinalizationCompletePayload.cs | 8 ++- ...MultiTestRunFinalizationProgressPayload.cs | 18 +++++ .../MultiTestRunFinalizationManager.cs | 56 ++++++---------- ...ltiTestRunFinalizationCompleteEventArgs.cs | 50 ++++++++++++++ ...ltiTestRunFinalizationProgressEventArgs.cs | 51 ++++++++++++++ .../IMultiTestRunFinalizationEventsHandler.cs | 17 ++++- .../VsTestConsoleRequestSender.cs | 9 ++- .../MultiTestRunFinalizationEventHandler.cs | 23 +++++++ ...tiTestRunFinalizationEventsHandlerTests.cs | 15 ++++- .../MultiTestRunFinalizationManagerTests.cs | 54 ++++++++++----- .../VsTestConsoleRequestSenderTests.cs | 67 ++++++++++++++++--- 13 files changed, 331 insertions(+), 79 deletions(-) create mode 100644 src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationProgressPayload.cs create mode 100644 src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationCompleteEventArgs.cs create mode 100644 src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationProgressEventArgs.cs diff --git a/src/Microsoft.TestPlatform.Client/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandler.cs b/src/Microsoft.TestPlatform.Client/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandler.cs index cc9c7cbcab..b31d7463a9 100644 --- a/src/Microsoft.TestPlatform.Client/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandler.cs +++ b/src/Microsoft.TestPlatform.Client/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandler.cs @@ -27,14 +27,7 @@ public MultiTestRunFinalizationEventsHandler(ICommunicationManager communication } /// - public void HandleLogMessage(TestMessageLevel level, string message) - { - var testMessagePayload = new TestMessagePayload { MessageLevel = level, Message = message }; - this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload); - } - - /// - public void HandleMultiTestRunFinalizationComplete(ICollection attachments) + public void HandleMultiTestRunFinalizationComplete(MultiTestRunFinalizationCompleteEventArgs finalizationCompleteEventArgs, IEnumerable lastChunk) { if (EqtTrace.IsInfoEnabled) { @@ -43,13 +36,37 @@ public void HandleMultiTestRunFinalizationComplete(ICollection at var payload = new MultiTestRunFinalizationCompletePayload() { - Attachments = attachments + FinalizationCompleteEventArgs = finalizationCompleteEventArgs, + Attachments = lastChunk }; - // Send run complete to translation layer this.communicationManager.SendMessage(MessageType.MultiTestRunFinalizationComplete, payload); } + /// + public void HandleMultiTestRunFinalizationProgress(MultiTestRunFinalizationProgressEventArgs finalizationProgressEventArgs) + { + var payload = new MultiTestRunFinalizationProgressPayload() + { + FinalizationProgressEventArgs = finalizationProgressEventArgs, + }; + + this.communicationManager.SendMessage(MessageType.MultiTestRunFinalizationProgress, payload); + } + + /// + public void HandleFinalisedAttachments(IEnumerable attachments) + { + throw new System.NotImplementedException(); + } + + /// + public void HandleLogMessage(TestMessageLevel level, string message) + { + var testMessagePayload = new TestMessagePayload { MessageLevel = level, Message = message }; + this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload); + } + /// public void HandleRawMessage(string rawMessage) { diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs index bb23393f03..802c8e5c87 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs @@ -133,6 +133,11 @@ public static class MessageType /// public const string MultiTestRunFinalizationComplete = "MultiTestRunFinalization.Complete"; + /// + /// Multi test run finalization progress + /// + public const string MultiTestRunFinalizationProgress = "MultiTestRunFinalization.Progress"; + /// /// Cancel multi test run finalization /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationCompletePayload.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationCompletePayload.cs index d20d55e61a..4d9ef24169 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationCompletePayload.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationCompletePayload.cs @@ -6,15 +6,21 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel using System.Collections.Generic; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; /// /// Multi test run finalization complete payload. /// public class MultiTestRunFinalizationCompletePayload { + /// + /// Gets or sets the multi test run finalization complete args. + /// + public MultiTestRunFinalizationCompleteEventArgs FinalizationCompleteEventArgs { get; set; } + /// /// Gets or sets the attachments. /// - public ICollection Attachments { get; set; } + public IEnumerable Attachments { get; set; } } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationProgressPayload.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationProgressPayload.cs new file mode 100644 index 0000000000..6190ada03c --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MultiTestRunFinalizationProgressPayload.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + + /// + /// Multi test run finalization complete payload. + /// + public class MultiTestRunFinalizationProgressPayload + { + /// + /// Gets or sets the multi test run finalization complete args. + /// + public MultiTestRunFinalizationProgressEventArgs FinalizationProgressEventArgs { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/MultiTestRunFinalization/MultiTestRunFinalizationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/MultiTestRunFinalization/MultiTestRunFinalizationManager.cs index 2e0a197bd5..5e7d14b69d 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/MultiTestRunFinalization/MultiTestRunFinalizationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/MultiTestRunFinalization/MultiTestRunFinalizationManager.cs @@ -65,19 +65,19 @@ private async Task> InternalFinalizeMultiTestRunAsync( { Task> task = Task.Run(() => { - return ProcessAttachments(new Collection(attachments.ToList()), new ProgressReporter(eventHandler, dataCollectorAttachmentsHandlers.Length), cancellationToken); + return ProcessAttachments(new Collection(attachments.ToList()), eventHandler, cancellationToken); }); var completedTask = await Task.WhenAny(task, taskCompletionSource.Task).ConfigureAwait(false); if (completedTask == task) { - return FinalizeOperation(requestData, await task, eventHandler, FinalizationCompleted); + return FinalizeOperation(requestData, new MultiTestRunFinalizationCompleteEventArgs(false, false, null), await task, eventHandler); } else { eventHandler?.HandleLogMessage(ObjectModel.Logging.TestMessageLevel.Informational, "Finalization was cancelled."); - return FinalizeOperation(requestData, attachments, eventHandler, FinalizationCanceled); + return FinalizeOperation(requestData, new MultiTestRunFinalizationCompleteEventArgs(true, false, null), attachments, eventHandler); } } } @@ -87,14 +87,14 @@ private async Task> InternalFinalizeMultiTestRunAsync( { EqtTrace.Warning("MultiTestRunFinalizationManager: operation was cancelled."); } - return FinalizeOperation(requestData, attachments, eventHandler, FinalizationCanceled); + return FinalizeOperation(requestData, new MultiTestRunFinalizationCompleteEventArgs(true, false, null), attachments, eventHandler); } catch (Exception e) { EqtTrace.Error("MultiTestRunFinalizationManager: Exception in FinalizeMultiTestRunAsync: " + e); eventHandler?.HandleLogMessage(ObjectModel.Logging.TestMessageLevel.Error, e.Message); - return FinalizeOperation(requestData, attachments, eventHandler, FinalizationFailed); + return FinalizeOperation(requestData, new MultiTestRunFinalizationCompleteEventArgs(false, true, e), attachments, eventHandler); } finally { @@ -103,12 +103,15 @@ private async Task> InternalFinalizeMultiTestRunAsync( } } - private Collection ProcessAttachments(Collection attachments, ProgressReporter progressReporter, CancellationToken cancellationToken) + private Collection ProcessAttachments(Collection attachments, IMultiTestRunFinalizationEventsHandler eventsHandler, CancellationToken cancellationToken) { - if (attachments == null || !attachments.Any()) return attachments; + if (attachments == null || !attachments.Any()) return attachments; - foreach (var dataCollectorAttachmentsHandler in dataCollectorAttachmentsHandlers) + for (int i = 0; i < dataCollectorAttachmentsHandlers.Length; i++) { + IDataCollectorAttachments dataCollectorAttachmentsHandler = dataCollectorAttachmentsHandlers[i]; + string attachmentsHandlerName = dataCollectorAttachmentsHandler.GetType().FullName; + Uri attachementUri = dataCollectorAttachmentsHandler.GetExtensionUri(); if (attachementUri != null) { @@ -120,6 +123,9 @@ private Collection ProcessAttachments(Collection a attachments.Remove(attachment); } + IProgress progressReporter = new Progress((int progress) => + eventsHandler?.HandleMultiTestRunFinalizationProgress( + new MultiTestRunFinalizationProgressEventArgs(i + 1, attachmentsHandlerName, progress, dataCollectorAttachmentsHandlers.Length))); ICollection processedAttachments = dataCollectorAttachmentsHandler.HandleDataCollectionAttachmentSets(new Collection(attachmentsToBeProcessed), progressReporter, cancellationToken); foreach (var attachment in processedAttachments) { @@ -132,38 +138,16 @@ private Collection ProcessAttachments(Collection a return attachments; } - private Collection FinalizeOperation(IRequestData requestData, Collection attachments, IMultiTestRunFinalizationEventsHandler eventHandler, string finalizationState) - { - eventHandler?.HandleMultiTestRunFinalizationComplete(attachments); + private Collection FinalizeOperation(IRequestData requestData, MultiTestRunFinalizationCompleteEventArgs completeArgs, Collection attachments, IMultiTestRunFinalizationEventsHandler eventHandler) + { testPlatformEventSource.MultiTestRunFinalizationStop(attachments.Count); requestData.MetricsCollection.Add(TelemetryDataConstants.NumberOfAttachmentsAfterFinalization, attachments.Count); - requestData.MetricsCollection.Add(TelemetryDataConstants.FinalizationState, finalizationState); - - return attachments; - } + requestData.MetricsCollection.Add(TelemetryDataConstants.FinalizationState, completeArgs.IsAborted ? FinalizationFailed : completeArgs.IsCanceled ? FinalizationCanceled : FinalizationCompleted); - private class ProgressReporter : IProgress - { - private readonly IMultiTestRunFinalizationEventsHandler eventsHandler; - private readonly int totalNumberOfHandlers; - private int currentHandlerIndex; + completeArgs.Metrics = requestData.MetricsCollection.Metrics; + eventHandler?.HandleMultiTestRunFinalizationComplete(completeArgs, attachments); - public ProgressReporter(IMultiTestRunFinalizationEventsHandler eventsHandler, int totalNumberOfHandlers) - { - this.eventsHandler = eventsHandler; - this.currentHandlerIndex = 0; - this.totalNumberOfHandlers = totalNumberOfHandlers; - } - - public void IncremenetHandlerIndex() - { - currentHandlerIndex++; - } - - public void Report(int value) - { - //eventsHandler.report( current, total, value) - } + return attachments; } } } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationCompleteEventArgs.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationCompleteEventArgs.cs new file mode 100644 index 0000000000..db61554c9d --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationCompleteEventArgs.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Client +{ + using System; + using System.Collections.Generic; + using System.Runtime.Serialization; + + [DataContract] + public class MultiTestRunFinalizationCompleteEventArgs : EventArgs + { + /// + /// Default constructor. + /// + /// Specifies whether the finalization is canceled. + /// Specifies whether the finalization is aborted. + /// Specifies the error encountered during the execution of the finalization. + public MultiTestRunFinalizationCompleteEventArgs(bool isCanceled, bool isAborted, Exception error) + { + this.IsCanceled = isCanceled; + this.IsAborted = isAborted; + this.Error = error; + } + + /// + /// Gets a value indicating whether the finalization is aborted or not. + /// + [DataMember] + public bool IsAborted { get; private set; } + + /// + /// Gets a value indicating whether the finalization is canceled or not. + /// + [DataMember] + public bool IsCanceled { get; private set; } + + /// + /// Gets the error encountered during the finalization of the test runs. Null if there is no error. + /// + [DataMember] + public Exception Error { get; private set; } + + /// + /// Get or Sets the Metrics + /// + [DataMember] + public IDictionary Metrics { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationProgressEventArgs.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationProgressEventArgs.cs new file mode 100644 index 0000000000..760987ec4a --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Events/MultiTestRunFinalizationProgressEventArgs.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Client +{ + using System; + using System.Runtime.Serialization; + + [DataContract] + public class MultiTestRunFinalizationProgressEventArgs : EventArgs + { + /// + /// Default constructor. + /// + /// Specifies current handler index. + /// Specifies current handler name. + /// Specifies current handler progress. + /// Specifies the overall number of handlers. + public MultiTestRunFinalizationProgressEventArgs(long currentHandlerIndex, string currentHandlerName, long currentHandlerProgress, long handlersCount) + { + CurrentHandlerIndex = currentHandlerIndex; + CurrentHandlerName = currentHandlerName; + CurrentHandlerProgress = currentHandlerProgress; + HandlersCount = handlersCount; + } + + /// + /// Gets a current handler index. + /// + [DataMember] + public long CurrentHandlerIndex { get; private set; } + + /// + /// Gets a current handler name. + /// + [DataMember] + public string CurrentHandlerName { get; private set; } + + /// + /// Gets a current handler progress. + /// + [DataMember] + public long CurrentHandlerProgress { get; private set; } + + /// + /// Gets the overall number of handlers. + /// + [DataMember] + public long HandlersCount { get; private set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IMultiTestRunFinalizationEventsHandler.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IMultiTestRunFinalizationEventsHandler.cs index 93484152da..8c00b00c60 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IMultiTestRunFinalizationEventsHandler.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IMultiTestRunFinalizationEventsHandler.cs @@ -13,7 +13,20 @@ public interface IMultiTestRunFinalizationEventsHandler : ITestMessageEventHandl /// /// Dispatch MultiTestRunFinalizationComplete event to listeners. /// - /// Attachments reprocessed. - void HandleMultiTestRunFinalizationComplete(ICollection attachments); + /// Finalization Complete event args. + /// Last set of processed attachment sets. + void HandleMultiTestRunFinalizationComplete(MultiTestRunFinalizationCompleteEventArgs finalizationCompleteEventArgs, IEnumerable lastChunk); + + /// + /// Dispatch FinalisedAttachments event to listeners. + /// + /// Finalised attachment sets. + void HandleFinalisedAttachments(IEnumerable attachments); + + /// + /// Dispatch MultiTestRunFinalizationProgress event to listeners. + /// + /// Finalization Progress event args. + void HandleMultiTestRunFinalizationProgress(MultiTestRunFinalizationProgressEventArgs finalizationProgressEventArgs); } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs index 6d0e187be5..783c254c95 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs @@ -762,9 +762,14 @@ private async Task SendMessageAndListenAndReportFinalizationResultAsync(IEnumera var multiTestRunFinalizationCompletePayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleMultiTestRunFinalizationComplete(multiTestRunFinalizationCompletePayload.Attachments); + eventHandler.HandleMultiTestRunFinalizationComplete(multiTestRunFinalizationCompletePayload.FinalizationCompleteEventArgs, multiTestRunFinalizationCompletePayload.Attachments); isMultiTestRunFinalizationComplete = true; } + else if (string.Equals(MessageType.MultiTestRunFinalizationProgress, message.MessageType)) + { + var multiTestRunFinalizationProgressPayload = this.dataSerializer.DeserializePayload(message); + eventHandler.HandleMultiTestRunFinalizationProgress(multiTestRunFinalizationProgressPayload.FinalizationProgressEventArgs); + } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { var testMessagePayload = this.dataSerializer.DeserializePayload(message); @@ -777,7 +782,7 @@ private async Task SendMessageAndListenAndReportFinalizationResultAsync(IEnumera { EqtTrace.Error("Aborting Test Session End Operation: {0}", exception); eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedMultiTestRunFinalization); - eventHandler.HandleMultiTestRunFinalizationComplete(null); + eventHandler.HandleMultiTestRunFinalizationComplete(new MultiTestRunFinalizationCompleteEventArgs(false, true, exception), null); // Earlier we were closing the connection with vstest.console in case of exceptions // Removing that code because vstest.console might be in a healthy state and letting the client diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/EventHandler/MultiTestRunFinalizationEventHandler.cs b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/EventHandler/MultiTestRunFinalizationEventHandler.cs index 0a1b77a832..baa457c62a 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/EventHandler/MultiTestRunFinalizationEventHandler.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/EventHandler/MultiTestRunFinalizationEventHandler.cs @@ -82,5 +82,28 @@ public void HandleMultiTestRunFinalizationComplete(ICollection at this.Attachments.AddRange(attachments); } } + + public void HandleMultiTestRunFinalizationComplete(MultiTestRunFinalizationCompleteEventArgs finalizationCompleteEventArgs, IEnumerable lastChunk) + { + if (lastChunk != null) + { + this.Attachments.AddRange(lastChunk); + } + + if (finalizationCompleteEventArgs.Error != null) + { + Errors.Add(finalizationCompleteEventArgs.Error.Message); + } + } + + public void HandleFinalisedAttachments(IEnumerable attachments) + { + throw new NotImplementedException(); + } + + public void HandleMultiTestRunFinalizationProgress(MultiTestRunFinalizationProgressEventArgs finalizationProgressEventArgs) + { + throw new NotImplementedException(); + } } } diff --git a/test/Microsoft.TestPlatform.Client.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandlerTests.cs b/test/Microsoft.TestPlatform.Client.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandlerTests.cs index 26d50e6edc..be9a766e63 100644 --- a/test/Microsoft.TestPlatform.Client.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandlerTests.cs +++ b/test/Microsoft.TestPlatform.Client.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationEventsHandlerTests.cs @@ -38,10 +38,21 @@ public void EventsHandlerHandleLogMessageShouldSendTestMessage() public void EventsHandlerHandleMultiTestRunFinalizationCompleteShouldSendFinalizationCompleteMessage() { var attachments = new[] { new AttachmentSet(new System.Uri("http://www.bing.com/"), "code coverage") }; + var args = new MultiTestRunFinalizationCompleteEventArgs(false, false, null); - handler.HandleMultiTestRunFinalizationComplete(attachments); + handler.HandleMultiTestRunFinalizationComplete(args, attachments); - mockCommunicationManager.Verify(cm => cm.SendMessage(MessageType.MultiTestRunFinalizationComplete, It.Is(p => p.Attachments == attachments))); + mockCommunicationManager.Verify(cm => cm.SendMessage(MessageType.MultiTestRunFinalizationComplete, It.Is(p => p.Attachments == attachments && p.FinalizationCompleteEventArgs == args))); + } + + [TestMethod] + public void EventsHandlerHandleMultiTestRunFinalizationProgressShouldSendFinalizationProgressMessage() + { + var args = new MultiTestRunFinalizationProgressEventArgs(1, "CC", 90, 2); + + handler.HandleMultiTestRunFinalizationProgress(args); + + mockCommunicationManager.Verify(cm => cm.SendMessage(MessageType.MultiTestRunFinalizationProgress, It.Is(p => p.FinalizationProgressEventArgs == args))); } [TestMethod] diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationManagerTests.cs index ba4f983854..e5b8d4d44a 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/MultiTestRunFinalization/MultiTestRunFinalizationManagerTests.cs @@ -63,8 +63,10 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnInitialAttachmentsThroug await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>(c => c.Count == 0))); + VerifyCompleteEvent(false, false, false); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is(a => !a.IsAborted && !a.IsCanceled), It.Is>(c => c.Count == 0))); mockEventsHandler.Verify(h => h.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockEventSource.Verify(s => s.MultiTestRunFinalizationStart(0)); mockEventSource.Verify(s => s.MultiTestRunFinalizationStop(0)); mockAttachmentHandler1.Verify(h => h.GetExtensionUri(), Times.Never); @@ -107,7 +109,8 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturn1NotProcessedAttachmentT await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>(c => c.Count == 1 && c.Contains(inputAttachments[0])))); + VerifyCompleteEvent(false, false, false, inputAttachments[0]); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockEventsHandler.Verify(h => h.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never); mockAttachmentHandler1.Verify(h => h.GetExtensionUri()); mockAttachmentHandler2.Verify(h => h.GetExtensionUri()); @@ -160,7 +163,8 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturn1ProcessedAttachmentThro await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>(c => c.Count == 1 && c.Contains(outputAttachments[0])))); + VerifyCompleteEvent(false, false, false, outputAttachments[0]); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockEventsHandler.Verify(h => h.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never); mockAttachmentHandler1.Verify(h => h.GetExtensionUri()); mockAttachmentHandler2.Verify(h => h.GetExtensionUri()); @@ -217,9 +221,8 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnInitialAttachmentsThroug await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>( - c => c.Count == 1 && - c.Contains(inputAttachments[0])))); + VerifyCompleteEvent(true, false, true, inputAttachments[0]); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockEventsHandler.Verify(h => h.HandleLogMessage(TestMessageLevel.Error, "exception message"), Times.Once); mockAttachmentHandler1.Verify(h => h.GetExtensionUri()); mockAttachmentHandler2.Verify(h => h.GetExtensionUri(), Times.Never); @@ -268,9 +271,8 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnInitialAttachmentsThroug await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>( - c => c.Count == 1 && - c.Contains(inputAttachments[0])))); + VerifyCompleteEvent(false, true, false, inputAttachments[0]); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockAttachmentHandler1.Verify(h => h.GetExtensionUri(), Times.Never); mockAttachmentHandler2.Verify(h => h.GetExtensionUri(), Times.Never); mockAttachmentHandler1.Verify(h => h.HandleDataCollectionAttachmentSets(It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never); @@ -333,11 +335,8 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnProcessedAttachmentsThro await manager.FinalizeMultiTestRunAsync(mockRequestData.Object, inputAttachments, mockEventsHandler.Object, cancellationTokenSource.Token); // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>( - c => c.Count == 3 && - c.Contains(inputAttachments[4]) && - c.Contains(outputAttachmentsForHandler1.First()) && - c.Contains(outputAttachmentsForHandler2.First())))); + VerifyCompleteEvent(false, false, false, inputAttachments[4], outputAttachmentsForHandler1.First(), outputAttachmentsForHandler2.First()); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Never); mockEventsHandler.Verify(h => h.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never); mockAttachmentHandler1.Verify(h => h.GetExtensionUri()); mockAttachmentHandler2.Verify(h => h.GetExtensionUri()); @@ -409,12 +408,13 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnInitialAttachmentsThroug { try { - for (int i = 0; i < 1000; ++i) + for (int i = 0; i < 100; ++i) { Task.Delay(100).Wait(); Console.WriteLine($"Iteration: {i}"); cancellation.ThrowIfCancellationRequested(); + progress.Report(i + 1); if (i == 3) { @@ -437,9 +437,12 @@ public async Task FinalizeMultiTestRunAsync_ShouldReturnInitialAttachmentsThroug await innerTaskCompletionSource.Task; // assert - mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete(It.Is>( - c => c.Count == 1 && - c.Contains(inputAttachments[0])))); + VerifyCompleteEvent(false, true, false, inputAttachments[0]); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.IsAny()), Times.Exactly(4)); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.Is(a => VerifyProgressArgs(a, 1)))); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.Is(a => VerifyProgressArgs(a, 2)))); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.Is(a => VerifyProgressArgs(a, 3)))); + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationProgress(It.Is(a => VerifyProgressArgs(a, 4)))); mockEventsHandler.Verify(h => h.HandleLogMessage(TestMessageLevel.Informational, "Finalization was cancelled.")); mockAttachmentHandler1.Verify(h => h.GetExtensionUri()); mockAttachmentHandler2.Verify(h => h.GetExtensionUri(), Times.Never); @@ -518,5 +521,20 @@ private void VerifyMetrics(int inputCount, int outputCount, string status = "Com mockMetricsCollection.Verify(m => m.Add(TelemetryDataConstants.FinalizationState, status)); mockMetricsCollection.Verify(m => m.Add(TelemetryDataConstants.TimeTakenInSecForFinalization, It.IsAny())); } + + private void VerifyCompleteEvent(bool isAborted, bool isCanceled, bool containsError, params AttachmentSet[] expectedSets) + { + mockEventsHandler.Verify(h => h.HandleMultiTestRunFinalizationComplete( + It.Is(a => a.IsAborted == isAborted && a.IsCanceled == isCanceled && (a.Error != null) == containsError), + It.Is>(c => c.Count == expectedSets.Length && expectedSets.All(e => c.Contains(e))))); + } + + private bool VerifyProgressArgs(MultiTestRunFinalizationProgressEventArgs args, int progress) + { + Assert.AreEqual(1, args.CurrentHandlerIndex); + Assert.AreEqual(2, args.HandlersCount); + Assert.IsTrue(args.CurrentHandlerName.StartsWith("Castle.Proxies.ObjectProxy")); + return progress == args.CurrentHandlerProgress; + } } } diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs index c1f999f6d8..3658178a24 100644 --- a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs +++ b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs @@ -1902,7 +1902,12 @@ public async Task FinalizeTestsShouldCompleteWithZeroAttachments() var mockHandler = new Mock(); - var payload = new MultiTestRunFinalizationCompletePayload() { Attachments = new AttachmentSet[0] }; + var payload = new MultiTestRunFinalizationCompletePayload() + { + FinalizationCompleteEventArgs = new MultiTestRunFinalizationCompleteEventArgs(false, false, null), + Attachments = new AttachmentSet[0] + }; + var finalizationComplete = new Message() { MessageType = MessageType.MultiTestRunFinalizationComplete, @@ -1914,7 +1919,7 @@ public async Task FinalizeTestsShouldCompleteWithZeroAttachments() mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel), Times.Never); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is>(a => a.Count == 0)), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is(a => !a.IsAborted && !a.IsCanceled && a.Error == null), It.Is>(a => a.Count == 0)), Times.Once, "Finalization Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never, "TestMessage event must not be called"); } @@ -1926,7 +1931,8 @@ public async Task FinalizeTestsShouldCompleteWithOneAttachment() var mockHandler = new Mock(); var payload = new MultiTestRunFinalizationCompletePayload() - { + { + FinalizationCompleteEventArgs = new MultiTestRunFinalizationCompleteEventArgs(true, true, new Exception("msg")), Attachments = new List { new AttachmentSet(new Uri("http://www.bing.com"), "out") } }; var finalizationComplete = new Message() @@ -1940,7 +1946,7 @@ public async Task FinalizeTestsShouldCompleteWithOneAttachment() mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel), Times.Never); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is>(a => a.Count == 1)), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is(a => a.IsAborted && a.IsCanceled && a.Error != null), It.Is>(a => a.Count == 1)), Times.Once, "Finalization Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(It.IsAny(), It.IsAny()), Times.Never, "TestMessage event must not be called"); } @@ -1953,8 +1959,10 @@ public async Task FinalizeTestsShouldCompleteWithOneAttachmentAndTestMessage() var payload = new MultiTestRunFinalizationCompletePayload() { + FinalizationCompleteEventArgs = new MultiTestRunFinalizationCompleteEventArgs(false, false, null), Attachments = new List { new AttachmentSet(new Uri("http://www.bing.com"), "out") } }; + var finalizationComplete = new Message() { MessageType = MessageType.MultiTestRunFinalizationComplete, @@ -1972,10 +1980,53 @@ public async Task FinalizeTestsShouldCompleteWithOneAttachmentAndTestMessage() mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel), Times.Never); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is>(a => a.Count == 1)), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.IsAny(), It.Is>(a => a.Count == 1)), Times.Once, "Finalization Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Informational, "Hello"), Times.Once, "TestMessage event must be called"); } + [TestMethod] + public async Task FinalizeTestsShouldCompleteWithOneAttachmentAndProgressMessage() + { + await this.InitializeCommunicationAsync(); + + var mockHandler = new Mock(); + + var completePayload = new MultiTestRunFinalizationCompletePayload() + { + FinalizationCompleteEventArgs = new MultiTestRunFinalizationCompleteEventArgs(false, false, null), + Attachments = new List { new AttachmentSet(new Uri("http://www.bing.com"), "out") } + }; + + var finalizationComplete = new Message() + { + MessageType = MessageType.MultiTestRunFinalizationComplete, + Payload = JToken.FromObject(completePayload) + }; + + var progressPayload = new MultiTestRunFinalizationProgressPayload() + { + FinalizationProgressEventArgs = new MultiTestRunFinalizationProgressEventArgs(1, "cc", 50, 2) + }; + + var finalizationProgress = new Message() + { + MessageType = MessageType.MultiTestRunFinalizationProgress, + Payload = JToken.FromObject(progressPayload) + }; + this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(finalizationProgress)); + + mockHandler.Setup(mh => mh.HandleMultiTestRunFinalizationProgress(It.IsAny())).Callback( + () => this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(finalizationComplete))); + + await this.requestSender.FinalizeMultiTestRunAsync(new List { new AttachmentSet(new Uri("http://www.bing.com"), "a") }, false, mockHandler.Object, CancellationToken.None); + + mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); + mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel), Times.Never); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.IsAny(), It.Is>(a => a.Count == 1)), Times.Once, "Finalization Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationProgress(It.Is(a => a.CurrentHandlerIndex == 1 && a.CurrentHandlerName == "cc" && a.CurrentHandlerProgress == 50 && a.HandlersCount == 2)), Times.Once, "Finalization Progress must be called"); + mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Informational, "Hello"), Times.Never); + } + [TestMethod] public async Task FinalizeTestsShouldSendCancelMessageIfCancellationTokenCancelled() { @@ -2009,7 +2060,7 @@ public async Task FinalizeTestsShouldSendCancelMessageIfCancellationTokenCancell mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel)); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is>(a => a.Count == 1)), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.IsAny(), It.Is>(a => a.Count == 1)), Times.Once, "Finalization Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Informational, "Hello"), Times.Once, "TestMessage event must be called"); } @@ -2039,7 +2090,7 @@ public async Task FinalizeTestsShouldSendCancelMessageIfCancellationTokenCancell mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationStart, It.IsAny())); mockCommunicationManager.Verify(c => c.SendMessage(MessageType.MultiTestRunFinalizationCancel)); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is>(a => a.Count == 1)), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.IsAny(), It.Is>(a => a.Count == 1)), Times.Once, "Finalizationomplete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Informational, "Hello"), Times.Never, "TestMessage event must be called"); } @@ -2051,7 +2102,7 @@ public async Task FinalizeTestsShouldAbortOnExceptionInSendMessage() await this.requestSender.FinalizeMultiTestRunAsync(new List { new AttachmentSet(new Uri("http://www.bing.com"), "out") }, false, mockHandler.Object, CancellationToken.None); - mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(null), Times.Once, "Discovery Complete must be called"); + mockHandler.Verify(mh => mh.HandleMultiTestRunFinalizationComplete(It.Is(a => !a.IsCanceled && a.IsAborted && a.Error is IOException), null), Times.Once, "Finalization Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once, "TestMessage event must be called"); this.mockCommunicationManager.Verify(cm => cm.StopServer(), Times.Never); }