Skip to content
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
6 changes: 3 additions & 3 deletions src/vstest.console/CommandLine/Executor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ internal class Executor
}

internal Executor(IOutput output, ITestPlatformEventSource testPlatformEventSource, IProcessHelper processHelper, IEnvironment environment)
: this(output, testPlatformEventSource, processHelper, environment, RunSettingsManager.Instance, RunSettingsHelper.Instance, new CommandLineOptions(), TestRunResultAggregator.Instance)
: this(output, testPlatformEventSource, processHelper, environment, RunSettingsManager.Instance, RunSettingsHelper.Instance, new CommandLineOptions(), new TestRunResultAggregator())
{
}

internal Executor(IOutput output, ITestPlatformEventSource testPlatformEventSource, IProcessHelper processHelper, IEnvironment environment, IRunSettingsProvider runSettingsProvider)
: this(output, testPlatformEventSource, processHelper, environment, runSettingsProvider, RunSettingsHelper.Instance, new CommandLineOptions(), TestRunResultAggregator.Instance)
: this(output, testPlatformEventSource, processHelper, environment, runSettingsProvider, RunSettingsHelper.Instance, new CommandLineOptions(), new TestRunResultAggregator())
{
}

Expand All @@ -125,7 +125,7 @@ internal Executor(IOutput output, ITestPlatformEventSource testPlatformEventSour
_runSettingsHelper = runSettingsHelper;
_commandLineOptions = commandLineOptions;
_testRunResultAggregator = testRunResultAggregator;
_testRequestManager = testRequestManager ?? new LazyTestRequestManager(() => new TestRequestManager(_commandLineOptions));
_testRequestManager = testRequestManager ?? new LazyTestRequestManager(() => new TestRequestManager(_commandLineOptions, _testRunResultAggregator));
}

/// <summary>
Expand Down
10 changes: 0 additions & 10 deletions src/vstest.console/CommandLine/TestRunResultAggregator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,15 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine;
/// </summary>
internal class TestRunResultAggregator
{
private static TestRunResultAggregator? s_instance;

/// <summary>
/// Initializes the TestRunResultAggregator
/// </summary>
/// <remarks>Constructor is private since the factory method should be used to get the instance.</remarks>
protected internal TestRunResultAggregator()
{
// Outcome is passed until we see a failure.
Outcome = TestOutcome.Passed;
}

/// <summary>
/// Gets the instance of the test run result aggregator.
/// </summary>
/// <returns>Instance of the test run result aggregator.</returns>
public static TestRunResultAggregator Instance
=> s_instance ??= new TestRunResultAggregator();

/// <summary>
/// The current test run outcome.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ internal static ArgumentProcessorFactory Create(IFeatureFlag? featureFlag = null
runSettingsProvider ??= RunSettingsManager.Instance;
runSettingsHelper ??= RunSettingsHelper.Instance;
commandLineOptions ??= new CommandLineOptions();
testRequestManager ??= new LazyTestRequestManager(() => new TestRequestManager(commandLineOptions));
testRequestManager ??= new LazyTestRequestManager(() => new TestRequestManager(commandLineOptions, new TestRunResultAggregator()));
var defaultArgumentProcessor = GetDefaultArgumentProcessors(runSettingsProvider, runSettingsHelper, commandLineOptions, testRequestManager);

if (!(featureFlag ?? FeatureFlag.Instance).IsSet(FeatureFlag.VSTEST_DISABLE_ARTIFACTS_POSTPROCESSING))
Expand Down
4 changes: 2 additions & 2 deletions src/vstest.console/TestPlatformHelpers/TestRequestManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ internal class TestRequestManager : ITestRequestManager
private CancellationTokenSource? _currentAttachmentsProcessingCancellationTokenSource;


internal TestRequestManager(CommandLineOptions commandLineOptions)
internal TestRequestManager(CommandLineOptions commandLineOptions, TestRunResultAggregator testRunResultAggregator)
: this(
commandLineOptions,
TestPlatformFactory.GetTestPlatform(),
TestRunResultAggregator.Instance,
testRunResultAggregator,
TestPlatformEventSource.Instance,
new InferHelper(AssemblyMetadataProvider.Instance),
MetricsPublisherFactory.GetMetricsPublisher(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.CommandLine;
[TestClass]
public class TestRunResultAggregatorTests
{
private readonly TestRunResultAggregator _resultAggregator = TestRunResultAggregator.Instance;
private readonly TestRunResultAggregator _resultAggregator = new TestRunResultAggregator();
private readonly Mock<ITestRunRequest> _mockTestRunRequest;

public TestRunResultAggregatorTests()
Expand Down
21 changes: 9 additions & 12 deletions test/vstest.console.UnitTests/ExecutorUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,19 +368,15 @@ public void MarkingTestRunFailedOnInjectedAggregatorIsObservedByExecutorExitCode
// The exit code produced at the end of Executor.Execute is OR-ed with the outcome of the
// TestRunResultAggregator (Executor.cs: exitCode |= (Outcome == Passed) ? 0 : 1). This test
// proves the reader (Executor) observes the SAME aggregator instance it was constructed with,
// not the process-wide TestRunResultAggregator.Instance static.
// and that separate aggregator instances are isolated from one another (no shared state).
//
// "--help" is a zero-baseline path: HelpArgumentProcessor runs first and returns Abort, which
// does not set the exit bit (only Fail does), so the aggregator's outcome is the sole
// contributor to the final exit code. That makes the two outcomes below decisively distinct.

// Baseline the shared static so the negative control is deterministic.
TestRunResultAggregator.Instance.Reset();

// Writer: mark a failure on an injected aggregator that is a different instance from the static.
// Writer: mark a failure on the injected aggregator.
var injectedAggregator = new DummyTestRunResultAggregator();
injectedAggregator.MarkTestRunFailed();
Assert.AreNotSame(TestRunResultAggregator.Instance, injectedAggregator);

// Reader observes the write through the injected instance: Failed outcome sets the exit bit.
var exitCodeWithInjected = new Executor(
Expand All @@ -395,20 +391,21 @@ public void MarkingTestRunFailedOnInjectedAggregatorIsObservedByExecutorExitCode

Assert.AreEqual(1, exitCodeWithInjected, "Executor must observe the injected aggregator's Failed outcome.");

// Negative control: an Executor bound to the static default (still Passed) yields a zero exit
// for the same args, and the write above did not leak onto the static instance.
var exitCodeWithStatic = new Executor(
// Negative control: an Executor bound to a separate, default aggregator (still Passed) yields a
// zero exit for the same args, and the write above did not leak onto this other instance.
var defaultAggregator = new TestRunResultAggregator();
var exitCodeWithDefault = new Executor(
new MockOutput(),
_mockTestPlatformEventSource.Object,
new ProcessHelper(),
new PlatformEnvironment(),
RunSettingsManager.Instance,
RunSettingsHelper.Instance,
_commandLineOptions,
TestRunResultAggregator.Instance).Execute("--help");
defaultAggregator).Execute("--help");

Assert.AreEqual(0, exitCodeWithStatic, "The static default aggregator is still Passed, so its Executor must not set the failure bit.");
Assert.AreEqual(TestOutcome.Passed, TestRunResultAggregator.Instance.Outcome, "Marking the injected aggregator failed must not leak onto the static instance.");
Assert.AreEqual(0, exitCodeWithDefault, "A separate default aggregator is still Passed, so its Executor must not set the failure bit.");
Assert.AreEqual(TestOutcome.Passed, defaultAggregator.Outcome, "Marking the injected aggregator failed must not leak onto other aggregator instances.");
}

private class MockOutput : IOutput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public void ExecutorInitializeWithValidSourceShouldAddItToTestSources()
{
_commandLineOptions.FileHelper = _mockFileHelper.Object;
_commandLineOptions.FilePatternParser = new FilePatternParser(new Mock<Matcher>().Object, _mockFileHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, TestPlatformFactory.GetTestPlatform(), TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, TestPlatformFactory.GetTestPlatform(), new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var executor = GetExecutor(testRequestManager, null);

executor.Initialize(_dummyTestFilePath);
Expand All @@ -144,7 +144,7 @@ public void ExecutorInitializeWithValidSourceShouldAddItToTestSources()
[TestMethod]
public void ExecutorExecuteForNoSourcesShouldReturnFail()
{
var testRequestManager = new TestRequestManager(_commandLineOptions, TestPlatformFactory.GetTestPlatform(), TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, TestPlatformFactory.GetTestPlatform(), new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var executor = GetExecutor(testRequestManager, null);

Assert.ThrowsExactly<CommandLineException>(() => executor.Execute());
Expand All @@ -161,7 +161,7 @@ public void ExecutorExecuteShouldThrowTestPlatformException()

ResetAndAddSourceToCommandLineOptions(true);

var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

var executor = GetExecutor(testRequestManager, null);

Expand All @@ -178,7 +178,7 @@ public void ExecutorExecuteShouldThrowSettingsException()
mockTestPlatform.Setup(tp => tp.CreateDiscoveryRequest(It.IsAny<IRequestData>(), It.IsAny<DiscoveryCriteria>(), It.IsAny<TestPlatformOptions>(), It.IsAny<Dictionary<string, SourceDetail>>(), It.IsAny<IWarningLogger>())).Returns(mockDiscoveryRequest.Object);
ResetAndAddSourceToCommandLineOptions(true);

var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

var listTestsArgumentExecutor = GetExecutor(testRequestManager, null);

Expand All @@ -197,7 +197,7 @@ public void ExecutorExecuteShouldThrowInvalidOperationException()
ResetAndAddSourceToCommandLineOptions(true);


var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

var listTestsArgumentExecutor = GetExecutor(testRequestManager, null);

Expand All @@ -215,7 +215,7 @@ public void ExecutorExecuteShouldThrowOtherExceptions()

ResetAndAddSourceToCommandLineOptions(true);

var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

var executor = GetExecutor(testRequestManager, null);

Expand Down Expand Up @@ -306,7 +306,7 @@ private void RunListFullyQualifiedTestArgumentProcessorWithTraits(Mock<IDiscover
var cmdOptions = _commandLineOptions;
cmdOptions.TestCaseFilterValue = "TestCategory=MyCat";

var testRequestManager = new TestRequestManager(cmdOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(cmdOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

GetExecutor(testRequestManager, mockConsoleOutput.Object).Execute();
}
Expand All @@ -324,7 +324,7 @@ private void RunListFullyQualifiedTestArgumentProcessorExecuteWithMockSetup(Mock

ResetAndAddSourceToCommandLineOptions(legitPath);

var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, TestRunResultAggregator.Instance, _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);
var testRequestManager = new TestRequestManager(_commandLineOptions, mockTestPlatform.Object, new TestRunResultAggregator(), _mockTestPlatformEventSource.Object, _inferHelper, _mockMetricsPublisherTask, _mockProcessHelper.Object, _mockAttachmentsProcessingManager.Object, _mockEnvironment.Object, _mockEnvironmentVariableHelper.Object);

GetExecutor(testRequestManager, mockConsoleOutput.Object).Execute();
}
Expand Down
Loading