test(sessions): switch SessionWorkerClientFactoryFakeWorkerTests to IAsyncLifetime so its teardown actually runs
xUnit v2 (2.9.3) never invokes IAsyncDisposable.DisposeAsync on a test class, so the unobserved-fault safety net this class documents — awaiting every scripted worker task after each test — has been dead code since it was written. Found via dumpasync on the wedged-testhost investigation: the NeverReadyWorkerProcessLauncher's Task.Delay(Infinite, _stop.Token) was still pending (DelayPromiseWithCancellation, detached) minutes after its test finished, which is only possible if DisposeAsync never ran. Proven both ways with a throw-probe in DisposeAsync: under IAsyncDisposable all 3 tests pass (never called); under IAsyncLifetime all 3 fail from the probe (called after every test). Sweep confirmed this is the only test class on IAsyncDisposable — all other implementers are helpers disposed via await using.
This commit is contained in:
+9
-2
@@ -11,7 +11,7 @@ using ZB.MOM.WW.MxGateway.Tests.TestSupport;
|
|||||||
|
|
||||||
namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Sessions;
|
namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Sessions;
|
||||||
|
|
||||||
public sealed class SessionWorkerClientFactoryFakeWorkerTests : IAsyncDisposable
|
public sealed class SessionWorkerClientFactoryFakeWorkerTests : IAsyncLifetime
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(5);
|
private static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
@@ -24,12 +24,19 @@ public sealed class SessionWorkerClientFactoryFakeWorkerTests : IAsyncDisposable
|
|||||||
|
|
||||||
private readonly List<IWorkerTaskLauncher> _launchers = [];
|
private readonly List<IWorkerTaskLauncher> _launchers = [];
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task InitializeAsync() => Task.CompletedTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Awaits every scripted worker task so an unhandled exception fails the owning test
|
/// Awaits every scripted worker task so an unhandled exception fails the owning test
|
||||||
/// instead of surfacing later as an unobserved <see cref="TaskScheduler.UnobservedTaskException"/>.
|
/// instead of surfacing later as an unobserved <see cref="TaskScheduler.UnobservedTaskException"/>.
|
||||||
|
/// This must stay on <see cref="IAsyncLifetime"/>: xUnit v2 never invokes
|
||||||
|
/// <see cref="IAsyncDisposable.DisposeAsync"/> on a test class, so under the previous
|
||||||
|
/// declaration this teardown silently never ran (the NeverReady launcher's parked infinite
|
||||||
|
/// delay was still pending in a post-run process dump).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||||
public async ValueTask DisposeAsync()
|
public async Task DisposeAsync()
|
||||||
{
|
{
|
||||||
foreach (IWorkerTaskLauncher launcher in _launchers)
|
foreach (IWorkerTaskLauncher launcher in _launchers)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user