diff --git a/src/DaemonTests/Internals/HighWaterAgentTests.cs b/src/DaemonTests/Internals/HighWaterAgentTests.cs index c15ec96dc3..c76ee53ed8 100644 --- a/src/DaemonTests/Internals/HighWaterAgentTests.cs +++ b/src/DaemonTests/Internals/HighWaterAgentTests.cs @@ -107,6 +107,32 @@ public async Task will_not_go_in_loop_when_sequence_is_advanced_but_gaps_from_hi await agent2.Tracker.WaitForHighWaterMark(NumberOfEvents + 5); } + [Fact] + public async Task skips_multiple_gaps_and_keeps_advancing() + { + NumberOfStreams = 10; + await PublishSingleThreaded(); + + // Create multiple gaps in the event sequence + var gaps = new[] { NumberOfEvents - 9, NumberOfEvents - 6, NumberOfEvents - 5, NumberOfEvents - 3 }; + await deleteEvents(gaps); + + // Make gap skipping kick in faster + theStore.Options.Projections.StaleSequenceThreshold = 1.Seconds(); + + using var agent = await StartDaemon(); + + // Expect the agent to move beyond each gap by reporting the last contiguous (safe harbor) mark + await agent.Tracker.WaitForHighWaterMark(gaps[0], 2.Seconds()); + await agent.Tracker.WaitForHighWaterMark(gaps[1], 2.Seconds()); + await agent.Tracker.WaitForHighWaterMark(gaps[2], 2.Seconds()); + await agent.Tracker.WaitForHighWaterMark(gaps[3], 2.Seconds()); + // And eventually reach the head + await agent.Tracker.WaitForHighWaterMark(NumberOfEvents, 2.Seconds()); + + await agent.StopAllAsync(); + } + private async Task deleteEvents(params long[] ids) { await using var conn = theStore.CreateConnection();