Skip to content

Commit 95b3649

Browse files
Fail in case of hybrid projects (new testing platform and vstest) (#45133)
1 parent fde3f63 commit 95b3649

24 files changed

+355
-106
lines changed

src/Cli/dotnet/commands/dotnet-test/CliConstants.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ internal static class CliConstants
99
public const string HelpOptionKey = "--help";
1010
public const string ServerOptionKey = "--server";
1111
public const string DotNetTestPipeOptionKey = "--dotnet-test-pipe";
12-
public const string ProjectOptionKey = "--project";
1312
public const string FrameworkOptionKey = "--framework";
1413

1514
public const string ServerOptionValue = "dotnettestcli";

src/Cli/dotnet/commands/dotnet-test/IPC/Models/ModuleMessage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
namespace Microsoft.DotNet.Tools.Test;
77

8-
internal sealed record ModuleMessage(string? DLLPath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath) : IRequest;
8+
internal sealed record ModuleMessage(string? DllOrExePath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath, string IsTestingPlatformApplication) : IRequest;

src/Cli/dotnet/commands/dotnet-test/IPC/Serializers/ModuleMessageSerializer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ public object Deserialize(Stream stream)
1313
string projectPath = ReadString(stream);
1414
string targetFramework = ReadString(stream);
1515
string runSettingsFilePath = ReadString(stream);
16-
return new ModuleMessage(modulePath.Trim(), projectPath.Trim(), targetFramework.Trim(), runSettingsFilePath.Trim());
16+
string isTestingPlatformApplication = ReadString(stream);
17+
return new ModuleMessage(modulePath.Trim(), projectPath.Trim(), targetFramework.Trim(), runSettingsFilePath.Trim(), isTestingPlatformApplication.Trim());
1718
}
1819

1920
public void Serialize(object objectToSerialize, Stream stream)
2021
{
21-
WriteString(stream, ((ModuleMessage)objectToSerialize).DLLPath);
22+
WriteString(stream, ((ModuleMessage)objectToSerialize).DllOrExePath);
2223
WriteString(stream, ((ModuleMessage)objectToSerialize).ProjectPath);
2324
WriteString(stream, ((ModuleMessage)objectToSerialize).TargetFramework);
2425
WriteString(stream, ((ModuleMessage)objectToSerialize).RunSettingsFilePath);
26+
WriteString(stream, ((ModuleMessage)objectToSerialize).IsTestingPlatformApplication);
2527
}
2628
}
2729
}

src/Cli/dotnet/commands/dotnet-test/LocalizableStrings.resx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,15 @@ Examples:
315315
<data name="CmdTestModulesRootDirectoryDescription" xml:space="preserve">
316316
<value>The test modules have the specified root directory.</value>
317317
</data>
318+
<data name="CmdUnsupportedMessageRequestTypeException" xml:space="preserve">
319+
<value>Message Request type '{0}' is unsupported.</value>
320+
<comment>{0} - message request type</comment>
321+
</data>
322+
<data name="CmdInvalidTestMessageStateException" xml:space="preserve">
323+
<value>Invalid test message state '{0}'</value>
324+
<comment>{0} - test message state</comment>
325+
</data>
326+
<data name="CmdUnsupportedVSTestTestApplicationsDescription" xml:space="preserve">
327+
<value>Test application(s) that support VSTest are not supported.</value>
328+
</data>
318329
</root>

src/Cli/dotnet/commands/dotnet-test/MSBuildConnectionHandler.cs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Concurrent;
45
using System.CommandLine;
56
using System.IO.Pipes;
67
using Microsoft.DotNet.Cli.Utils;
@@ -15,6 +16,8 @@ internal sealed class MSBuildConnectionHandler : IDisposable
1516

1617
private readonly PipeNameDescription _pipeNameDescription = NamedPipeServer.GetPipeName(Guid.NewGuid().ToString("N"));
1718
private readonly List<NamedPipeServer> _namedPipeConnections = new();
19+
private readonly ConcurrentBag<TestApplication> _testApplications = new();
20+
private bool _areTestingPlatformApplications = true;
1821

1922
public MSBuildConnectionHandler(List<string> args, TestApplicationActionQueue actionQueue)
2023
{
@@ -62,9 +65,16 @@ private Task<IResponse> OnRequest(IRequest request)
6265
throw new NotSupportedException($"Request '{request.GetType()}' is unsupported.");
6366
}
6467

65-
var testApp = new TestApplication(new Module(module.DLLPath, module.ProjectPath, module.TargetFramework, module.RunSettingsFilePath), _args);
66-
// Write the test application to the channel
67-
_actionQueue.Enqueue(testApp);
68+
// Check if the test app has IsTestingPlatformApplication property set to true
69+
if (bool.TryParse(module.IsTestingPlatformApplication, out bool isTestingPlatformApplication) && isTestingPlatformApplication)
70+
{
71+
var testApp = new TestApplication(new Module(module.DllOrExePath, module.ProjectPath, module.TargetFramework, module.RunSettingsFilePath), _args);
72+
_testApplications.Add(testApp);
73+
}
74+
else // If one test app has IsTestingPlatformApplication set to false, then we will not run any of the test apps
75+
{
76+
_areTestingPlatformApplications = false;
77+
}
6878
}
6979
catch (Exception ex)
7080
{
@@ -79,14 +89,29 @@ private Task<IResponse> OnRequest(IRequest request)
7989
return Task.FromResult((IResponse)VoidResponse.CachedInstance);
8090
}
8191

92+
public bool EnqueueTestApplications()
93+
{
94+
if (!_areTestingPlatformApplications)
95+
{
96+
return false;
97+
}
98+
99+
foreach (var testApp in _testApplications)
100+
{
101+
_actionQueue.Enqueue(testApp);
102+
}
103+
return true;
104+
}
105+
82106
public int RunWithMSBuild(ParseResult parseResult)
83107
{
84108
List<string> msbuildCommandLineArgs =
85109
[
86110
parseResult.GetValue(TestingPlatformOptions.ProjectOption) ?? string.Empty,
87-
$"-t:_GetTestsProject",
111+
"-t:Restore;_GetTestsProject",
88112
$"-p:GetTestsProjectPipeName={_pipeNameDescription.Name}",
89-
"-verbosity:q"
113+
"-verbosity:q",
114+
"-nologo",
90115
];
91116

92117
AddBinLogParameterIfExists(msbuildCommandLineArgs, _args);
@@ -137,6 +162,11 @@ public void Dispose()
137162
{
138163
namedPipeServer.Dispose();
139164
}
165+
166+
foreach (var testApplication in _testApplications)
167+
{
168+
testApplication.Dispose();
169+
}
140170
}
141171
}
142172
}

src/Cli/dotnet/commands/dotnet-test/Models.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Microsoft.DotNet.Cli
77
{
8-
internal sealed record Module(string? DLLOrExe, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath);
8+
internal sealed record Module(string? DllOrExePath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath);
99

1010
internal sealed record Handshake(Dictionary<byte, string>? Properties);
1111

src/Cli/dotnet/commands/dotnet-test/TestApplication.cs

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ public async Task<int> RunAsync(bool isFilterMode, bool enableHelp, BuiltInOptio
5555
return 1;
5656
}
5757

58-
bool isDll = _module.DLLOrExe.EndsWith(".dll");
58+
bool isDll = _module.DllOrExePath.EndsWith(".dll");
5959

6060
ProcessStartInfo processStartInfo = new()
6161
{
62-
FileName = isFilterMode ? isDll ? Environment.ProcessPath : _module.DLLOrExe : Environment.ProcessPath,
63-
Arguments = enableHelp ? BuildHelpArgs(isDll) : isFilterMode ? BuildArgs(isDll) : BuildArgsWithDotnetRun(builtInOptions),
62+
FileName = isFilterMode ? isDll ? Environment.ProcessPath : _module.DllOrExePath : Environment.ProcessPath,
63+
Arguments = isFilterMode ? BuildArgs(isDll) : BuildArgsWithDotnetRun(enableHelp, builtInOptions),
6464
RedirectStandardOutput = true,
6565
RedirectStandardError = true
6666
};
@@ -74,8 +74,10 @@ public async Task<int> RunAsync(bool isFilterMode, bool enableHelp, BuiltInOptio
7474
var result = await StartProcess(processStartInfo);
7575

7676
_namedPipeConnectionLoop.Wait();
77+
7778
return result;
7879
}
80+
7981
private async Task WaitConnectionAsync(CancellationToken token)
8082
{
8183
try
@@ -145,7 +147,7 @@ private Task<IResponse> OnRequest(IRequest request)
145147

146148
default:
147149
// If it doesn't match any of the above, throw an exception
148-
throw new NotSupportedException($"Request '{request.GetType()}' is unsupported.");
150+
throw new NotSupportedException(string.Format(LocalizableStrings.CmdUnsupportedMessageRequestTypeException, request.GetType()));
149151
}
150152
}
151153
catch (Exception ex)
@@ -224,19 +226,19 @@ private void StoreOutputAndErrorData(Process process)
224226

225227
private bool ModulePathExists()
226228
{
227-
if (!File.Exists(_module.DLLOrExe))
229+
if (!File.Exists(_module.DllOrExePath))
228230
{
229-
ErrorReceived.Invoke(this, new ErrorEventArgs { ErrorMessage = $"Test module '{_module.DLLOrExe}' not found. Build the test application before or run 'dotnet test'." });
231+
ErrorReceived.Invoke(this, new ErrorEventArgs { ErrorMessage = $"Test module '{_module.DllOrExePath}' not found. Build the test application before or run 'dotnet test'." });
230232
return false;
231233
}
232234
return true;
233235
}
234236

235-
private string BuildArgsWithDotnetRun(BuiltInOptions builtInOptions)
237+
private string BuildArgsWithDotnetRun(bool hasHelp, BuiltInOptions builtInOptions)
236238
{
237239
StringBuilder builder = new();
238240

239-
builder.Append($"{CliConstants.DotnetRunCommand} {CliConstants.ProjectOptionKey} \"{_module.ProjectPath}\"");
241+
builder.Append($"{CliConstants.DotnetRunCommand} {TestingPlatformOptions.ProjectOption.Name} \"{_module.ProjectPath}\"");
240242

241243
if (builtInOptions.HasNoRestore)
242244
{
@@ -265,6 +267,11 @@ private string BuildArgsWithDotnetRun(BuiltInOptions builtInOptions)
265267

266268
builder.Append($" {CliConstants.ParametersSeparator} ");
267269

270+
if (hasHelp)
271+
{
272+
builder.Append($" {CliConstants.HelpOptionKey} ");
273+
}
274+
268275
builder.Append(_args.Count != 0
269276
? _args.Aggregate((a, b) => $"{a} {b}")
270277
: string.Empty);
@@ -280,7 +287,7 @@ private string BuildArgs(bool isDll)
280287

281288
if (isDll)
282289
{
283-
builder.Append($"exec {_module.DLLOrExe} ");
290+
builder.Append($"exec {_module.DllOrExePath} ");
284291
}
285292

286293
builder.Append(_args.Count != 0
@@ -292,26 +299,12 @@ private string BuildArgs(bool isDll)
292299
return builder.ToString();
293300
}
294301

295-
private string BuildHelpArgs(bool isDll)
296-
{
297-
StringBuilder builder = new();
298-
299-
if (isDll)
300-
{
301-
builder.Append($"exec {_module.DLLOrExe} ");
302-
}
303-
304-
builder.Append($" {CliConstants.HelpOptionKey} {CliConstants.ServerOptionKey} {CliConstants.ServerOptionValue} {CliConstants.DotNetTestPipeOptionKey} {_pipeNameDescription.Name}");
305-
306-
return builder.ToString();
307-
}
308-
309302
public void OnHandshakeMessage(HandshakeMessage handshakeMessage)
310303
{
311304
if (handshakeMessage.Properties.TryGetValue(HandshakeMessagePropertyNames.ExecutionId, out string executionId))
312305
{
313306
AddExecutionId(executionId);
314-
ExecutionIdReceived?.Invoke(this, new ExecutionEventArgs { ModulePath = _module.DLLOrExe, ExecutionId = executionId });
307+
ExecutionIdReceived?.Invoke(this, new ExecutionEventArgs { ModulePath = _module.DllOrExePath, ExecutionId = executionId });
315308
}
316309
HandshakeReceived?.Invoke(this, new HandshakeArgs { Handshake = new Handshake(handshakeMessage.Properties) });
317310
}
@@ -354,9 +347,9 @@ public override string ToString()
354347
{
355348
StringBuilder builder = new();
356349

357-
if (!string.IsNullOrEmpty(_module.DLLOrExe))
350+
if (!string.IsNullOrEmpty(_module.DllOrExePath))
358351
{
359-
builder.Append($"DLL: {_module.DLLOrExe}");
352+
builder.Append($"DLL: {_module.DllOrExePath}");
360353
}
361354

362355
if (!string.IsNullOrEmpty(_module.ProjectPath))

0 commit comments

Comments
 (0)