| File: Helpers\CaptureWorkspaceOnFailureAttribute.cs | Web Access |
| Project: src\tests\Aspire.Cli.EndToEnd.Tests\Aspire.Cli.EndToEnd.Tests.csproj (Aspire.Cli.EndToEnd.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Reflection; using Xunit; using Xunit.v3; namespace Aspire.Cli.EndToEnd.Tests.Helpers; /// <summary> /// When applied to a test method, captures directories to /// <c>testresults/workspaces/{testName}/</c> on test failure so the generated /// files are uploaded as CI artifacts for debugging. /// <para> /// Register paths to capture via <c>TestContext.Current.KeyValueStorage</c>: /// <list type="bullet"> /// <item><c>"WorkspacePath"</c> — the primary workspace directory</item> /// <item><c>"CapturePath:{label}"</c> — additional directories to capture under the given label</item> /// <item><c>"CaptureFile:{fileName}"</c> — additional files to capture under the given destination name</item> /// </list> /// Workspace capture is automatic when using <see cref="TemporaryWorkspace.Create"/>. /// </para> /// </summary> [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] internal sealed class CaptureWorkspaceOnFailureAttribute : BeforeAfterTestAttribute { public override void Before(MethodInfo methodUnderTest, IXunitTest test) { _ = methodUnderTest; _ = test; TestContext.Current?.KeyValueStorage["PreserveWorkspaceOnFailure"] = true; } public override void After(MethodInfo methodUnderTest, IXunitTest test) { if (TestContext.Current.TestState?.Result is not TestResult.Failed) { if (!CliE2ETestHelpers.IsRunningInCI && TestContext.Current.KeyValueStorage.TryGetValue("WorkspacePath", out var workspaceValue) && workspaceValue is string preservedWorkspacePath) { TemporaryWorkspace.ReleasePreservation(preservedWorkspacePath); } return; } var testName = $"{test.TestCase.TestClassName}.{methodUnderTest.Name}"; try { if (!CliE2ETestHelpers.IsRunningInCI) { if (TestContext.Current.KeyValueStorage.TryGetValue("WorkspacePath", out var workspaceValue) && workspaceValue is string localWorkspacePath) { Console.WriteLine($"Failed test workspace preserved at: {localWorkspacePath}"); TemporaryWorkspace.ReleasePreservation(localWorkspacePath, deleteDirectory: false); } foreach (var kvp in TestContext.Current.KeyValueStorage) { if (kvp.Key.StartsWith("CapturePath:", StringComparison.Ordinal) && kvp.Value is string path && Directory.Exists(path)) { var label = kvp.Key["CapturePath:".Length..]; Console.WriteLine($"Failed test diagnostics '{label}' available at: {path}"); } if (kvp.Key.StartsWith("CaptureFile:", StringComparison.Ordinal) && kvp.Value is string filePath && File.Exists(filePath)) { var fileName = kvp.Key["CaptureFile:".Length..]; Console.WriteLine($"Failed test file '{fileName}' available at: {filePath}"); } } return; } // Capture primary workspace if (TestContext.Current.KeyValueStorage.TryGetValue("WorkspacePath", out var value) && value is string workspacePath && Directory.Exists(workspacePath)) { var capturePath = CliE2ETestHelpers.CaptureDirectory(workspacePath, testName, label: null); Console.WriteLine($"Captured failed test workspace to: {capturePath}"); } // Capture additional registered paths (e.g., "CapturePath:aspire-home" → ~/.aspire) foreach (var kvp in TestContext.Current.KeyValueStorage) { if (kvp.Key.StartsWith("CapturePath:", StringComparison.Ordinal) && kvp.Value is string path && Directory.Exists(path)) { var label = kvp.Key["CapturePath:".Length..]; var capturePath = CliE2ETestHelpers.CaptureDirectory(path, testName, label); Console.WriteLine($"Captured failed test diagnostics '{label}' to: {capturePath}"); } if (kvp.Key.StartsWith("CaptureFile:", StringComparison.Ordinal) && kvp.Value is string filePath && File.Exists(filePath)) { var fileName = kvp.Key["CaptureFile:".Length..]; var capturePath = CliE2ETestHelpers.CaptureFile(filePath, testName, fileName); Console.WriteLine($"Captured failed test file '{fileName}' to: {capturePath}"); } } } catch { // Don't fail the test because of capture issues. } } }