Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specifying a TRX report filename that already exists causes the Microsoft Testing Platform to hang and crash #4561

Open
AdamMaras opened this issue Jan 8, 2025 · 0 comments

Comments

@AdamMaras
Copy link

Describe the bug

When running a unit test suite using the Microsoft Testing Platform and the TRX report extension, if one uses the --report-trx-filename command-line option to specify a filename that already exists, the test suite hangs for 30 seconds (doing a tight loop of I/O retries that will not succeed) at the end, and exits unsuccessfully. When specifying a TRX report filename explicitly, the report extension should overwrite the existing file with the contents of the new test report. This occurs with the latest release of the Microsoft.Testing.Extensions.TrxReport package, version 1.5.0.

Steps To Reproduce

First, start by creating a new unit testing project (this example uses xUnit 3) and adding the TRX report extension to the project:

dotnet new install xunit.v3.templates
dotnet new xunit3 -n TrxHangCrash
dotnet add ./TrxHangCrash package Microsoft.Testing.Extensions.TrxReport

Then, modify ./TrxHangCrash/TrxHangCrash.csproj to use the Microsoft Testing Platform:

  <PropertyGroup>
    <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
  </PropertyGroup>

Finally, run the test suite twice, specifying the same report filename twice:

dotnet test ./TrxHangCrash -- --report-trx --report-trx-filename report.trx
dotnet test ./TrxHangCrash -- --report-trx --report-trx-filename report.trx

Expected behavior

The test suite completes, and the report.trx file is overwritten with the contents of the new test report.

Actual behavior

The test suite hangs for 30 seconds at the end of the tests, and then fails with the following stack trace in the test log:

Unhandled exception. System.IO.IOException: The file '/redacted/TrxHangCrash/bin/Debug/net8.0/TestResults/report.trx' already exists.
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at Microsoft.Testing.Platform.Helpers.SystemFileSystem.NewFileStream(String path, FileMode mode) in /_/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs:line 14
   at Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxReportEngine.<>c__DisplayClass27_0.<<GenerateReportAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxReportEngine.RetryWhenIOExceptionAsync(Func`1 func) in /_/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs:line 223
   at Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxReportEngine.GenerateReportAsync(String testHostCrashInfo, Boolean isTestHostCrashed, Boolean keepReportFileStreamOpen) in /_/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs:line 150
   at Microsoft.Testing.Extensions.TrxReport.Abstractions.TrxReportGenerator.OnTestSessionFinishingAsync(SessionUid sessionUid, CancellationToken cancellationToken) in /_/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs:line 242
   at Microsoft.Testing.Platform.Hosts.CommonTestHost.NotifyTestSessionEndAsync(SessionUid sessionUid, BaseMessageBus baseMessageBus, ServiceProvider serviceProvider, CancellationToken cancellationToken) in /_/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs:line 206
   at Microsoft.Testing.Platform.Hosts.CommonTestHost.ExecuteRequestAsync(ProxyOutputDevice outputDevice, ITestSessionContext testSessionInfo, ServiceProvider serviceProvider, BaseMessageBus baseMessageBus, ITestFramework testFramework, ClientInfo client) in /_/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs:line 137
   at Microsoft.Testing.Platform.Hosts.ConsoleTestHost.InternalRunAsync() in /_/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs:line 86
   at Microsoft.Testing.Platform.Hosts.ConsoleTestHost.InternalRunAsync() in /_/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs:line 118
   at Microsoft.Testing.Platform.Hosts.CommonTestHost.RunTestAppAsync(CancellationToken testApplicationCancellationToken) in /_/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs:line 110
   at Microsoft.Testing.Platform.Hosts.CommonTestHost.RunAsync() in /_/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs:line 34
   at Microsoft.Testing.Platform.Hosts.CommonTestHost.RunAsync() in /_/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs:line 71
   at Microsoft.Testing.Platform.Builder.TestApplication.RunAsync() in /_/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs:line 244
   at Xunit.Runner.InProc.SystemConsole.TestingPlatform.TestPlatformTestFramework.RunAsync(String[] args, Action`2 extensionRegistration) in D:\a\xunit\xunit\src\xunit.v3.runner.inproc.console\TestingPlatform\TestPlatformTestFramework.cs:line 270
   at XunitAutoGeneratedEntryPoint.Main(String[] args) in /redacted/.nuget/packages/xunit.v3.core/1.0.0/_content/EntryPoint-xunit.cs:line 9

Additional context

There's some IO retry logic during TRX report generation that seems to account for filename collisions when the time is part of the TRX report filename, but it seems as though the new file stream being opened in TrxReportEngine.GenerateReportAsync could use FileMode.Create instead of FileMode.CreateNew when the report filename is explicitly provided instead of being generated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants