Skip to content

Commit ba2d762

Browse files
committed
fix: Correct flaky tests
1 parent fd212af commit ba2d762

3 files changed

Lines changed: 34 additions & 11 deletions

File tree

tests/MultiLock.Tests/InMemoryProviderTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public async Task GetCurrentLeaderAsync_WhenLeaderExists_ShouldReturnLeaderInfo(
7777
// Assert
7878
leader.ShouldNotBeNull();
7979
leader.LeaderId.ShouldBe(participantId);
80-
leader.Metadata.ShouldContainKey("key");
80+
leader.Metadata.ContainsKey("key").ShouldBeTrue();
8181
leader.Metadata["key"].ShouldBe("value");
8282
}
8383

@@ -147,7 +147,7 @@ public async Task UpdateHeartbeatAsync_WhenIsLeader_ShouldSucceed()
147147

148148
LeaderInfo? leader = await provider.GetCurrentLeaderAsync(electionGroup);
149149
leader.ShouldNotBeNull();
150-
leader.Metadata.ShouldContainKey("key");
150+
leader.Metadata.ContainsKey("key").ShouldBeTrue();
151151
leader.Metadata["key"].ShouldBe("updated-value");
152152
}
153153

tests/MultiLock.Tests/LeadershipExtensionMethodsTests.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,14 @@ public async Task DistinctUntilChanged_ShouldFilterConsecutiveDuplicates()
210210
ILeaderElectionService service = services.GetRequiredService<ILeaderElectionService>();
211211
var events = new List<LeadershipChangedEventArgs>();
212212
object eventsLock = new();
213-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
213+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
214214

215215
// Act - Start listening BEFORE starting service
216216
CancellationToken cancellationToken = cts.Token;
217217
var eventTask = Task.Run(async () =>
218218
{
219219
await foreach (LeadershipChangedEventArgs e in service.GetLeadershipChangesAsync(cancellationToken)
220-
.DistinctUntilChanged(cancellationToken)
221-
.Take(2, cancellationToken))
220+
.DistinctUntilChanged(cancellationToken))
222221
{
223222
lock (eventsLock)
224223
{
@@ -228,12 +227,18 @@ public async Task DistinctUntilChanged_ShouldFilterConsecutiveDuplicates()
228227
}, cancellationToken);
229228

230229
// Give the async enumerable consumer time to start
231-
await Task.Delay(TimeSpan.FromMilliseconds(50), cts.Token);
230+
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
232231

233-
await service.StartAsync(cts.Token);
234-
await service.WaitForLeadershipAsync(cts.Token);
235-
await service.StopAsync(cts.Token);
236-
await TestHelpers.WaitForConditionAsync(() => events.Count >= 1, TimeSpan.FromSeconds(5), cts.Token, eventsLock);
232+
await service.StartAsync(cancellationToken);
233+
await service.WaitForLeadershipAsync(cancellationToken);
234+
235+
// Wait for the first event (gained leadership)
236+
await TestHelpers.WaitForConditionAsync(() => events.Count >= 1, TimeSpan.FromSeconds(3), cancellationToken, eventsLock);
237+
238+
await service.StopAsync(cancellationToken);
239+
240+
// Wait for the second event (lost leadership)
241+
await TestHelpers.WaitForConditionAsync(() => events.Count >= 2, TimeSpan.FromSeconds(3), cancellationToken, eventsLock);
237242

238243
// Cleanup - Cancel and wait for event task to complete before asserting
239244
await cts.CancelAsync();
@@ -245,7 +250,9 @@ public async Task DistinctUntilChanged_ShouldFilterConsecutiveDuplicates()
245250
{
246251
eventSnapshot = events.ToArray();
247252
}
248-
eventSnapshot.Length.ShouldBeGreaterThanOrEqualTo(1);
253+
eventSnapshot.Length.ShouldBeGreaterThanOrEqualTo(2);
254+
eventSnapshot[0].BecameLeader.ShouldBeTrue();
255+
eventSnapshot[1].LostLeadership.ShouldBeTrue();
249256

250257
await services.DisposeAsync();
251258
}

tests/MultiLock.Tests/MultiInstanceLeaderElectionTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public async Task MultipleInstances_WithInMemoryProvider_ShouldElectOneLeader()
6666
services.Add(service);
6767
}
6868

69+
// Give event subscriptions time to start
70+
await Task.Delay(TimeSpan.FromMilliseconds(100), cts.Token);
71+
6972
// Act - Start all instances
7073
Task[] startTasks = services.Select(s => s.StartAsync(cts.Token)).ToArray();
7174
await Task.WhenAll(startTasks);
@@ -76,6 +79,19 @@ await TestHelpers.WaitForConditionAsync(
7679
TimeSpan.FromSeconds(5),
7780
cts.Token);
7881

82+
// Wait for leadership events to be received
83+
await TestHelpers.WaitForConditionAsync(
84+
() =>
85+
{
86+
lock (leadershipEvents)
87+
{
88+
return leadershipEvents.Any(e => e.IsLeader);
89+
}
90+
},
91+
TimeSpan.FromSeconds(3),
92+
cts.Token,
93+
leadershipEvents);
94+
7995
// Assert - Exactly one leader should be elected
8096
var currentLeaders = services.Where(s => s.IsLeader).ToList();
8197
currentLeaders.Count.ShouldBe(1, "exactly one instance should be the leader");

0 commit comments

Comments
 (0)