Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed CC for in-process console scenarios #4084

Merged
merged 5 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions src/vstest.console/InProcessVsTestConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ await ProcessTestRunAttachmentsAsync(
}

/// <inheritdoc/>
public Task ProcessTestRunAttachmentsAsync(
public async Task ProcessTestRunAttachmentsAsync(
IEnumerable<AttachmentSet> attachments,
IEnumerable<InvokedDataCollector>? invokedDataCollectors,
string? processingSettings,
Expand All @@ -839,7 +839,55 @@ public Task ProcessTestRunAttachmentsAsync(
ITestRunAttachmentsProcessingEventsHandler eventsHandler,
CancellationToken cancellationToken)
{
throw new NotImplementedException();
_testPlatformEventSource.TranslationLayerTestRunAttachmentsProcessingStart();

try
{
var attachmentProcessingPayload = new TestRunAttachmentsProcessingPayload
{
Attachments = attachments,
InvokedDataCollectors = invokedDataCollectors,
RunSettings = processingSettings,
CollectMetrics = collectMetrics
};

using (cancellationToken.Register(() =>
TestRequestManager?.CancelTestRunAttachmentsProcessing()))
{
// Awaiting the attachment processing task here. The implementation of the
// underlying operation guarantees the event handler is called when processing
// is complete, so when awaiting ends, the results have already been passed to
// the caller via the event handler. No need for further synchronization.
//
// NOTE: We're passing in CancellationToken.None and that is by design, *DO NOT*
// attempt to optimize this code by passing in the cancellation token registered
// above. Passing in the said token would result in potentially leaving the caller
// hanging when the token is signaled before even starting the test run attachment
// processing. In this scenario, the Task.Run should not even run in the first
// place, and as such the event handler that signals processing is complete will
// not be triggered anymore.
await Task.Run(() =>
TestRequestManager?.ProcessTestRunAttachments(
attachmentProcessingPayload,
eventsHandler,
new ProtocolConfig { Version = _highestSupportedVersion }),
CancellationToken.None)
Evangelink marked this conversation as resolved.
Show resolved Hide resolved
.ConfigureAwait(false);
}
}
catch (Exception ex)
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
{
EqtTrace.Error("InProcessVsTestConsoleWrapper.ProcessTestRunAttachmentsAsync: Exception occurred: " + ex);

var attachmentsProcessingArgs = new TestRunAttachmentsProcessingCompleteEventArgs(
isCanceled: cancellationToken.IsCancellationRequested,
ex);

eventsHandler.HandleLogMessage(TestMessageLevel.Error, ex.ToString());
eventsHandler.HandleTestRunAttachmentsProcessingComplete(attachmentsProcessingArgs, lastChunk: null);
}

_testPlatformEventSource.TranslationLayerTestRunAttachmentsProcessingStop();
}

/// <inheritdoc/>
Expand Down
192 changes: 191 additions & 1 deletion test/vstest.console.UnitTests/InProcessVsTestConsoleWrapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.TestPlatform.VsTestConsole.TranslationLayer;
using Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces;
Expand All @@ -15,13 +17,14 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using FluentAssertions;
using Moq;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;

namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests;

Expand All @@ -38,6 +41,17 @@ public class InProcessVsTestConsoleWrapperTests

private readonly IList<string> _testSources = new List<String>() { "test1", "test2" };
private readonly IList<TestCase> _testCases = new List<TestCase>() { new TestCase(), new TestCase() };
private readonly IList<AttachmentSet> _attachmentSets = new List<AttachmentSet>()
{
new AttachmentSet(new Uri("datacollector://AttachmentSetDataCollector1"), "AttachmentSet1"),
new AttachmentSet(new Uri("datacollector://AttachmentSetDataCollector2"), "AttachmentSet2"),
};
private readonly IList<InvokedDataCollector> _invokedDataCollectors = new List<InvokedDataCollector>()
{
new InvokedDataCollector(new Uri("datacollector://InvokedDataCollector1"), "InvokedDataCollector1", "DummyAssemblyName1", "DummyFilePath1", true),
new InvokedDataCollector(new Uri("datacollector://InvokedDataCollector2"), "InvokedDataCollector2", "DummyAssemblyName2", "DummyFilePath2", false),
};

private readonly string _runSettings = "dummy runsettings";

public InProcessVsTestConsoleWrapperTests()
Expand Down Expand Up @@ -849,4 +863,180 @@ public void InProcessWrapperStartTestSessionSucceedsWhenNoExceptionIsThrown()
mockTestSessionEventsHandler.Verify(eh => eh.HandleStartTestSessionComplete(startTestSessionCompleteArgs), Times.Once);
mockTestSessionEventsHandler.Verify(eh => eh.HandleStopTestSessionComplete(stopTestSessionCompleteArgs), Times.Once);
}

[TestMethod]
public async Task InProcessWrapperProcessTestRunAttachmentsAsyncWithSevenParamsIsSuccessfullyInvoked()
{
var attachmentsEventHandler = new Mock<ITestRunAttachmentsProcessingEventsHandler>();

TestRunAttachmentsProcessingPayload? payload = null;
_mockTestRequestManager
.Setup(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()))
.Callback((
TestRunAttachmentsProcessingPayload p,
ITestRunAttachmentsProcessingEventsHandler _,
ProtocolConfig _) => payload = p);

await _consoleWrapper.ProcessTestRunAttachmentsAsync(
_attachmentSets,
_invokedDataCollectors,
_runSettings,
true,
false,
attachmentsEventHandler.Object,
CancellationToken.None).ConfigureAwait(false);

Assert.IsNotNull(payload);
Assert.IsTrue(_attachmentSets.SequenceEqual(payload.Attachments!));
Assert.IsTrue(_invokedDataCollectors.SequenceEqual(payload.InvokedDataCollectors!));
Assert.AreEqual(_runSettings, payload.RunSettings);
Assert.IsFalse(payload.CollectMetrics);

_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStart(), Times.Once);
_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStop(), Times.Once);
_mockTestRequestManager.Verify(trm => trm.ResetOptions(), Times.Never);
_mockTestRequestManager.Verify(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()), Times.Once);
}

[TestMethod]
public async Task InProcessWrapperProcessTestRunAttachmentsAsyncWithSevenParamsSuccessfullyHandlesCancellation()
{
var attachmentsEventHandler = new Mock<ITestRunAttachmentsProcessingEventsHandler>();

TestRunAttachmentsProcessingPayload? payload = null;
_mockTestRequestManager
.Setup(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()))
.Callback((
TestRunAttachmentsProcessingPayload p,
ITestRunAttachmentsProcessingEventsHandler _,
ProtocolConfig _) => payload = p);
_mockTestRequestManager.Setup(trm => trm.CancelTestRunAttachmentsProcessing())
.Callback(() => { });

var cancellationTokenSource = new CancellationTokenSource();

cancellationTokenSource.Cancel();
await _consoleWrapper.ProcessTestRunAttachmentsAsync(
_attachmentSets,
_invokedDataCollectors,
_runSettings,
true,
false,
attachmentsEventHandler.Object,
cancellationTokenSource.Token).ConfigureAwait(false);

Assert.IsNotNull(payload);
Assert.IsTrue(_attachmentSets.SequenceEqual(payload.Attachments!));
Assert.IsTrue(_invokedDataCollectors.SequenceEqual(payload.InvokedDataCollectors!));
Assert.AreEqual(_runSettings, payload.RunSettings);
Assert.IsFalse(payload.CollectMetrics);

_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStart(), Times.Once);
_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStop(), Times.Once);
_mockTestRequestManager.Verify(trm => trm.ResetOptions(), Times.Never);
_mockTestRequestManager.Verify(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()), Times.Once);
_mockTestRequestManager.Verify(trm => trm.CancelTestRunAttachmentsProcessing(), Times.Once);
}

[TestMethod]
public async Task InProcessWrapperProcessTestRunAttachmentsAsyncWithSevenParamsSuccessfullyHandlesExceptions()
{
var attachmentsEventHandler = new Mock<ITestRunAttachmentsProcessingEventsHandler>();

_mockTestRequestManager
.Setup(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()))
.Throws(new Exception("Dummy exception"));

await _consoleWrapper.ProcessTestRunAttachmentsAsync(
_attachmentSets,
_invokedDataCollectors,
_runSettings,
true,
false,
attachmentsEventHandler.Object,
CancellationToken.None).ConfigureAwait(false);

_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStart(), Times.Once);
_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStop(), Times.Once);
_mockTestRequestManager.Verify(trm => trm.ResetOptions(), Times.Never);
_mockTestRequestManager.Verify(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()), Times.Once);
attachmentsEventHandler.Verify(eh => eh.HandleLogMessage(TestMessageLevel.Error, It.IsAny<string>()));
}

[TestMethod]
public async Task InProcessWrapperProcessTestRunAttachmentsAsyncWithSevenParamsSuccessfullyHandlesNullTestRequestManager()
{
var attachmentsEventHandler = new Mock<ITestRunAttachmentsProcessingEventsHandler>();

_consoleWrapper.TestRequestManager = null;

await _consoleWrapper.ProcessTestRunAttachmentsAsync(
_attachmentSets,
_invokedDataCollectors,
_runSettings,
true,
false,
attachmentsEventHandler.Object,
CancellationToken.None).ConfigureAwait(false);

_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStart(), Times.Once);
_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStop(), Times.Once);
}

[TestMethod]
public async Task InProcessWrapperProcessTestRunAttachmentsAsyncWithSixParamsIsSuccessfullyInvoked()
{
var attachmentsEventHandler = new Mock<ITestRunAttachmentsProcessingEventsHandler>();

TestRunAttachmentsProcessingPayload? payload = null;
_mockTestRequestManager
.Setup(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()))
.Callback((
TestRunAttachmentsProcessingPayload p,
ITestRunAttachmentsProcessingEventsHandler _,
ProtocolConfig _) => payload = p);

await _consoleWrapper.ProcessTestRunAttachmentsAsync(
_attachmentSets,
_runSettings,
true,
false,
attachmentsEventHandler.Object,
CancellationToken.None);

Assert.IsNotNull(payload);
Assert.IsTrue(_attachmentSets.SequenceEqual(payload.Attachments!));
Assert.IsNull(payload.InvokedDataCollectors);
Assert.AreEqual(_runSettings, payload.RunSettings);
Assert.IsFalse(payload.CollectMetrics);

_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStart(), Times.Once);
_mockEventSource.Verify(es => es.TranslationLayerTestRunAttachmentsProcessingStop(), Times.Once);
_mockTestRequestManager.Verify(trm => trm.ResetOptions(), Times.Never);
_mockTestRequestManager.Verify(trm => trm.ProcessTestRunAttachments(
It.IsAny<TestRunAttachmentsProcessingPayload>(),
It.IsAny<ITestRunAttachmentsProcessingEventsHandler>(),
It.IsAny<ProtocolConfig>()), Times.Once);
}
}