Skip to content

Add crash report support to the CrashDump extension#8191

Open
Copilot wants to merge 8 commits into
mainfrom
copilot/feature-generate-crash-report
Open

Add crash report support to the CrashDump extension#8191
Copilot wants to merge 8 commits into
mainfrom
copilot/feature-generate-crash-report

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 13, 2026

New Feature

What does this feature do?

The CrashDump extension can now ask the .NET runtime to generate JSON crash reports in addition to, or instead of, a dump. This makes crash triage lighter-weight in CI, especially for environments where full dump collection is expensive or impractical.

Why is this feature needed?

DOTNET_EnableCrashReport and DOTNET_EnableCrashReportOnly are already available in the runtime, but the MTP CrashDump extension only exposed dump generation. Surfacing crash reports gives a cheaper diagnostic path and improves crash investigation on machines where developers cannot inspect native dumps directly.

Implementation details

  • CLI surface

    • Added --crashreport to generate a crash report alongside --crashdump
    • Added --crashreport-only to request only the JSON crash report
    • Added validation for invalid combinations:
      • --crashreport requires --crashdump
      • --crashreport-only cannot be combined with other crash options
  • Runtime configuration

    • Wired the new options to the runtime environment variables:
      • DOTNET_EnableCrashReport
      • DOTNET_EnableCrashReportOnly
    • Kept DbgEnableMiniDump enabled for --crashreport-only, since the runtime still requires createdump activation to emit the report
  • Artifacts and user-visible behavior

    • Added crash report artifact discovery/publishing for *.crashreport.json
    • Updated crash messages to distinguish:
      • dump only
      • report only
      • dump + report
    • Updated help text and package docs to describe the new options
  • Coverage

    • Extended unit coverage for command-line validation
    • Added acceptance coverage for:
      • dump + crash report
      • crash report only
      • invalid --crashreport usage
    • Updated help/info expectations for the new CLI options

Example

# Generate a dump and a JSON crash report
dotnet test -- --crashdump --crashreport

# Generate only a JSON crash report
dotnet test -- --crashreport-only

Copilot AI self-assigned this May 13, 2026
Copilot AI review requested due to automatic review settings May 13, 2026 17:02
Copilot AI review requested due to automatic review settings May 13, 2026 17:02
Copilot AI linked an issue May 13, 2026 that may be closed by this pull request
Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 13, 2026 17:23
Copilot AI changed the title [WIP] Add feature to generate crash report for .NET 6.0 and 7.0 Add crash report support to the CrashDump extension May 13, 2026
Copilot AI requested a review from Evangelink May 13, 2026 17:24
@Evangelink Evangelink marked this pull request as ready for review May 14, 2026 14:59
Copilot AI review requested due to automatic review settings May 14, 2026 14:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the CrashDump MTP extension with new --crashreport and --crashreport-only options that wire the test host runtime variables DOTNET_EnableCrashReport / DOTNET_EnableCrashReportOnly and publish the resulting *.crashreport.json as artifacts.

Changes:

  • New CLI options with mutual-exclusion validation (--crashreport requires --crashdump; --crashreport-only excludes the others).
  • Environment variable provider sets the new runtime variables (and keeps DbgEnableMiniDump for --crashreport-only); lifetime handler emits new "dump only / report only / dump + report" messages and publishes crash report artifacts.
  • New resx/xlf entries, PACKAGE.md doc update, unit/acceptance/help-info test coverage for the new options.
Show a summary per file
File Description
src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineOptions.cs Adds option name constants for the two new flags.
src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpCommandLineProvider.cs Registers new options and adds combined-options validation via chained ternary.
src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpEnvironmentVariableProvider.cs Sets/validates DOTNET_EnableCrashReport(Only) and conditionalizes DbgEnableMiniDump.
src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs Picks crash message variant; publishes .crashreport.json artifacts in addition to dumps.
src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/CrashDumpResources.resx New resource strings for descriptions, errors, and crash messages.
src/Platform/Microsoft.Testing.Extensions.CrashDump/Resources/xlf/*.xlf Auto-added state="new" entries mirroring the resx additions across all locales.
src/Platform/Microsoft.Testing.Extensions.CrashDump/PACKAGE.md Documents new crash report capabilities.
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/CrashDumpTests.cs Adds unit tests for valid/invalid combinations of the new flags.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/CrashDumpTests.cs Acceptance tests for dump+report, report-only, and --crashreport without --crashdump.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs Updates expected help/info output to include the new options.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 3

Comment on lines +50 to +57
=> commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOptionName) &&
!commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)
? ValidationResult.InvalidTask(CrashDumpResources.CrashReportRequiresCrashDumpErrorMessage)
: commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOnlyOptionName) &&
(commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName) ||
commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOptionName))
? ValidationResult.InvalidTask(CrashDumpResources.CrashReportOnlyCannotBeCombinedErrorMessage)
: ValidationResult.ValidTask;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e8b4818. Refactored into explicit if-statements (one per invalid combination) so future mutually-exclusive crash options are easy to add.

Comment on lines +85 to +99
if (crashReportEnabled)
{
foreach (string prefix in Prefixes)
{
environmentVariables.SetVariable(new($"{prefix}{EnableCrashReportVariable}", EnableMiniDumpValue, false, true));
}
}

if (crashReportOnlyEnabled)
{
foreach (string prefix in Prefixes)
{
environmentVariables.SetVariable(new($"{prefix}{EnableCrashReportOnlyVariable}", EnableMiniDumpValue, false, true));
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e8b4818. Renamed EnableMiniDumpValue to the neutral EnabledValue since it's now also used for DOTNET_EnableCrashReport and DOTNET_EnableCrashReportOnly.

Amaury Levé and others added 2 commits May 14, 2026 20:19
…shDump tests/code

- Reorder --crashreport / --crashreport-only after --crashdump-type in the
  Help and Info expectations to match the platform's alphabetical ordering
  (CommandLineHandler.PrintOptionsAsync OrderBy(option.Name)).
- Refactor CrashDump option validation into explicit if-statements for clarity.
- Rename EnableMiniDumpValue -> EnabledValue (now reused for crash report vars).
- Make CrashReportOnly_CustomDumpName_CreateOnlyCrashReport robust on Windows by
  doing an exact filename comparison instead of relying on Directory.GetFiles
  pattern matching, which can match 'customdumpname.dmp.crashreport.json'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Revert the validation refactor, EnabledValue rename, and the Windows-safe
filename check in CrashReportOnly_CustomDumpName_CreateOnlyCrashReport.
The HelpInfoAllExtensionsTests ordering fix is preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 14, 2026 18:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Extensions.CrashDump/CrashDumpProcessLifetimeHandler.cs:1

  • Mirror of the existing dump-fallback path: if Path.GetDirectoryName(expectedCrashReportFile) returns an empty string (when the dump file pattern is just a filename with no directory component), Directory.GetFiles("", ...) will throw ArgumentException. The pre-existing dump branch has the same issue, but consider falling back to the current directory or skipping the scan when the directory is empty so the new code path doesn't introduce another instance of the same brittleness.
// Copyright (c) Microsoft Corporation. All rights reserved.
  • Files reviewed: 22/22 changed files
  • Comments generated: 8

Comment on lines +50 to +57
=> commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOptionName) &&
!commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)
? ValidationResult.InvalidTask(CrashDumpResources.CrashReportRequiresCrashDumpErrorMessage)
: commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOnlyOptionName) &&
(commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName) ||
commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOptionName))
? ValidationResult.InvalidTask(CrashDumpResources.CrashReportOnlyCannotBeCombinedErrorMessage)
: ValidationResult.ValidTask;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 64d9b6f (and the prior d68feac). Beyond the requested refactor: the entire validation method is now a no-op because the CLI surface was simplified to a single --crash-report flag (see #8191 (comment) / the rename discussion in PR comments). The two mutually-exclusive rules and their error messages no longer exist.

<value>[net6.0+ only] Generate a crash report file if the test process crashes. Requires '--crashdump'.</value>
</data>
<data name="CrashReportRequiresCrashDumpErrorMessage" xml:space="preserve">
<value>You specified '--crashreport' but did not enable crash dumps, add --crashdump to the command line</value>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CrashReportRequiresCrashDumpErrorMessage resource was already updated to quote both option names in d68feac, and as of 64d9b6f the resource was removed altogether (the validation it backed no longer exists since the CLI surface was simplified to a single --crash-report flag).

Comment on lines +71 to +77
if (crashDumpEnabled || crashReportOnlyEnabled)
{
foreach (string prefix in Prefixes)
{
environmentVariables.SetVariable(new($"{prefix}{EnableMiniDumpVariable}", EnableMiniDumpValue, false, true));
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Addressed in d68feac (the condition now includes crashReportEnabled so MiniDump is enabled whenever any crash option is set, regardless of validator order). 64d9b6f keeps the same self-consistent wiring for the simplified single-flag design.

{
await _outputDisplay.DisplayAsync(this, new ErrorMessageOutputDeviceData(string.Format(CultureInfo.InvariantCulture, CrashDumpResources.CannotFindExpectedCrashDumpFile, expectedDumpFile)), cancellationToken).ConfigureAwait(false);
foreach (string dumpFile in Directory.GetFiles(Path.GetDirectoryName(expectedDumpFile)!, "*.dmp"))
string expectedCrashReportFile = $"{expectedDumpFile}.crashreport.json";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d68feac. Extracted private const string CrashReportFileExtension = .crashreport.json; and private const string CrashReportFileSearchPattern = * + CrashReportFileExtension; so the suffix is defined in one place. The resource string is parameterized with {1} to receive the search pattern.

}

[TestMethod]
public async Task CrashReportOnly_CustomDumpName_CreateOnlyCrashReport()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d68feac. Renamed to CrashReportOnly_WithCustomDumpFilename_CreatesOnlyCrashReport (and to CrashReport_WithCustomDumpFilename_CreatesOnlyCrashReport in 64d9b6f after --crashreport-only was removed) so the intent is explicit.

Comment on lines +200 to +207
if (_commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashReportOptionName))
{
foreach (string prefix in Prefixes)
{
if (!environmentVariables.TryGetVariable($"{prefix}{EnableCrashReportVariable}", out OwnedEnvironmentVariable? enableCrashReport)
|| enableCrashReport.Value != EnableMiniDumpValue)
{
AddError(errors, $"{prefix}{EnableCrashReportVariable}", EnableMiniDumpValue, enableCrashReport?.Value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d68feac. Extracted a ValidateBothPrefixes(string variableName, string expectedValue) local function and replaced all three duplicated blocks with calls to it.

Comment on lines +79 to +85
[TestMethod]
public async Task CrashReportOnly_Cannot_Be_Combined_With_Other_Crash_Options()
{
var provider = new CrashDumpCommandLineProvider();
var options = new Dictionary<string, string[]>
{
{ CrashDumpCommandLineOptions.CrashDumpOptionName, [] },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d68feac. The CrashReportOnly_Cannot_Be_Combined_With_Other_Crash_Options test became data-driven with [DataRow(CrashDumpCommandLineOptions.CrashDumpOptionName)] and [DataRow(CrashDumpCommandLineOptions.CrashReportOptionName)] so both invalid combinations are covered. The test was subsequently removed in 64d9b6f because --crashreport-only was eliminated as part of the CLI simplification.

Comment on lines +85 to +91
if (crashReportEnabled)
{
foreach (string prefix in Prefixes)
{
environmentVariables.SetVariable(new($"{prefix}{EnableCrashReportVariable}", EnableMiniDumpValue, false, true));
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d68feac. Renamed EnableMiniDumpValue to the neutral EnabledValue since it's reused by all three runtime variables.

- CrashDumpCommandLineProvider: replace chained ternary with explicit
  if-statements for clarity and easier extension.
- CrashDumpEnvironmentVariableProvider: rename EnableMiniDumpValue to
  EnabledValue since it's now reused for the crash report environment
  variables (DOTNET_EnableCrashReport / DOTNET_EnableCrashReportOnly).
- CrashReportOnly_CustomDumpName_CreateOnlyCrashReport: do an explicit
  filename comparison instead of relying on Directory.GetFiles' pattern
  matching, which on Windows can also match
  'customdumpname.dmp.crashreport.json' for the literal pattern
  'customdumpname.dmp'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member

@copilot address review comments

Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 14, 2026 19:01
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot address review comments

Addressed in d68feac. I covered the remaining CrashDump review feedback: validation precedence/coverage, resource quoting and XLF sync, crash report minidump wiring, crash report suffix constants, environment validation deduplication, and the acceptance test rename.

Replaces the two-flag design (--crashreport + --crashreport-only) with a single composable flag --crash-report. Behavior:

- '--crashdump' alone: dump only (unchanged)

- '--crash-report' alone: report only (DOTNET_EnableCrashReportOnly=1)

- '--crashdump --crash-report': both (DOTNET_EnableCrashReport=1)

Removes obsolete validation rules and resource strings (CrashReportRequiresCrashDumpErrorMessage, CrashReportOnlyCannotBeCombinedErrorMessage, CrashReportOnlyOptionDescription) and the corresponding XLF entries. Updates PACKAGE.md, unit tests, acceptance tests and HelpInfoAllExtensionsTests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 15, 2026 14:16
@Evangelink
Copy link
Copy Markdown
Member

CLI option rename and simplification (commit 64d9b6f)

After discussing the CLI surface, I simplified the design from two flags (--crashreport + --crashreport-only) to a single composable flag --crash-report:

Command Result Internal
--crashdump dump only DbgEnableMiniDump=1
--crash-report report only DbgEnableMiniDump=1 + DOTNET_EnableCrashReportOnly=1
--crashdump --crash-report dump + report DbgEnableMiniDump=1 + DOTNET_EnableCrashReport=1

Why:

  • One flag = one artifact type (cleaner mental model).
  • No need for an awkward -only suffix flag.
  • Removes the "--crashreport requires --crashdump" validation rule — that coupling was a wart.
  • Removes the "--crashreport-only cannot be combined with..." validation rule.
  • --crash-report (kebab-case) follows the broader MTP CLI convention (--results-directory, --diagnostic-output-fileprefix, etc.) — --crashdump itself is the legacy outlier.

This also lets us drop two error-message resources (and their XLF entries) and the option-mutual-exclusion test cases.

All 8 review comments from the second review are addressed individually above.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 3

Comment on lines +69 to +74
if (crashDumpEnabled || crashReportEnabled)
{
foreach (string prefix in Prefixes)
{
environmentVariables.SetVariable(new($"{prefix}{EnableMiniDumpVariable}", EnabledValue, false, true));
}
internal static class CrashDumpCommandLineOptions
{
public const string CrashDumpOptionName = "crashdump";
public const string CrashReportOptionName = "crash-report";
Comment on lines +150 to +167
<data name="CrashReportArtifactDescription" xml:space="preserve">
<value>The testhost process crash report file</value>
</data>
<data name="CrashReportArtifactDisplayName" xml:space="preserve">
<value>Crash report file</value>
</data>
<data name="CrashReportOptionDescription" xml:space="preserve">
<value>Generate a JSON crash report when the test process crashes. Combine with '--crashdump' to also generate a dump file. Requires .NET 7+ when used alone; .NET 6+ when combined with '--crashdump'.</value>
</data>
<data name="CrashDumpProcessCrashedDumpAndReportFileCreated" xml:space="preserve">
<value>Test host process with PID '{0}' crashed, a dump file and crash report were generated</value>
</data>
<data name="CrashDumpProcessCrashedDumpFileCreated" xml:space="preserve">
<value>Test host process with PID '{0}' crashed, a dump file was generated</value>
</data>
<data name="CrashDumpProcessCrashedReportFileCreated" xml:space="preserve">
<value>Test host process with PID '{0}' crashed, a crash report was generated</value>
</data>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Generate crash report

3 participants