Skip to content

Commit

Permalink
dotnet test improvements for MTP
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Mar 9, 2025
1 parent 7726046 commit a7e8c22
Show file tree
Hide file tree
Showing 48 changed files with 64 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ For MSTest before 2.2.4, the timeout is used for all testcases.</value>
<comment>{0} - test message state</comment>
</data>
<data name="CmdUnsupportedVSTestTestApplicationsDescription" xml:space="preserve">
<value>Test projects that use both VSTest and Microsoft.Testing.Platform in the same solution are not supported.
<value>Test project '{0}' is using VSTest. When opting-in via dotnet.config, all the test projects are expected to be using Microsoft.Testing.Platform.
See https://aka.ms/dotnet-test/mtp for more information.</value>
</data>
<data name="Aborted" xml:space="preserve">
Expand Down
29 changes: 17 additions & 12 deletions src/Cli/dotnet/commands/dotnet-test/MSBuildHandler.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Concurrent;
using System.IO;
using Microsoft.DotNet.Tools.Common;
using Microsoft.DotNet.Tools.Test;
using Microsoft.Testing.Platform.OutputDevice;
using Microsoft.Testing.Platform.OutputDevice.Terminal;

namespace Microsoft.DotNet.Cli
Expand Down Expand Up @@ -70,7 +73,7 @@ private int RunBuild(string directoryPath, BuildOptions buildOptions)
return ExitCode.GenericFailure;
}

(IEnumerable<Module> projects, bool restored) = GetProjectsProperties(projectOrSolutionFilePath, isSolution, buildOptions);
(IEnumerable<TestModule> projects, bool restored) = GetProjectsProperties(projectOrSolutionFilePath, isSolution, buildOptions);

InitializeTestApplications(projects);

Expand All @@ -79,28 +82,30 @@ private int RunBuild(string directoryPath, BuildOptions buildOptions)

private int RunBuild(string filePath, bool isSolution, BuildOptions buildOptions)
{
(IEnumerable<Module> projects, bool restored) = GetProjectsProperties(filePath, isSolution, buildOptions);
(IEnumerable<TestModule> projects, bool restored) = GetProjectsProperties(filePath, isSolution, buildOptions);

InitializeTestApplications(projects);

return restored ? ExitCode.Success : ExitCode.GenericFailure;
}

private void InitializeTestApplications(IEnumerable<Module> modules)
private void InitializeTestApplications(IEnumerable<TestModule> modules)
{
foreach (Module module in modules)
foreach (TestModule module in modules)
{
if (!module.IsTestProject)
if (!module.IsTestProject && !module.IsTestingPlatformApplication)
{
// Non test projects, like the projects that include production code are skipped over, we won't run them.
return;
// This should never happen. We should only ever create Module if it's a test project.
throw new InvalidOperationException();
}

if (!module.IsTestingPlatformApplication)
{
// If one test app has IsTestingPlatformApplication set to false, then we will not run any of the test apps
// If one test app has IsTestingPlatformApplication set to false (VSTest and not MTP), then we will not run any of the test apps
// Note that we still continue the loop here so that we print all projects that are VSTest and not MTP.
_areTestingPlatformApplications = false;
return;
_output.WriteMessage(string.Format(LocalizableStrings.CmdUnsupportedVSTestTestApplicationsDescription, Path.GetFileName(module.ProjectFullPath)), new SystemConsoleColor { ConsoleColor = ConsoleColor.Red });
continue;
}

var testApp = new TestApplication(module, _args);
Expand All @@ -122,9 +127,9 @@ public bool EnqueueTestApplications()
return true;
}

private (IEnumerable<Module> Projects, bool Restored) GetProjectsProperties(string solutionOrProjectFilePath, bool isSolution, BuildOptions buildOptions)
private (IEnumerable<TestModule> Projects, bool Restored) GetProjectsProperties(string solutionOrProjectFilePath, bool isSolution, BuildOptions buildOptions)
{
(IEnumerable<Module> projects, bool isBuiltOrRestored) = isSolution ?
(IEnumerable<TestModule> projects, bool isBuiltOrRestored) = isSolution ?
MSBuildUtility.GetProjectsFromSolution(solutionOrProjectFilePath, buildOptions) :
MSBuildUtility.GetProjectsFromProject(solutionOrProjectFilePath, buildOptions);

Expand All @@ -133,7 +138,7 @@ public bool EnqueueTestApplications()
return (projects, isBuiltOrRestored);
}

private void LogProjectProperties(IEnumerable<Module> modules)
private void LogProjectProperties(IEnumerable<TestModule> modules)
{
if (!Logger.TraceEnabled)
{
Expand Down
14 changes: 7 additions & 7 deletions src/Cli/dotnet/commands/dotnet-test/MSBuildUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.Cli
{
internal static class MSBuildUtility
{
public static (IEnumerable<Module> Projects, bool IsBuiltOrRestored) GetProjectsFromSolution(string solutionFilePath, BuildOptions buildOptions)
public static (IEnumerable<TestModule> Projects, bool IsBuiltOrRestored) GetProjectsFromSolution(string solutionFilePath, BuildOptions buildOptions)
{
SolutionModel solutionModel = SlnFileFactory.CreateFromFileOrDirectory(solutionFilePath, includeSolutionFilterFiles: true, includeSolutionXmlFiles: true);

Expand All @@ -23,18 +23,18 @@ public static (IEnumerable<Module> Projects, bool IsBuiltOrRestored) GetProjects
Path.GetDirectoryName(solutionModel.Description) :
SolutionAndProjectUtility.GetRootDirectory(solutionFilePath);

ConcurrentBag<Module> projects = GetProjectsProperties(new ProjectCollection(), solutionModel.SolutionProjects.Select(p => Path.Combine(rootDirectory, p.FilePath)), buildOptions);
ConcurrentBag<TestModule> projects = GetProjectsProperties(new ProjectCollection(), solutionModel.SolutionProjects.Select(p => Path.Combine(rootDirectory, p.FilePath)), buildOptions);

isBuiltOrRestored |= !projects.IsEmpty;

return (projects, isBuiltOrRestored);
}

public static (IEnumerable<Module> Projects, bool IsBuiltOrRestored) GetProjectsFromProject(string projectFilePath, BuildOptions buildOptions)
public static (IEnumerable<TestModule> Projects, bool IsBuiltOrRestored) GetProjectsFromProject(string projectFilePath, BuildOptions buildOptions)
{
bool isBuiltOrRestored = BuildOrRestoreProjectOrSolution(projectFilePath, buildOptions);

IEnumerable<Module> projects = SolutionAndProjectUtility.GetProjectProperties(projectFilePath, GetGlobalProperties(buildOptions.BuildProperties), new ProjectCollection());
IEnumerable<TestModule> projects = SolutionAndProjectUtility.GetProjectProperties(projectFilePath, GetGlobalProperties(buildOptions.BuildProperties), new ProjectCollection());

isBuiltOrRestored |= projects.Any();

Expand Down Expand Up @@ -124,16 +124,16 @@ private static bool BuildOrRestoreProjectOrSolution(string filePath, BuildOption
return result == (int)BuildResultCode.Success;
}

private static ConcurrentBag<Module> GetProjectsProperties(ProjectCollection projectCollection, IEnumerable<string> projects, BuildOptions buildOptions)
private static ConcurrentBag<TestModule> GetProjectsProperties(ProjectCollection projectCollection, IEnumerable<string> projects, BuildOptions buildOptions)
{
var allProjects = new ConcurrentBag<Module>();
var allProjects = new ConcurrentBag<TestModule>();

Parallel.ForEach(
projects,
new ParallelOptions { MaxDegreeOfParallelism = buildOptions.DegreeOfParallelism },
(project) =>
{
IEnumerable<Module> projectsMetadata = SolutionAndProjectUtility.GetProjectProperties(project, GetGlobalProperties(buildOptions.BuildProperties), projectCollection);
IEnumerable<TestModule> projectsMetadata = SolutionAndProjectUtility.GetProjectProperties(project, GetGlobalProperties(buildOptions.BuildProperties), projectCollection);
foreach (var projectMetadata in projectsMetadata)
{
allProjects.Add(projectMetadata);
Expand Down
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 @@ -3,7 +3,7 @@

namespace Microsoft.DotNet.Cli
{
internal sealed record Module(string? TargetPath, string? ProjectFullPath, string? TargetFramework, string? RunSettingsFilePath, bool IsTestingPlatformApplication, bool IsTestProject);
internal sealed record TestModule(string? TargetPath, string? ProjectFullPath, string? TargetFramework, string? RunSettingsFilePath, bool IsTestingPlatformApplication, bool IsTestProject);

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

Expand Down
13 changes: 6 additions & 7 deletions src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ public static string GetRootDirectory(string solutionOrProjectFilePath)
return string.IsNullOrEmpty(fileDirectory) ? Directory.GetCurrentDirectory() : fileDirectory;
}

public static IEnumerable<Module> GetProjectProperties(string projectFilePath, IDictionary<string, string> globalProperties, ProjectCollection projectCollection)
public static IEnumerable<TestModule> GetProjectProperties(string projectFilePath, IDictionary<string, string> globalProperties, ProjectCollection projectCollection)
{
var projects = new List<Module>();
var projects = new List<TestModule>();

var globalPropertiesWithoutTargetFramework = new Dictionary<string, string>(globalProperties);
globalPropertiesWithoutTargetFramework.Remove(ProjectProperties.TargetFramework);
Expand Down Expand Up @@ -164,23 +164,22 @@ private static bool IsValidTargetFramework(Project project, string targetFramewo
return frameworks.Contains(targetFramework);
}

private static Module? GetModuleFromProject(Project project)
private static TestModule? GetModuleFromProject(Project project)
{
_ = bool.TryParse(project.GetPropertyValue(ProjectProperties.IsTestProject), out bool isTestProject);
_ = bool.TryParse(project.GetPropertyValue(ProjectProperties.IsTestingPlatformApplication), out bool isTestingPlatformApplication);

if (!isTestProject)
if (!isTestProject && !isTestingPlatformApplication)
{
return null;
}

_ = bool.TryParse(project.GetPropertyValue(ProjectProperties.IsTestingPlatformApplication), out bool isTestingPlatformApplication);

string targetFramework = project.GetPropertyValue(ProjectProperties.TargetFramework);
string targetPath = project.GetPropertyValue(ProjectProperties.TargetPath);
string projectFullPath = project.GetPropertyValue(ProjectProperties.ProjectFullPath);
string runSettingsFilePath = project.GetPropertyValue(ProjectProperties.RunSettingsFilePath);

return new Module(targetPath, PathUtility.FixFilePath(projectFullPath), targetFramework, runSettingsFilePath, isTestingPlatformApplication, isTestProject);
return new TestModule(targetPath, PathUtility.FixFilePath(projectFullPath), targetFramework, runSettingsFilePath, isTestingPlatformApplication, isTestProject);
}
}
}
6 changes: 3 additions & 3 deletions src/Cli/dotnet/commands/dotnet-test/TestApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.DotNet.Cli
{
internal sealed class TestApplication : IDisposable
{
private readonly Module _module;
private readonly TestModule _module;
private readonly List<string> _args;

private readonly List<string> _outputData = [];
Expand All @@ -33,9 +33,9 @@ internal sealed class TestApplication : IDisposable
public event EventHandler<TestProcessExitEventArgs> TestProcessExited;
public event EventHandler<ExecutionEventArgs> ExecutionIdReceived;

public Module Module => _module;
public TestModule Module => _module;

public TestApplication(Module module, List<string> args)
public TestApplication(TestModule module, List<string> args)
{
_module = module;
_args = args;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public bool RunWithTestModulesFilter(ParseResult parseResult)

foreach (string testModule in testModulePaths)
{
var testApp = new TestApplication(new Module(testModule, null, null, null, true, true), _args);
var testApp = new TestApplication(new TestModule(testModule, null, null, null, true, true), _args);
// Write the test application to the channel
_actionQueue.Enqueue(testApp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ public int Run(ParseResult parseResult)

if (!_msBuildHandler.EnqueueTestApplications())
{
_output.WriteMessage(LocalizableStrings.CmdUnsupportedVSTestTestApplicationsDescription, new SystemConsoleColor { ConsoleColor = ConsoleColor.Red });
return ExitCode.GenericFailure;
}
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a7e8c22

Please sign in to comment.