Skip to content

Commit fb527ca

Browse files
Add TestingPlatformTrace and MSBuild --verbosity option to dotnet test (#46909)
1 parent 045c58b commit fb527ca

File tree

9 files changed

+100
-34
lines changed

9 files changed

+100
-34
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ internal static class CliConstants
4646
public const string DLLExtension = ".dll";
4747

4848
public const string MTPTarget = "_MTPBuild";
49+
50+
public const string TestTraceLoggingEnvVar = "DOTNET_CLI_TEST_TRACEFILE";
4951
}
5052

5153
internal static class TestStates
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.DotNet.Cli;
5+
6+
namespace Microsoft.DotNet.Tools.Test
7+
{
8+
internal static class Logger
9+
{
10+
public static bool TraceEnabled { get; private set; }
11+
private static readonly string _traceFilePath;
12+
private static readonly object _lock = new();
13+
14+
static Logger()
15+
{
16+
_traceFilePath = Environment.GetEnvironmentVariable(CliConstants.TestTraceLoggingEnvVar);
17+
TraceEnabled = !string.IsNullOrEmpty(_traceFilePath);
18+
}
19+
20+
public static void LogTrace(Func<string> messageLog)
21+
{
22+
if (!TraceEnabled)
23+
{
24+
return;
25+
}
26+
27+
try
28+
{
29+
string message = $"[dotnet test - {DateTimeOffset.UtcNow:MM/dd/yyyy HH:mm:ss.fff}]{messageLog()}";
30+
31+
lock (_lock)
32+
{
33+
using StreamWriter logFile = File.AppendText(_traceFilePath);
34+
logFile.WriteLine(message);
35+
}
36+
}
37+
catch (Exception ex)
38+
{
39+
Console.WriteLine($"[dotnet test - {DateTimeOffset.UtcNow:MM/dd/yyyy HH:mm:ss.fff}]{ex}");
40+
}
41+
}
42+
}
43+
}

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,19 @@ public bool EnqueueTestApplications()
135135

136136
private void LogProjectProperties(IEnumerable<Module> modules)
137137
{
138-
if (!VSTestTrace.TraceEnabled)
138+
if (!Logger.TraceEnabled)
139139
{
140140
return;
141141
}
142142

143143
foreach (var module in modules)
144144
{
145-
Console.WriteLine();
146-
147-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.ProjectFullPath}: {module.ProjectFullPath}");
148-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.IsTestProject}: {module.IsTestProject}");
149-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.IsTestingPlatformApplication}: {module.IsTestingPlatformApplication}");
150-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.TargetFramework}: {module.TargetFramework}");
151-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.TargetPath}: {module.TargetPath}");
152-
VSTestTrace.SafeWriteTrace(() => $"{ProjectProperties.RunSettingsFilePath}: {module.RunSettingsFilePath}");
153-
154-
Console.WriteLine();
145+
Logger.LogTrace(() => $"{ProjectProperties.ProjectFullPath}: {module.ProjectFullPath}");
146+
Logger.LogTrace(() => $"{ProjectProperties.IsTestProject}: {module.IsTestProject}");
147+
Logger.LogTrace(() => $"{ProjectProperties.IsTestingPlatformApplication}: {module.IsTestingPlatformApplication}");
148+
Logger.LogTrace(() => $"{ProjectProperties.TargetFramework}: {module.TargetFramework}");
149+
Logger.LogTrace(() => $"{ProjectProperties.TargetPath}: {module.TargetPath}");
150+
Logger.LogTrace(() => $"{ProjectProperties.RunSettingsFilePath}: {module.RunSettingsFilePath}");
155151
}
156152
}
157153

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public static BuildOptions GetBuildOptions(ParseResult parseResult, int degreeOf
6969
buildProperties,
7070
parseResult.GetValue(CommonOptions.NoRestoreOption),
7171
parseResult.GetValue(TestingPlatformOptions.NoBuildOption),
72+
parseResult.HasOption(CommonOptions.VerbosityOption) ? parseResult.GetValue(CommonOptions.VerbosityOption) : null,
7273
degreeOfParallelism,
7374
unmatchedTokens,
7475
msbuildArgs);
@@ -110,6 +111,11 @@ private static bool BuildOrRestoreProjectOrSolution(string filePath, BuildOption
110111
{
111112
List<string> msbuildArgs = [.. buildOptions.MSBuildArgs];
112113

114+
if (buildOptions.Verbosity is null)
115+
{
116+
msbuildArgs.Add($"-verbosity:quiet");
117+
}
118+
113119
msbuildArgs.Add(filePath);
114120
msbuildArgs.Add($"-target:{CliConstants.MTPTarget}");
115121

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ internal record PathOptions(string ProjectPath, string SolutionPath, string Dire
99

1010
internal record BuildProperties(string Configuration, string RuntimeIdentifier, string TargetFramework);
1111

12-
internal record BuildOptions(PathOptions PathOptions, BuildProperties BuildProperties, bool HasNoRestore, bool HasNoBuild, int DegreeOfParallelism, List<string> UnmatchedTokens, IEnumerable<string> MSBuildArgs);
12+
internal record BuildOptions(PathOptions PathOptions, BuildProperties BuildProperties, bool HasNoRestore, bool HasNoBuild, VerbosityOptions? Verbosity, int DegreeOfParallelism, List<string> UnmatchedTokens, IEnumerable<string> MSBuildArgs);
1313
}

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

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ public void OnHandshakeReceived(object sender, HandshakeArgs args)
3131
_executions[testApplication] = appInfo;
3232
_output.AssemblyRunStarted(appInfo.ModulePath, appInfo.TargetFramework, appInfo.Architecture, appInfo.ExecutionId);
3333

34-
if (!VSTestTrace.TraceEnabled) return;
34+
if (!Logger.TraceEnabled) return;
3535

3636
foreach (var property in args.Handshake.Properties)
3737
{
38-
VSTestTrace.SafeWriteTrace(() => $"{GetHandshakePropertyName(property.Key)}: {property.Value}");
38+
Logger.LogTrace(() => $"{GetHandshakePropertyName(property.Key)}: {property.Value}");
3939
}
4040
}
4141

@@ -65,12 +65,12 @@ public void OnDiscoveredTestsReceived(object sender, DiscoveredTestEventArgs arg
6565
test.Uid);
6666
}
6767

68-
if (!VSTestTrace.TraceEnabled) return;
68+
if (!Logger.TraceEnabled) return;
6969

70-
VSTestTrace.SafeWriteTrace(() => $"DiscoveredTests Execution Id: {args.ExecutionId}");
70+
Logger.LogTrace(() => $"DiscoveredTests Execution Id: {args.ExecutionId}");
7171
foreach (var discoveredTestMessage in args.DiscoveredTests)
7272
{
73-
VSTestTrace.SafeWriteTrace(() => $"DiscoveredTest: {discoveredTestMessage.Uid}, {discoveredTestMessage.DisplayName}");
73+
Logger.LogTrace(() => $"DiscoveredTest: {discoveredTestMessage.Uid}, {discoveredTestMessage.DisplayName}");
7474
}
7575
}
7676

@@ -108,20 +108,20 @@ public void OnTestResultsReceived(object sender, TestResultEventArgs args)
108108
errorOutput: null);
109109
}
110110

111-
if (!VSTestTrace.TraceEnabled) return;
111+
if (!Logger.TraceEnabled) return;
112112

113-
VSTestTrace.SafeWriteTrace(() => $"TestResults Execution Id: {args.ExecutionId}");
113+
Logger.LogTrace(() => $"TestResults Execution Id: {args.ExecutionId}");
114114

115115
foreach (SuccessfulTestResult successfulTestResult in args.SuccessfulTestResults)
116116
{
117-
VSTestTrace.SafeWriteTrace(() => $"SuccessfulTestResult: {successfulTestResult.Uid}, {successfulTestResult.DisplayName}, " +
117+
Logger.LogTrace(() => $"SuccessfulTestResult: {successfulTestResult.Uid}, {successfulTestResult.DisplayName}, " +
118118
$"{successfulTestResult.State}, {successfulTestResult.Duration}, {successfulTestResult.Reason}, {successfulTestResult.StandardOutput}," +
119119
$"{successfulTestResult.ErrorOutput}, {successfulTestResult.SessionUid}");
120120
}
121121

122122
foreach (FailedTestResult failedTestResult in args.FailedTestResults)
123123
{
124-
VSTestTrace.SafeWriteTrace(() => $"FailedTestResult: {failedTestResult.Uid}, {failedTestResult.DisplayName}, " +
124+
Logger.LogTrace(() => $"FailedTestResult: {failedTestResult.Uid}, {failedTestResult.DisplayName}, " +
125125
$"{failedTestResult.State}, {failedTestResult.Duration}, {failedTestResult.Reason}, {string.Join(", ", failedTestResult.Exceptions?.Select(e => $"{e.ErrorMessage}, {e.ErrorType}, {e.StackTrace}"))}" +
126126
$"{failedTestResult.StandardOutput}, {failedTestResult.ErrorOutput}, {failedTestResult.SessionUid}");
127127
}
@@ -140,31 +140,31 @@ public void OnFileArtifactsReceived(object sender, FileArtifactEventArgs args)
140140
artifact.TestDisplayName, artifact.FullPath);
141141
}
142142

143-
if (!VSTestTrace.TraceEnabled) return;
143+
if (!Logger.TraceEnabled) return;
144144

145-
VSTestTrace.SafeWriteTrace(() => $"FileArtifactMessages Execution Id: {args.ExecutionId}");
145+
Logger.LogTrace(() => $"FileArtifactMessages Execution Id: {args.ExecutionId}");
146146

147147
foreach (FileArtifact fileArtifactMessage in args.FileArtifacts)
148148
{
149-
VSTestTrace.SafeWriteTrace(() => $"FileArtifact: {fileArtifactMessage.FullPath}, {fileArtifactMessage.DisplayName}, " +
149+
Logger.LogTrace(() => $"FileArtifact: {fileArtifactMessage.FullPath}, {fileArtifactMessage.DisplayName}, " +
150150
$"{fileArtifactMessage.Description}, {fileArtifactMessage.TestUid}, {fileArtifactMessage.TestDisplayName}, " +
151151
$"{fileArtifactMessage.SessionUid}");
152152
}
153153
}
154154

155155
public void OnSessionEventReceived(object sender, SessionEventArgs args)
156156
{
157-
if (!VSTestTrace.TraceEnabled) return;
157+
if (!Logger.TraceEnabled) return;
158158

159159
var sessionEvent = args.SessionEvent;
160-
VSTestTrace.SafeWriteTrace(() => $"TestSessionEvent: {sessionEvent.SessionType}, {sessionEvent.SessionUid}, {sessionEvent.ExecutionId}");
160+
Logger.LogTrace(() => $"TestSessionEvent: {sessionEvent.SessionType}, {sessionEvent.SessionUid}, {sessionEvent.ExecutionId}");
161161
}
162162

163163
public void OnErrorReceived(object sender, ErrorEventArgs args)
164164
{
165-
if (!VSTestTrace.TraceEnabled) return;
165+
if (!Logger.TraceEnabled) return;
166166

167-
VSTestTrace.SafeWriteTrace(() => args.ErrorMessage);
167+
Logger.LogTrace(() => args.ErrorMessage);
168168
}
169169

170170
public void OnTestProcessExited(object sender, TestProcessExitEventArgs args)
@@ -180,21 +180,21 @@ public void OnTestProcessExited(object sender, TestProcessExitEventArgs args)
180180
_output.AssemblyRunCompleted(testApplication.Module.TargetPath ?? testApplication.Module.ProjectFullPath, testApplication.Module.TargetFramework, architecture: null, null, args.ExitCode, string.Join(Environment.NewLine, args.OutputData), string.Join(Environment.NewLine, args.ErrorData));
181181
}
182182

183-
if (!VSTestTrace.TraceEnabled) return;
183+
if (!Logger.TraceEnabled) return;
184184

185185
if (args.ExitCode != ExitCode.Success)
186186
{
187-
VSTestTrace.SafeWriteTrace(() => $"Test Process exited with non-zero exit code: {args.ExitCode}");
187+
Logger.LogTrace(() => $"Test Process exited with non-zero exit code: {args.ExitCode}");
188188
}
189189

190190
if (args.OutputData.Count > 0)
191191
{
192-
VSTestTrace.SafeWriteTrace(() => $"Output Data: {string.Join("\n", args.OutputData)}");
192+
Logger.LogTrace(() => $"Output Data: {string.Join("\n", args.OutputData)}");
193193
}
194194

195195
if (args.ErrorData.Count > 0)
196196
{
197-
VSTestTrace.SafeWriteTrace(() => $"Error Data: {string.Join("\n", args.ErrorData)}");
197+
Logger.LogTrace(() => $"Error Data: {string.Join("\n", args.ErrorData)}");
198198
}
199199
}
200200

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ private static CliCommand GetTestingPlatformCliCommand()
231231
command.Options.Add(TestingPlatformOptions.FrameworkOption);
232232
command.Options.Add(CommonOptions.OperatingSystemOption);
233233
command.Options.Add(CommonOptions.RuntimeOption);
234+
command.Options.Add(CommonOptions.VerbosityOption);
234235
command.Options.Add(CommonOptions.NoRestoreOption);
235236
command.Options.Add(TestingPlatformOptions.NoBuildOption);
236237
command.Options.Add(TestingPlatformOptions.NoAnsiOption);

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ namespace Microsoft.DotNet.Cli
1010
internal sealed class TestModulesFilterHandler
1111
{
1212
private readonly List<string> _args;
13-
1413
private readonly TestApplicationActionQueue _actionQueue;
1514

1615
public TestModulesFilterHandler(List<string> args, TestApplicationActionQueue actionQueue)
@@ -44,7 +43,7 @@ public bool RunWithTestModulesFilter(ParseResult parseResult)
4443
// If no matches were found, we simply return
4544
if (!testModulePaths.Any())
4645
{
47-
VSTestTrace.SafeWriteTrace(() => $"No test modules found for the given test module pattern: {testModules} with root directory: {rootDirectory}");
46+
Logger.LogTrace(() => $"No test modules found for the given test module pattern: {testModules} with root directory: {rootDirectory}");
4847
return false;
4948
}
5049

test/dotnet-test.Tests/GivenDotnetTestBuildsAndRunsTestsWithDifferentOptions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,5 +500,24 @@ public void RunMultiTFMsProjectSolutionWithFrameworkOption_ShouldReturnExitCodeG
500500
result.ExitCode.Should().Be(ExitCode.GenericFailure);
501501
}
502502

503+
[InlineData(TestingConstants.Debug)]
504+
[InlineData(TestingConstants.Release)]
505+
[Theory]
506+
public void RunWithTraceFileLogging_ShouldReturnExitCodeGenericFailure(string configuration)
507+
{
508+
TestAsset testInstance = _testAssetsManager.CopyTestAsset("MultiTestProjectSolutionWithTests", Guid.NewGuid().ToString()).WithSource();
509+
510+
string traceFile = "logs.txt";
511+
CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false)
512+
.WithWorkingDirectory(testInstance.Path)
513+
.WithEnvironmentVariable(CliConstants.TestTraceLoggingEnvVar, traceFile)
514+
.WithEnableTestingPlatform()
515+
.Execute(TestingPlatformOptions.ConfigurationOption.Name, configuration);
516+
517+
Assert.True(File.Exists(Path.Combine(testInstance.Path, traceFile)), "Trace file should exist after test execution.");
518+
519+
result.ExitCode.Should().Be(ExitCode.GenericFailure);
520+
}
521+
503522
}
504523
}

0 commit comments

Comments
 (0)