Skip to content

Disposable data-source roots leak when object-graph tracking throws in a nested getter #7213

Closed

Description

@thomhurst

What happens

When object-graph tracking for a test throws, the test's data-source objects are never disposed, including disposable root arguments that were created successfully.

ObjectTracker.TrackObjects (src/TUnit.Core/Tracking/ObjectTracker.cs) asks ObjectGraphDiscoverer.DiscoverAndTrackObjects for the test's object graph and only counts references after discovery finishes. If a nested property getter throws during discovery (for example an IAsyncInitializer-typed or injectable property on a class-data object), no reference is counted. Since PR #7191, the objects that discovery had already added to TestContext.TrackedObjects are also removed, so completing the test does not release references it never took.

As a result the root argument objects are neither counted nor tracked. Neither UntrackObjects at test completion nor the session-end sweep (DisposeAndClearStaticTrackingAsync) disposes them.

This affects both registration paths:

Repro

public sealed class Root : IDisposable
{
    public static bool Disposed;
    public Nested Child => throw new InvalidOperationException("getter");
    public void Dispose() => Disposed = true;
}
public sealed class Nested : IAsyncInitializer { public Task InitializeAsync() => Task.CompletedTask; }

[ClassDataSource<Root>(Shared = SharedType.None)]
public class T(Root root) { [Test] public void A() { } }

From reading the code (not yet run): A fails during registration, and Root.Disposed stays false at session end, in both modes. Adding [Skip] to A should give the same result.

Expected

Roots that discovery has already produced are counted before nested traversal starts, or are kept when discovery fails, so they are disposed when the test completes. Rollback should remove only what nested discovery added. Shared objects must keep correct reference counts.

Found while reviewing CodeRabbit feedback on PR #7191 (src/TUnit.Engine/Services/TestFilterService.cs around line 126).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium: edge case, mode divergence, flaky test, or workaround existsbugSomething isn't workingin-progressWork is in progress

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions