Skip to content

Commit aa1052f

Browse files
CopilotEvangelink
andcommitted
Add acceptance test for multiple crash dumps collection
Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
1 parent c114745 commit aa1052f

File tree

1 file changed

+130
-0
lines changed
  • test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests

1 file changed

+130
-0
lines changed

test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/CrashDumpTests.cs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ public async Task CrashDump_InvalidFormat_ShouldFail()
7272
testHostResult.AssertOutputContains("Option '--crashdump-type' has invalid arguments: 'invalid' is not a valid dump type. Valid options are 'Mini', 'Heap', 'Triage' and 'Full'");
7373
}
7474

75+
[TestMethod]
76+
public async Task CrashDump_WithChildProcess_CollectsMultipleDumps()
77+
{
78+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
79+
{
80+
// TODO: Investigate failures on macos
81+
return;
82+
}
83+
84+
string resultDirectory = Path.Combine(AssetFixture.TargetAssetPath, Guid.NewGuid().ToString("N"));
85+
var testHost = TestInfrastructure.TestHost.LocateFrom(AssetFixture.TargetAssetPath, "CrashDumpWithChild", TargetFrameworks.NetCurrent);
86+
TestHostResult testHostResult = await testHost.ExecuteAsync($"--crashdump --results-directory {resultDirectory}", cancellationToken: TestContext.CancellationToken);
87+
testHostResult.AssertExitCodeIs(ExitCodes.TestHostProcessExitedNonGracefully);
88+
89+
string[] dumpFiles = Directory.GetFiles(resultDirectory, "*.dmp", SearchOption.AllDirectories);
90+
Assert.IsTrue(dumpFiles.Length >= 2, $"Expected at least 2 dump files (parent and child), but found {dumpFiles.Length}. Dumps: {string.Join(", ", dumpFiles.Select(Path.GetFileName))}\n{testHostResult}");
91+
}
92+
7593
public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.NuGetGlobalPackagesFolder)
7694
{
7795
private const string AssetName = "CrashDumpFixture";
@@ -82,6 +100,11 @@ public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.
82100
Sources
83101
.PatchTargetFrameworks(TargetFrameworks.All)
84102
.PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion));
103+
104+
yield return ("CrashDumpWithChildFixture", "CrashDumpWithChildFixture",
105+
SourcesWithChild
106+
.PatchTargetFrameworks(TargetFrameworks.All)
107+
.PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion));
85108
}
86109

87110
public string TargetAssetPath => GetAssetPath(AssetName);
@@ -152,6 +175,113 @@ public Task ExecuteRequestAsync(ExecuteRequestContext context)
152175
return Task.CompletedTask;
153176
}
154177
}
178+
""";
179+
180+
private const string SourcesWithChild = """
181+
#file CrashDumpWithChild.csproj
182+
<Project Sdk="Microsoft.NET.Sdk">
183+
<PropertyGroup>
184+
<TargetFrameworks>$TargetFrameworks$</TargetFrameworks>
185+
<OutputType>Exe</OutputType>
186+
<UseAppHost>true</UseAppHost>
187+
<Nullable>enable</Nullable>
188+
<LangVersion>preview</LangVersion>
189+
</PropertyGroup>
190+
<ItemGroup>
191+
<PackageReference Include="Microsoft.Testing.Extensions.CrashDump" Version="$MicrosoftTestingPlatformVersion$" />
192+
</ItemGroup>
193+
</Project>
194+
195+
#file Program.cs
196+
using System;
197+
using System.Diagnostics;
198+
using System.IO;
199+
using System.Linq;
200+
using System.Threading;
201+
using System.Threading.Tasks;
202+
using System.Globalization;
203+
using Microsoft.Testing.Platform;
204+
using Microsoft.Testing.Platform.Extensions.TestFramework;
205+
using Microsoft.Testing.Platform.Builder;
206+
using Microsoft.Testing.Platform.Capabilities.TestFramework;
207+
using Microsoft.Testing.Extensions;
208+
using Microsoft.Testing.Platform.Messages;
209+
using Microsoft.Testing.Platform.Requests;
210+
using Microsoft.Testing.Platform.Services;
211+
212+
public class Startup
213+
{
214+
public static async Task<int> Main(string[] args)
215+
{
216+
Process self = Process.GetCurrentProcess();
217+
string path = self.MainModule!.FileName!;
218+
219+
// Handle child process execution
220+
if (args.Length > 0 && args[0] == "--child")
221+
{
222+
// Child process crashes immediately
223+
Environment.FailFast("Child process crash");
224+
return 1;
225+
}
226+
227+
// Start a child process that will also crash (only when running as testhost controller)
228+
if (args.Any(a => a == "--internal-testhostcontroller-pid"))
229+
{
230+
try
231+
{
232+
var childProcess = Process.Start(new ProcessStartInfo(path, "--child")
233+
{
234+
UseShellExecute = false,
235+
RedirectStandardOutput = true,
236+
RedirectStandardError = true,
237+
});
238+
239+
if (childProcess != null)
240+
{
241+
// Give child process time to start and crash
242+
Thread.Sleep(500);
243+
}
244+
}
245+
catch
246+
{
247+
// Ignore any errors starting child process
248+
}
249+
}
250+
251+
ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args);
252+
builder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_,__) => new DummyTestFramework());
253+
builder.AddCrashDumpProvider();
254+
using ITestApplication app = await builder.BuildAsync();
255+
return await app.RunAsync();
256+
}
257+
}
258+
259+
public class DummyTestFramework : ITestFramework
260+
{
261+
public string Uid => nameof(DummyTestFramework);
262+
263+
public string Version => "2.0.0";
264+
265+
public string DisplayName => nameof(DummyTestFramework);
266+
267+
public string Description => nameof(DummyTestFramework);
268+
269+
public Task<bool> IsEnabledAsync() => Task.FromResult(true);
270+
271+
public Task<CreateTestSessionResult> CreateTestSessionAsync(CreateTestSessionContext context)
272+
=> Task.FromResult(new CreateTestSessionResult() { IsSuccess = true });
273+
274+
public Task<CloseTestSessionResult> CloseTestSessionAsync(CloseTestSessionContext context)
275+
=> Task.FromResult(new CloseTestSessionResult() { IsSuccess = true });
276+
277+
public Task ExecuteRequestAsync(ExecuteRequestContext context)
278+
{
279+
// Parent process crashes
280+
Environment.FailFast("Parent process crash");
281+
context.Complete();
282+
return Task.CompletedTask;
283+
}
284+
}
155285
""";
156286
}
157287

0 commit comments

Comments
 (0)