From 4bcf71239c1124db4a169c76a7836e59ad7c2812 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 24 Mar 2026 13:35:10 +0100 Subject: [PATCH 1/2] Attach diagnostic logs to acceptance test runs Automatically enable --diag flag in InvokeVsTest, InvokeDotnetTest, and InvokeVsTestForExecution test helpers so diagnostic logs are collected by default. When a test fails, the diag logs are attached to the test results via the existing _attachments mechanism. Each method gains a collectDiagnostics parameter (default true) so callers can opt out. If the arguments already contain --diag, the automatic flag is skipped to avoid conflicts. Closes #15571 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../IntegrationTestBase.cs | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs index d03ee27538..9f61b40d37 100644 --- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs +++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs @@ -210,8 +210,18 @@ public static string PrepareArguments(string testAssembly, string? testAdapterPa /// /// Arguments provided to vstest.console.exe /// Environment variables to set to the started process. - public void InvokeVsTest(string? arguments, Dictionary? environmentVariables = null) + /// When true, automatically adds --diag flag and attaches logs to test results on failure. + public void InvokeVsTest(string? arguments, Dictionary? environmentVariables = null, bool collectDiagnostics = true) { + if (collectDiagnostics && arguments?.Contains("--diag") != true) + { + var diagLogsDir = Path.Combine(TempDirectory.Path, "diag"); + Directory.CreateDirectory(diagLogsDir); + arguments = string.Concat(arguments, GetDiagArg(diagLogsDir)); + _attachments.Add(diagLogsDir); + Console.WriteLine($"Diagnostic logs directory: {diagLogsDir}"); + } + var debugEnvironmentVariables = AddDebugEnvironmentVariables(environmentVariables); ExecuteVsTestConsole(arguments, out _standardTestOutput, out _standardTestError, out _runnerExitCode, debugEnvironmentVariables); FormatStandardOutCome(); @@ -223,7 +233,8 @@ public void InvokeVsTest(string? arguments, Dictionary? environ /// Arguments provided to vstest.console.exe /// Environment variables to set to the started process. /// - public void InvokeDotnetTest(string arguments, Dictionary? environmentVariables = null, string? workingDirectory = null) + /// When true, automatically adds --diag flag and attaches logs to test results on failure. + public void InvokeDotnetTest(string arguments, Dictionary? environmentVariables = null, string? workingDirectory = null, bool collectDiagnostics = true) { string globalJsonPath = Path.Combine(workingDirectory!, "global.json"); if (workingDirectory is not null && !File.Exists(globalJsonPath)) @@ -272,6 +283,28 @@ public void InvokeDotnetTest(string arguments, Dictionary? envi // https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/commands/dotnet-test/VSTestForwardingApp.cs#L30-L39 debugEnvironmentVariables["VSTEST_CONSOLE_PATH"] = vstestConsolePath; + if (collectDiagnostics && !arguments.Contains("--diag")) + { + var diagLogsDir = Path.Combine(TempDirectory.Path, "diag"); + Directory.CreateDirectory(diagLogsDir); + var diagPath = Path.Combine(diagLogsDir, "log.txt"); + var diagArg = " --diag " + diagPath.AddDoubleQuote(); + + // Insert --diag before the -- separator so dotnet test forwards it to vstest.console. + var separatorPos = arguments.IndexOf(" -- "); + if (separatorPos == -1) + { + arguments += diagArg; + } + else + { + arguments = arguments.Insert(separatorPos, diagArg); + } + + _attachments.Add(diagLogsDir); + Console.WriteLine($"Diagnostic logs directory: {diagLogsDir}"); + } + IntegrationTestBase.ExecutePatchedDotnet("test", arguments, out _standardTestOutput, out _standardTestError, out _runnerExitCode, debugEnvironmentVariables, workingDirectory); FormatStandardOutCome(); } @@ -284,14 +317,16 @@ public void InvokeDotnetTest(string arguments, Dictionary? envi /// Dotnet Framework of test assembly. /// Run settings for execution. /// Environment variables to set to the started process. + /// When true, automatically adds --diag flag and attaches logs to test results on failure. public void InvokeVsTestForExecution(string testAssembly, string? testAdapterPath, string framework, string? runSettings = "", - Dictionary? environmentVariables = null) + Dictionary? environmentVariables = null, + bool collectDiagnostics = true) { var arguments = PrepareArguments(testAssembly, testAdapterPath, runSettings, framework, _testEnvironment.InIsolationValue, resultsDirectory: TempDirectory.Path); - InvokeVsTest(arguments, environmentVariables); + InvokeVsTest(arguments, environmentVariables, collectDiagnostics); } private Dictionary AddDebugEnvironmentVariables(Dictionary? environmentVariables) From f1d56d71ace105b2e700c8af6a8b1ac89bbfc944 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 24 Mar 2026 16:14:41 +0100 Subject: [PATCH 2/2] Address review feedback: rename diag dir, add IsDiagAlreadyEnabled helper - Rename 'diag' folder to 'logs' in both InvokeVsTest and InvokeDotnetTest - Extract IsDiagAlreadyEnabled helper to check --diag, /diag, -diag args and VSTEST_DIAG environment variable - Use helper in both methods instead of inline string checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../IntegrationTestBase.cs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs index 9f61b40d37..6964e5c01f 100644 --- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs +++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs @@ -213,9 +213,9 @@ public static string PrepareArguments(string testAssembly, string? testAdapterPa /// When true, automatically adds --diag flag and attaches logs to test results on failure. public void InvokeVsTest(string? arguments, Dictionary? environmentVariables = null, bool collectDiagnostics = true) { - if (collectDiagnostics && arguments?.Contains("--diag") != true) + if (collectDiagnostics && !IsDiagAlreadyEnabled(arguments ?? "")) { - var diagLogsDir = Path.Combine(TempDirectory.Path, "diag"); + var diagLogsDir = Path.Combine(TempDirectory.Path, "logs"); Directory.CreateDirectory(diagLogsDir); arguments = string.Concat(arguments, GetDiagArg(diagLogsDir)); _attachments.Add(diagLogsDir); @@ -283,9 +283,9 @@ public void InvokeDotnetTest(string arguments, Dictionary? envi // https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/commands/dotnet-test/VSTestForwardingApp.cs#L30-L39 debugEnvironmentVariables["VSTEST_CONSOLE_PATH"] = vstestConsolePath; - if (collectDiagnostics && !arguments.Contains("--diag")) + if (collectDiagnostics && !IsDiagAlreadyEnabled(arguments)) { - var diagLogsDir = Path.Combine(TempDirectory.Path, "diag"); + var diagLogsDir = Path.Combine(TempDirectory.Path, "logs"); Directory.CreateDirectory(diagLogsDir); var diagPath = Path.Combine(diagLogsDir, "log.txt"); var diagArg = " --diag " + diagPath.AddDoubleQuote(); @@ -1072,6 +1072,21 @@ protected string BuildMultipleAssemblyPath(params string[] assetNames) return string.Join(" ", GetTestDlls(assetNames).Select(a => a.AddDoubleQuote())); } + private static bool IsDiagAlreadyEnabled(string arguments) + { + // Check args for --diag, /diag, -diag (case-insensitive) + if (arguments.Contains("--diag", StringComparison.OrdinalIgnoreCase) + || arguments.Contains("/diag", StringComparison.OrdinalIgnoreCase) + || arguments.Contains("-diag", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Check environment variable + var envDiag = Environment.GetEnvironmentVariable("VSTEST_DIAG"); + return !StringUtils.IsNullOrEmpty(envDiag); + } + protected static string GetDiagArg(string rootDir) => " --diag:" + Path.Combine(rootDir, "log.txt");