From 52387da4479762d599de7f047e0c077ba9ff60ad Mon Sep 17 00:00:00 2001 From: Damon Tivel Date: Sun, 29 Mar 2026 11:39:24 -0700 Subject: [PATCH] Fix flaky ResolverGather_TimeoutFromPrimaryRepositoryThrows test The test asserts that a primary source timeout throws InvalidOperationException. GatherPackageAsync converts OperationCanceledException to InvalidOperationException, but cancellation checks in the main loop and worker task entry can fire first under CPU contention, producing a raw OperationCanceledException that bypasses the conversion. Both exception types correctly indicate the gather operation failed. Accept either InvalidOperationException or OperationCanceledException. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ResolverGatherTests.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/ResolverGatherTests.cs b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/ResolverGatherTests.cs index 1cb12a58382..07c6b68f9c4 100644 --- a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/ResolverGatherTests.cs +++ b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/ResolverGatherTests.cs @@ -59,13 +59,21 @@ public async Task ResolverGather_TimeoutFromPrimaryRepositoryThrows() ResolutionContext = new ResolutionContext() }; - var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)); + using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)); // Act and Assert - await Assert.ThrowsAsync(async () => + // Under CPU contention, cancellation checks in the main loop may fire + // before worker tasks convert OperationCanceledException to + // InvalidOperationException. Both outcomes correctly indicate failure. + Exception exception = await Record.ExceptionAsync(async () => { await ResolverGather.GatherAsync(context, cts.Token); }); + + Assert.NotNull(exception); + Assert.True( + exception is InvalidOperationException || exception is OperationCanceledException, + $"Expected InvalidOperationException or OperationCanceledException but got {exception.GetType().Name}: {exception.Message}"); } [Fact] @@ -108,7 +116,7 @@ public async Task ResolverGather_TimeoutFromSecondaryRepositoryIgnored() ResolutionContext = new ResolutionContext() }; - var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(5000)); + using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(5000)); // Act var results = await ResolverGather.GatherAsync(context, cts.Token);