From 4a4d3f353b9d53c1f724dc533a06504813effa71 Mon Sep 17 00:00:00 2001 From: Flaminel Date: Fri, 23 Oct 2026 15:44:27 +0300 Subject: [PATCH] fixed flaky deferred outcome monitor test --- .../Jobs/SeekerCommandMonitorTests.cs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/code/backend/Cleanuparr.Infrastructure.Tests/Features/Jobs/SeekerCommandMonitorTests.cs b/code/backend/Cleanuparr.Infrastructure.Tests/Features/Jobs/SeekerCommandMonitorTests.cs index 87451199..6a699411 100644 --- a/code/backend/Cleanuparr.Infrastructure.Tests/Features/Jobs/SeekerCommandMonitorTests.cs +++ b/code/backend/Cleanuparr.Infrastructure.Tests/Features/Jobs/SeekerCommandMonitorTests.cs @@ -446,7 +446,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable _arrClient.GetQueueItemsAsync(Arg.Any(), Arg.Any()) .Returns(new QueueListResponse()); - Task publishTask = CaptureNextPublishedStatus(); + Task publishTask = CaptureNextPublishedStatus(out Task savedAfterPublish); // Act await _sut.StartAsync(_cts.Token); @@ -454,6 +454,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable await publishTask.WaitAsync(TimeSpan.FromSeconds(5)); // Assert + await savedAfterPublish.WaitAsync(TimeSpan.FromSeconds(5)); await WaitForTrackerCountAsync(0); } @@ -537,7 +538,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable AddTracker(Guid.NewGuid(), eventId, status: SearchCommandStatus.Completed); await _eventsContext.SaveChangesAsync(); - Task publishTask = CaptureNextPublishedStatus(); + Task publishTask = CaptureNextPublishedStatus(out Task savedAfterPublish); // Act await _sut.StartAsync(_cts.Token); @@ -550,6 +551,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable await _eventPublisher.Received(1).PublishSearchCompleted( eventId, SearchCommandStatus.Failed, Arg.Any(), Arg.Any(), Arg.Any?>()); + await savedAfterPublish.WaitAsync(TimeSpan.FromSeconds(5)); await WaitForTrackerCountAsync(0); } @@ -561,7 +563,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable AddTracker(Guid.NewGuid(), eventId); await _eventsContext.SaveChangesAsync(); - Task pendingPublishTask = CaptureNextPublishedStatus(); + Task pendingPublishTask = CaptureNextPublishedStatus(out Task savedAfterPublish); // Act await _sut.StartAsync(_cts.Token); @@ -576,6 +578,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable await _arrClient.DidNotReceive().GetCommandsAsync(Arg.Any()); + await savedAfterPublish.WaitAsync(TimeSpan.FromSeconds(5)); await WaitForTrackerCountAsync(0); } @@ -600,11 +603,12 @@ public class SeekerCommandMonitorTests : IAsyncDisposable _arrClient.GetQueueItemsAsync(Arg.Any(), Arg.Any()) .Returns(new QueueListResponse()); - CaptureNextPublishedStatus(); + CaptureNextPublishedStatus(out Task savedAfterPublish); // Act await _sut.StartAsync(_cts.Token); _timeProvider.Advance(TimeSpan.FromSeconds(11)); + await savedAfterPublish.WaitAsync(TimeSpan.FromSeconds(5)); await WaitForTrackerCountAsync(0); // Assert @@ -736,7 +740,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable }); }); - Task publishTask = CaptureNextPublishedStatus(); + Task publishTask = CaptureNextPublishedStatus(out Task savedAfterPublish); // Act: the first poll hits a failing queue read await _sut.StartAsync(_cts.Token); @@ -758,6 +762,7 @@ public class SeekerCommandMonitorTests : IAsyncDisposable await _eventPublisher.Received(1).PublishSearchCompleted( eventId, SearchCommandStatus.Completed, Arg.Any(), Arg.Any(), Arg.Is?>(items => items != null && items.Count == 1 && items[0] == "Test.Item.1080p")); + await savedAfterPublish.WaitAsync(TimeSpan.FromSeconds(5)); await WaitForTrackerCountAsync(0); } @@ -1756,18 +1761,29 @@ public class SeekerCommandMonitorTests : IAsyncDisposable (await _eventsContext.SeekerCommandTrackers.CountAsync()).ShouldBe(expected); } - private Task CaptureNextPublishedStatus() + private Task CaptureNextPublishedStatus(out Task savedAfterPublish) { + TaskCompletionSource saved = new(); + savedAfterPublish = saved.Task; + TaskCompletionSource tcs = new(); _eventPublisher.PublishSearchCompleted( Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any?>()) .Returns(Task.CompletedTask) - .AndDoes(ci => tcs.TrySetResult(ci.ArgAt(1))); + .AndDoes(ci => + { + // armed here so the save before the publish cannot complete it + _eventsContext.SavedChanges += (_, _) => saved.TrySetResult(); + _eventsContext.SaveChangesFailed += (_, _) => saved.TrySetResult(); + tcs.TrySetResult(ci.ArgAt(1)); + }); return tcs.Task; } + private Task CaptureNextPublishedStatus() => CaptureNextPublishedStatus(out _); + private Task CaptureNthPoll(int count) { TaskCompletionSource tcs = new();