diff --git a/Directory.Build.props b/Directory.Build.props
index 57ba700d..50381c5f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -31,7 +31,7 @@
6.0.3
3.1.5
3.1.5
- 1.5.67
+ 1.5.68
[9.0.0,)
[9.0.0,)
diff --git a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveTestKit.verified.txt b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveTestKit.verified.txt
index 1baf252f..d77b749e 100644
--- a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveTestKit.verified.txt
+++ b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveTestKit.verified.txt
@@ -43,6 +43,7 @@ namespace Akka.Hosting.TestKit
public System.Threading.Tasks.Task WithSnapshotSave(System.Func behaviorSelector, System.Action execution) { }
public System.Threading.Tasks.Task WithSnapshotSave(System.Func behaviorSelector, System.Func execution) { }
}
+ [Akka.TestKit.Xunit.Attributes.AkkaCleanAmbientContext]
public abstract class TestKit : Akka.TestKit.TestKitBase, System.IAsyncDisposable, Xunit.IAsyncLifetime
{
protected TestKit(string? actorSystemName = null, Xunit.ITestOutputHelper? output = null, System.TimeSpan? startupTimeout = default, Microsoft.Extensions.Logging.LogLevel logLevel = 2) { }
diff --git a/src/Akka.Hosting.TestKit.Tests/ParallelAmbientContextSpec.cs b/src/Akka.Hosting.TestKit.Tests/ParallelAmbientContextSpec.cs
new file mode 100644
index 00000000..0842fba6
--- /dev/null
+++ b/src/Akka.Hosting.TestKit.Tests/ParallelAmbientContextSpec.cs
@@ -0,0 +1,83 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (C) 2013-2022 .NET Foundation
+//
+// -----------------------------------------------------------------------
+
+using System;
+using System.Threading.Tasks;
+using Akka.Actor;
+using Akka.Actor.Internal;
+using Akka.TestKit;
+using Xunit;
+
+namespace Akka.Hosting.TestKit.Tests;
+
+public abstract class ParallelAmbientContextSpecBase : TestKit
+{
+ protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
+ {
+ }
+
+ [Fact]
+ public async Task Implicit_sender_should_resolve_to_own_TestActor()
+ {
+ TestActor.Tell("ping");
+ await ExpectMsgAsync(
+ "ping",
+ TimeSpan.FromSeconds(5),
+ cancellationToken: TestContext.Current.CancellationToken);
+ Assert.Equal(TestActor, LastSender);
+
+ await Task.Yield();
+ TestActor.Tell("ping-after-yield");
+ await ExpectMsgAsync(
+ "ping-after-yield",
+ TimeSpan.FromSeconds(5),
+ cancellationToken: TestContext.Current.CancellationToken);
+ Assert.Equal(TestActor, LastSender);
+ }
+}
+
+public class ParallelAmbientContextSpec01 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec02 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec03 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec04 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec05 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec06 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec07 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec08 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec09 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec10 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec11 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec12 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec13 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec14 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec15 : ParallelAmbientContextSpecBase { }
+public class ParallelAmbientContextSpec16 : ParallelAmbientContextSpecBase { }
+
+public abstract class ParallelNoImplicitSenderSpecBase : TestKit, INoImplicitSender
+{
+ protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
+ {
+ }
+
+ [Fact]
+ public async Task Current_should_be_null_both_pre_and_post_await()
+ {
+ Assert.Null(InternalCurrentActorCellKeeper.Current);
+ await Task.Yield();
+ Assert.Null(InternalCurrentActorCellKeeper.Current);
+ await Task.Yield();
+ Assert.Null(InternalCurrentActorCellKeeper.Current);
+ }
+}
+
+public class ParallelNoImplicitSenderSpec01 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec02 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec03 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec04 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec05 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec06 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec07 : ParallelNoImplicitSenderSpecBase { }
+public class ParallelNoImplicitSenderSpec08 : ParallelNoImplicitSenderSpecBase { }
diff --git a/src/Akka.Hosting.TestKit.Tests/Properties/AssemblyInfo.cs b/src/Akka.Hosting.TestKit.Tests/Properties/AssemblyInfo.cs
index e2336be8..d7439b5d 100644
--- a/src/Akka.Hosting.TestKit.Tests/Properties/AssemblyInfo.cs
+++ b/src/Akka.Hosting.TestKit.Tests/Properties/AssemblyInfo.cs
@@ -32,4 +32,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)]
+[assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass)]
diff --git a/src/Akka.Hosting.TestKit.Tests/xunit.runner.json b/src/Akka.Hosting.TestKit.Tests/xunit.runner.json
index 4a73b1e5..4ba486b0 100644
--- a/src/Akka.Hosting.TestKit.Tests/xunit.runner.json
+++ b/src/Akka.Hosting.TestKit.Tests/xunit.runner.json
@@ -1,6 +1,6 @@
{
"$schema": "https://xunit.github.io/schema/current/xunit.runner.schema.json",
"longRunningTestSeconds": 60,
- "parallelizeAssembly": false,
- "parallelizeTestCollections": false
+ "parallelizeAssembly": true,
+ "parallelizeTestCollections": true
}
\ No newline at end of file
diff --git a/src/Akka.Hosting.TestKit/TestKit.Shared.cs b/src/Akka.Hosting.TestKit/TestKit.Shared.cs
index 940ba95e..11f421e1 100644
--- a/src/Akka.Hosting.TestKit/TestKit.Shared.cs
+++ b/src/Akka.Hosting.TestKit/TestKit.Shared.cs
@@ -54,7 +54,7 @@ public IHost Host
///
private void EnsureImplicitSender()
{
- if (this is not INoImplicitSender && TestActor != null)
+ if (this is not INoImplicitSender && InternalCurrentActorCellKeeper.Current == null && TestActor != null)
InternalCurrentActorCellKeeper.Current = (ActorCell)((ActorRefWithCell)TestActor).Underlying;
}
@@ -192,12 +192,6 @@ private async Task InitializeAsyncCore()
// TestActor initialization and registration now happens in AddStartup
// before user actors are created, preventing race conditions
- // ALWAYS set the implicit sender context on the current thread after initialization
- // This ensures it's available on the thread where tests will run
- // This is critical for tests using DI-created actors
- if (this is not INoImplicitSender && TestActor != null)
- InternalCurrentActorCellKeeper.Current = (ActorCell)((ActorRefWithCell)TestActor).Underlying;
-
await BeforeTestStart();
}
@@ -221,11 +215,6 @@ protected sealed override void InitializeTest(ActorSystem system, ActorSystemSet
protected virtual Task BeforeTestStart()
{
- // Ensure the implicit sender is set on the current thread before each test
- // This is critical because tests may run on different threads than initialization
- if (this is not INoImplicitSender)
- InternalCurrentActorCellKeeper.Current = (ActorCell)((ActorRefWithCell)TestActor).Underlying;
-
return Task.CompletedTask;
}
diff --git a/src/Akka.Hosting.TestKit/TestKit.cs b/src/Akka.Hosting.TestKit/TestKit.cs
index 922ee6df..a0a28b05 100644
--- a/src/Akka.Hosting.TestKit/TestKit.cs
+++ b/src/Akka.Hosting.TestKit/TestKit.cs
@@ -7,10 +7,12 @@
using System;
using System.Threading.Tasks;
using Akka.Annotations;
+using Akka.TestKit.Xunit.Attributes;
using Xunit;
namespace Akka.Hosting.TestKit
{
+ [AkkaCleanAmbientContext]
public abstract partial class TestKit : IAsyncLifetime, IAsyncDisposable
{
[InternalApi]