Skip to content

Commit

Permalink
Fail in case of hybrid projects (new testing platform and vstest) (#4…
Browse files Browse the repository at this point in the history
  • Loading branch information
mariam-abdulla authored Nov 26, 2024
1 parent fde3f63 commit 95b3649
Show file tree
Hide file tree
Showing 24 changed files with 355 additions and 106 deletions.
1 change: 0 additions & 1 deletion src/Cli/dotnet/commands/dotnet-test/CliConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ internal static class CliConstants
public const string HelpOptionKey = "--help";
public const string ServerOptionKey = "--server";
public const string DotNetTestPipeOptionKey = "--dotnet-test-pipe";
public const string ProjectOptionKey = "--project";
public const string FrameworkOptionKey = "--framework";

public const string ServerOptionValue = "dotnettestcli";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

namespace Microsoft.DotNet.Tools.Test;

internal sealed record ModuleMessage(string? DLLPath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath) : IRequest;
internal sealed record ModuleMessage(string? DllOrExePath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath, string IsTestingPlatformApplication) : IRequest;
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ public object Deserialize(Stream stream)
string projectPath = ReadString(stream);
string targetFramework = ReadString(stream);
string runSettingsFilePath = ReadString(stream);
return new ModuleMessage(modulePath.Trim(), projectPath.Trim(), targetFramework.Trim(), runSettingsFilePath.Trim());
string isTestingPlatformApplication = ReadString(stream);
return new ModuleMessage(modulePath.Trim(), projectPath.Trim(), targetFramework.Trim(), runSettingsFilePath.Trim(), isTestingPlatformApplication.Trim());
}

public void Serialize(object objectToSerialize, Stream stream)
{
WriteString(stream, ((ModuleMessage)objectToSerialize).DLLPath);
WriteString(stream, ((ModuleMessage)objectToSerialize).DllOrExePath);
WriteString(stream, ((ModuleMessage)objectToSerialize).ProjectPath);
WriteString(stream, ((ModuleMessage)objectToSerialize).TargetFramework);
WriteString(stream, ((ModuleMessage)objectToSerialize).RunSettingsFilePath);
WriteString(stream, ((ModuleMessage)objectToSerialize).IsTestingPlatformApplication);
}
}
}
11 changes: 11 additions & 0 deletions src/Cli/dotnet/commands/dotnet-test/LocalizableStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,15 @@ Examples:
<data name="CmdTestModulesRootDirectoryDescription" xml:space="preserve">
<value>The test modules have the specified root directory.</value>
</data>
<data name="CmdUnsupportedMessageRequestTypeException" xml:space="preserve">
<value>Message Request type '{0}' is unsupported.</value>
<comment>{0} - message request type</comment>
</data>
<data name="CmdInvalidTestMessageStateException" xml:space="preserve">
<value>Invalid test message state '{0}'</value>
<comment>{0} - test message state</comment>
</data>
<data name="CmdUnsupportedVSTestTestApplicationsDescription" xml:space="preserve">
<value>Test application(s) that support VSTest are not supported.</value>
</data>
</root>
40 changes: 35 additions & 5 deletions src/Cli/dotnet/commands/dotnet-test/MSBuildConnectionHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Concurrent;
using System.CommandLine;
using System.IO.Pipes;
using Microsoft.DotNet.Cli.Utils;
Expand All @@ -15,6 +16,8 @@ internal sealed class MSBuildConnectionHandler : IDisposable

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

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

var testApp = new TestApplication(new Module(module.DLLPath, module.ProjectPath, module.TargetFramework, module.RunSettingsFilePath), _args);
// Write the test application to the channel
_actionQueue.Enqueue(testApp);
// Check if the test app has IsTestingPlatformApplication property set to true
if (bool.TryParse(module.IsTestingPlatformApplication, out bool isTestingPlatformApplication) && isTestingPlatformApplication)
{
var testApp = new TestApplication(new Module(module.DllOrExePath, module.ProjectPath, module.TargetFramework, module.RunSettingsFilePath), _args);
_testApplications.Add(testApp);
}
else // If one test app has IsTestingPlatformApplication set to false, then we will not run any of the test apps
{
_areTestingPlatformApplications = false;
}
}
catch (Exception ex)
{
Expand All @@ -79,14 +89,29 @@ private Task<IResponse> OnRequest(IRequest request)
return Task.FromResult((IResponse)VoidResponse.CachedInstance);
}

public bool EnqueueTestApplications()
{
if (!_areTestingPlatformApplications)
{
return false;
}

foreach (var testApp in _testApplications)
{
_actionQueue.Enqueue(testApp);
}
return true;
}

public int RunWithMSBuild(ParseResult parseResult)
{
List<string> msbuildCommandLineArgs =
[
parseResult.GetValue(TestingPlatformOptions.ProjectOption) ?? string.Empty,
$"-t:_GetTestsProject",
"-t:Restore;_GetTestsProject",
$"-p:GetTestsProjectPipeName={_pipeNameDescription.Name}",
"-verbosity:q"
"-verbosity:q",
"-nologo",
];

AddBinLogParameterIfExists(msbuildCommandLineArgs, _args);
Expand Down Expand Up @@ -137,6 +162,11 @@ public void Dispose()
{
namedPipeServer.Dispose();
}

foreach (var testApplication in _testApplications)
{
testApplication.Dispose();
}
}
}
}
2 changes: 1 addition & 1 deletion src/Cli/dotnet/commands/dotnet-test/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Microsoft.DotNet.Cli
{
internal sealed record Module(string? DLLOrExe, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath);
internal sealed record Module(string? DllOrExePath, string? ProjectPath, string? TargetFramework, string? RunSettingsFilePath);

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

Expand Down
45 changes: 19 additions & 26 deletions src/Cli/dotnet/commands/dotnet-test/TestApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ public async Task<int> RunAsync(bool isFilterMode, bool enableHelp, BuiltInOptio
return 1;
}

bool isDll = _module.DLLOrExe.EndsWith(".dll");
bool isDll = _module.DllOrExePath.EndsWith(".dll");

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

_namedPipeConnectionLoop.Wait();

return result;
}

private async Task WaitConnectionAsync(CancellationToken token)
{
try
Expand Down Expand Up @@ -145,7 +147,7 @@ private Task<IResponse> OnRequest(IRequest request)

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

private bool ModulePathExists()
{
if (!File.Exists(_module.DLLOrExe))
if (!File.Exists(_module.DllOrExePath))
{
ErrorReceived.Invoke(this, new ErrorEventArgs { ErrorMessage = $"Test module '{_module.DLLOrExe}' not found. Build the test application before or run 'dotnet test'." });
ErrorReceived.Invoke(this, new ErrorEventArgs { ErrorMessage = $"Test module '{_module.DllOrExePath}' not found. Build the test application before or run 'dotnet test'." });
return false;
}
return true;
}

private string BuildArgsWithDotnetRun(BuiltInOptions builtInOptions)
private string BuildArgsWithDotnetRun(bool hasHelp, BuiltInOptions builtInOptions)
{
StringBuilder builder = new();

builder.Append($"{CliConstants.DotnetRunCommand} {CliConstants.ProjectOptionKey} \"{_module.ProjectPath}\"");
builder.Append($"{CliConstants.DotnetRunCommand} {TestingPlatformOptions.ProjectOption.Name} \"{_module.ProjectPath}\"");

if (builtInOptions.HasNoRestore)
{
Expand Down Expand Up @@ -265,6 +267,11 @@ private string BuildArgsWithDotnetRun(BuiltInOptions builtInOptions)

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

if (hasHelp)
{
builder.Append($" {CliConstants.HelpOptionKey} ");
}

builder.Append(_args.Count != 0
? _args.Aggregate((a, b) => $"{a} {b}")
: string.Empty);
Expand All @@ -280,7 +287,7 @@ private string BuildArgs(bool isDll)

if (isDll)
{
builder.Append($"exec {_module.DLLOrExe} ");
builder.Append($"exec {_module.DllOrExePath} ");
}

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

private string BuildHelpArgs(bool isDll)
{
StringBuilder builder = new();

if (isDll)
{
builder.Append($"exec {_module.DLLOrExe} ");
}

builder.Append($" {CliConstants.HelpOptionKey} {CliConstants.ServerOptionKey} {CliConstants.ServerOptionValue} {CliConstants.DotNetTestPipeOptionKey} {_pipeNameDescription.Name}");

return builder.ToString();
}

public void OnHandshakeMessage(HandshakeMessage handshakeMessage)
{
if (handshakeMessage.Properties.TryGetValue(HandshakeMessagePropertyNames.ExecutionId, out string executionId))
{
AddExecutionId(executionId);
ExecutionIdReceived?.Invoke(this, new ExecutionEventArgs { ModulePath = _module.DLLOrExe, ExecutionId = executionId });
ExecutionIdReceived?.Invoke(this, new ExecutionEventArgs { ModulePath = _module.DllOrExePath, ExecutionId = executionId });
}
HandshakeReceived?.Invoke(this, new HandshakeArgs { Handshake = new Handshake(handshakeMessage.Properties) });
}
Expand Down Expand Up @@ -354,9 +347,9 @@ public override string ToString()
{
StringBuilder builder = new();

if (!string.IsNullOrEmpty(_module.DLLOrExe))
if (!string.IsNullOrEmpty(_module.DllOrExePath))
{
builder.Append($"DLL: {_module.DLLOrExe}");
builder.Append($"DLL: {_module.DllOrExePath}");
}

if (!string.IsNullOrEmpty(_module.ProjectPath))
Expand Down
Loading

0 comments on commit 95b3649

Please sign in to comment.