| File: Processors\RunTestsArgumentProcessor.cs | Web Access |
| Project: src\vstest\src\vstest.console\vstest.console.csproj (vstest.console) |
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Linq; using Microsoft.VisualStudio.TestPlatform.Client.RequestHelper; using Microsoft.VisualStudio.TestPlatform.CommandLine.Internal; using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.ArtifactProcessing; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.Utilities; using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources; namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors; internal class RunTestsArgumentProcessor : IArgumentProcessor { public const string CommandName = "/RunTests"; private Lazy<IArgumentProcessorCapabilities>? _metadata; private Lazy<IArgumentExecutor>? _executor; private readonly IRunSettingsProvider _runSettingsProvider; private readonly CommandLineOptions _commandLineOptions; private readonly ITestRequestManager _testRequestManager; public RunTestsArgumentProcessor(CommandLineOptions commandLineOptions, IRunSettingsProvider runSettingsProvider, ITestRequestManager testRequestManager) { _commandLineOptions = commandLineOptions; _runSettingsProvider = runSettingsProvider; _testRequestManager = testRequestManager; } public Lazy<IArgumentProcessorCapabilities> Metadata => _metadata ??= new Lazy<IArgumentProcessorCapabilities>(() => new RunTestsArgumentProcessorCapabilities()); public Lazy<IArgumentExecutor>? Executor { get => _executor ??= new Lazy<IArgumentExecutor>(() => new RunTestsArgumentExecutor( _commandLineOptions, _runSettingsProvider, _testRequestManager, new ArtifactProcessingManager(_commandLineOptions.TestSessionCorrelationId), ConsoleOutput.Instance)); set => _executor = value; } } internal class RunTestsArgumentProcessorCapabilities : BaseArgumentProcessorCapabilities { public override string CommandName => RunTestsArgumentProcessor.CommandName; public override bool AllowMultiple => false; public override bool IsAction => true; public override ArgumentProcessorPriority Priority => ArgumentProcessorPriority.Normal; public override string HelpContentResourceName => CommandLineResources.RunTestsArgumentHelp; public override HelpContentPriority HelpPriority => HelpContentPriority.RunTestsArgumentProcessorHelpPriority; public override bool IsSpecialCommand => true; public override bool AlwaysExecute => false; } internal class RunTestsArgumentExecutor : IArgumentExecutor { /// <summary> /// Used for getting tests to run. /// </summary> private readonly CommandLineOptions _commandLineOptions; /// <summary> /// The instance of testPlatforms /// </summary> private readonly ITestRequestManager _testRequestManager; /// <summary> /// Used for sending discovery messages. /// </summary> internal IOutput Output; /// <summary> /// Settings manager to get currently active settings. /// </summary> private readonly IRunSettingsProvider _runSettingsManager; /// <summary> /// Registers and Unregisters for test run events before and after test run /// </summary> private readonly ITestRunEventsRegistrar _testRunEventsRegistrar; /// <summary> /// Shows the number of tests which were executed /// </summary> private static long s_numberOfExecutedTests; /// <summary> /// Default constructor. /// </summary> public RunTestsArgumentExecutor( CommandLineOptions commandLineOptions, IRunSettingsProvider runSettingsProvider, ITestRequestManager testRequestManager, IArtifactProcessingManager artifactProcessingManager, IOutput output) { ValidateArg.NotNull(commandLineOptions, nameof(commandLineOptions)); _commandLineOptions = commandLineOptions; _runSettingsManager = runSettingsProvider; _testRequestManager = testRequestManager; Output = output; _testRunEventsRegistrar = new TestRunRequestEventsRegistrar(Output, _commandLineOptions, artifactProcessingManager, _runSettingsManager); } public void Initialize(string? argument) { // Nothing to do. } /// <summary> /// Execute all of the tests. /// </summary> public ArgumentProcessorResult Execute() { TPDebug.Assert(_commandLineOptions != null); TPDebug.Assert(!StringUtils.IsNullOrWhiteSpace(_runSettingsManager?.ActiveRunSettings?.SettingsXml)); if (_commandLineOptions.IsDesignMode) { // Do not attempt execution in case of design mode. Expect execution to happen via the design mode client. return ArgumentProcessorResult.Success; } // Ensure a test source file was provided var anySource = _commandLineOptions.Sources.FirstOrDefault(); if (anySource == null) { throw new CommandLineException(CommandLineResources.MissingTestSourceFile); } if (Environment.GetEnvironmentVariable("VSTEST_MSBUILD_NOLOGO") != "1") { Output.WriteLine(CommandLineResources.StartingExecution, OutputLevel.Information); } if (!StringUtils.IsNullOrEmpty(EqtTrace.LogFile)) { Output.Information(false, CommandLineResources.VstestDiagLogOutputPath, EqtTrace.LogFile); } var runSettings = _runSettingsManager.ActiveRunSettings.SettingsXml; if (_commandLineOptions.Sources.Any()) { RunTests(runSettings); } bool treatNoTestsAsError = RunSettingsUtilities.GetTreatNoTestsAsError(runSettings); return treatNoTestsAsError && s_numberOfExecutedTests == 0 ? ArgumentProcessorResult.Fail : ArgumentProcessorResult.Success; } private void RunTests(string runSettings) { // create/start test run EqtTrace.Info("RunTestsArgumentProcessor:Execute: Test run is starting."); EqtTrace.Verbose("RunTestsArgumentProcessor:Execute: Queuing Test run."); // for command line keep alive is always false. // for Windows Store apps it should be false, as Windows Store apps executor should terminate after finishing the test execution. var keepAlive = false; var runRequestPayload = new TestRunRequestPayload() { Sources = _commandLineOptions.Sources.ToList(), RunSettings = runSettings, KeepAlive = keepAlive, TestPlatformOptions = new TestPlatformOptions() { TestCaseFilter = _commandLineOptions.TestCaseFilterValue } }; _testRequestManager.RunTests(runRequestPayload, null, _testRunEventsRegistrar, Constants.DefaultProtocolConfig); EqtTrace.Info("RunTestsArgumentProcessor:Execute: Test run is completed."); } private class TestRunRequestEventsRegistrar : ITestRunEventsRegistrar { private readonly IOutput _output; private readonly CommandLineOptions _commandLineOptions; private readonly IArtifactProcessingManager _artifactProcessingManager; private readonly IRunSettingsProvider _runSettingsProvider; public TestRunRequestEventsRegistrar(IOutput output, CommandLineOptions commandLineOptions, IArtifactProcessingManager artifactProcessingManager, IRunSettingsProvider runSettingsProvider) { _output = output; _commandLineOptions = commandLineOptions; _artifactProcessingManager = artifactProcessingManager; _runSettingsProvider = runSettingsProvider; } public void LogWarning(string message) { ConsoleLogger.RaiseTestRunWarning(message); } public void RegisterTestRunEvents(ITestRunRequest testRunRequest) { testRunRequest.OnRunCompletion += TestRunRequest_OnRunCompletion; } public void UnregisterTestRunEvents(ITestRunRequest testRunRequest) { testRunRequest.OnRunCompletion -= TestRunRequest_OnRunCompletion; } /// <summary> /// Handles the TestRunRequest complete event /// </summary> /// <param name="sender"></param> /// <param name="e">RunCompletion args</param> private void TestRunRequest_OnRunCompletion(object? sender, TestRunCompleteEventArgs e) { // If run is not aborted/canceled then check the count of executed tests. // we need to check if there are any tests executed - to try show some help info to user to check for installed vsix extensions if (!e.IsAborted && !e.IsCanceled) { var testsFoundInAnySource = e.TestRunStatistics != null && e.TestRunStatistics.ExecutedTests > 0; s_numberOfExecutedTests = e.TestRunStatistics!.ExecutedTests; // Indicate the user to use test adapter path command if there are no tests found if (!testsFoundInAnySource && !_commandLineOptions.TestAdapterPathsSet && _commandLineOptions.TestCaseFilterValue == null) { _output.Warning(false, CommandLineResources.SuggestTestAdapterPathIfNoTestsIsFound); } } // Collect tests session artifacts for post processing if (_commandLineOptions.ArtifactProcessingMode == ArtifactProcessingMode.Collect) { var settingsXml = _runSettingsProvider.ActiveRunSettings?.SettingsXml; TPDebug.Assert(settingsXml is not null, "RunSettingsProvider.ActiveRunSettings.SettingsXml is null"); _artifactProcessingManager.CollectArtifacts(e, settingsXml); } } } }