diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionSpec.cs index 00af0945838..02ddefa0334 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionSpec.cs @@ -148,10 +148,10 @@ public void ClusterShardingDeadShardRegionTest() } [Fact] - public void ClusterSharding_must() + public async Task ClusterSharding_must() { ClusterSharding_must_initialize_cluster_and_allocate_sharded_actors(); - ClusterSharding_must_only_deliver_buffered_RestartShard_to_the_local_region(); + await ClusterSharding_must_only_deliver_buffered_RestartShard_to_the_local_region(); } public void ClusterSharding_must_initialize_cluster_and_allocate_sharded_actors() @@ -186,7 +186,7 @@ public void ClusterSharding_must_initialize_cluster_and_allocate_sharded_actors( p2.ExpectMsg(3); } - public void ClusterSharding_must_only_deliver_buffered_RestartShard_to_the_local_region() + public async Task ClusterSharding_must_only_deliver_buffered_RestartShard_to_the_local_region() { ImmutableHashSet StatesFor(IActorRef region, TestProbe probe, int expect) { @@ -203,14 +203,14 @@ ImmutableHashSet StatesFor(IActorRef region, TestProbe probe, int expect }, msgs: expect).SelectMany(i => i).ToImmutableHashSet(); } - bool AwaitRebalance(IActorRef region, int msg, TestProbe probe) + async Task AwaitRebalanceAsync(IActorRef region, int msg, TestProbe probe) { region.Tell(msg, probe.Ref); - var m = probe.ExpectMsg(TimeSpan.FromSeconds(2)); + var m = await probe.ExpectMsgAsync(TimeSpan.FromSeconds(2)); if (m == msg) return true; else - return AwaitRebalance(region, msg, probe); + return await AwaitRebalanceAsync(region, msg, probe); } void Swap(ref T v1, ref T v2) @@ -244,9 +244,9 @@ void Swap(ref T v1, ref T v2) }); // Difficult to raise the RestartShard in conjunction with the rebalance for mode=ddata - AwaitAssert(() => + await AwaitAssertAsync(async () => { - AwaitRebalance(region1, shardIdToMove, p1).Should().BeTrue(); + (await AwaitRebalanceAsync(region1, shardIdToMove, p1)).Should().BeTrue(); }); var rebalancedOnRegion1 = StatesFor(region1, p1, expect: numberOfShards); diff --git a/src/core/Akka.Tests/Actor/InboxSpec.cs b/src/core/Akka.Tests/Actor/InboxSpec.cs index 64b159bd696..b948f2779f5 100644 --- a/src/core/Akka.Tests/Actor/InboxSpec.cs +++ b/src/core/Akka.Tests/Actor/InboxSpec.cs @@ -126,17 +126,29 @@ public async Task Inbox_have_a_default_and_custom_timeouts() { await WithinAsync(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(6), () => { - Assert.Throws(() => _inbox.Receive()); + // Inbox.Receive() may throw TimeoutException directly or wrapped in AggregateException + // depending on internal implementation (sync vs async path) + var ex = Record.Exception(() => _inbox.Receive()); + Assert.NotNull(ex); + Assert.True(IsTimeoutException(ex), $"Expected TimeoutException but got: {ex.GetType().Name}"); return Task.CompletedTask; }); await WithinAsync(TimeSpan.FromSeconds(1), () => { - Assert.Throws(() => _inbox.Receive(TimeSpan.FromMilliseconds(100))); + var ex = Record.Exception(() => _inbox.Receive(TimeSpan.FromMilliseconds(100))); + Assert.NotNull(ex); + Assert.True(IsTimeoutException(ex), $"Expected TimeoutException but got: {ex.GetType().Name}"); return Task.CompletedTask; }); } + private static bool IsTimeoutException(Exception ex) + { + return ex is TimeoutException || + (ex is AggregateException agg && agg.Flatten().InnerExceptions.Any(e => e is TimeoutException)); + } + [Fact] public void Select_WithClient_should_update_Client_and_copy_the_rest_of_the_properties_BUG_427() { diff --git a/src/core/Akka.Tests/Actor/Scheduler/TaskBasedScheduler_ActionScheduler_Schedule_Tests.cs b/src/core/Akka.Tests/Actor/Scheduler/TaskBasedScheduler_ActionScheduler_Schedule_Tests.cs index 1220fb17779..6bb376f82cb 100644 --- a/src/core/Akka.Tests/Actor/Scheduler/TaskBasedScheduler_ActionScheduler_Schedule_Tests.cs +++ b/src/core/Akka.Tests/Actor/Scheduler/TaskBasedScheduler_ActionScheduler_Schedule_Tests.cs @@ -51,6 +51,10 @@ public async Task ScheduleRepeatedly_in_milliseconds_Tests_and_verify_the_interv //Expect to get a list from receiver after it has received three messages var dateTimeOffsets = await ExpectMsgAsync>(); dateTimeOffsets.ShouldHaveCount(3); + // CI machines can have significant timing variability due to CPU contention, + // virtualization overhead, and GC pauses. Use 30% tolerance to accommodate + // this while still catching gross scheduler bugs. + const double maxDeviation = 0.30; Action validate = (a, b) => { var valA = dateTimeOffsets[a]; @@ -58,10 +62,10 @@ public async Task ScheduleRepeatedly_in_milliseconds_Tests_and_verify_the_interv var diffBetweenMessages = Math.Abs((valB - valA).TotalMilliseconds); var diffInMs = Math.Abs(diffBetweenMessages - interval); var deviate = (diffInMs/interval); - deviate.Should(val => val < 0.1, + deviate.Should(val => val < maxDeviation, string.Format( - "Expected the interval between message {1} and {2} to deviate maximum 10% from {0}. It was {3} ms between the messages. It deviated {4}%", - interval, a + 1, b + 1, diffBetweenMessages, deviate*100)); + "Expected the interval between message {1} and {2} to deviate maximum {5}% from {0}. It was {3} ms between the messages. It deviated {4}%", + interval, a + 1, b + 1, diffBetweenMessages, deviate*100, maxDeviation*100)); }; validate(0, 1); validate(1, 2);