-
Notifications
You must be signed in to change notification settings - Fork 323
/
RunTestsArgumentProcessor.cs
235 lines (189 loc) · 9.33 KB
/
RunTestsArgumentProcessor.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// 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.CommandLine.TestPlatformHelpers;
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;
public Lazy<IArgumentProcessorCapabilities> Metadata
=> _metadata ??= new Lazy<IArgumentProcessorCapabilities>(() =>
new RunTestsArgumentProcessorCapabilities());
public Lazy<IArgumentExecutor>? Executor
{
get => _executor ??= new Lazy<IArgumentExecutor>(() =>
new RunTestsArgumentExecutor(
CommandLineOptions.Instance,
RunSettingsManager.Instance,
TestRequestManager.Instance,
new ArtifactProcessingManager(CommandLineOptions.Instance.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);
}
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);
}
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;
public TestRunRequestEventsRegistrar(IOutput output, CommandLineOptions commandLineOptions, IArtifactProcessingManager artifactProcessingManager)
{
_output = output;
_commandLineOptions = commandLineOptions;
_artifactProcessingManager = artifactProcessingManager;
}
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.Instance.TestAdapterPathsSet && _commandLineOptions.TestCaseFilterValue == null)
{
_output.Warning(false, CommandLineResources.SuggestTestAdapterPathIfNoTestsIsFound);
}
}
// Collect tests session artifacts for post processing
if (_commandLineOptions.ArtifactProcessingMode == ArtifactProcessingMode.Collect)
{
TPDebug.Assert(RunSettingsManager.Instance.ActiveRunSettings.SettingsXml is not null, "RunSettingsManager.Instance.ActiveRunSettings.SettingsXml is null");
_artifactProcessingManager.CollectArtifacts(e, RunSettingsManager.Instance.ActiveRunSettings.SettingsXml);
}
}
}
}