diff --git a/src/core/Akka.TestKit/TestKitBase.cs b/src/core/Akka.TestKit/TestKitBase.cs index d00870f5b9e..a3bf106516a 100644 --- a/src/core/Akka.TestKit/TestKitBase.cs +++ b/src/core/Akka.TestKit/TestKitBase.cs @@ -15,7 +15,7 @@ using Akka.Actor.Setup; using Akka.Configuration; using Akka.Event; -using Akka.Pattern; +using Akka.TestKit.Extensions; using Akka.TestKit.Internal; using Akka.Util; using Akka.Util.Internal; @@ -189,6 +189,7 @@ protected void InitializeTest(ActorSystem system, ActorSystemSetup config, strin } [MethodImpl(MethodImplOptions.AggressiveInlining)] + // Do not convert this method to async, it is being called inside the constructor. private static void WaitUntilTestActorIsReady(IActorRef testActor) { var deadline = TimeSpan.FromSeconds(5); @@ -485,10 +486,32 @@ public TimeSpan GetTimeoutOrDefault(TimeSpan? timeout) /// /// Optional. The duration to wait for shutdown. Default is 5 seconds multiplied with the config value "akka.test.timefactor". /// if set to true an exception will be thrown on failure. - public virtual void Shutdown(TimeSpan? duration = null, bool verifySystemShutdown = false) - { - Shutdown(_testState.System, duration, verifySystemShutdown); - } + /// to cancel the operation + /// TBD + public virtual void Shutdown( + TimeSpan? duration = null, + bool verifySystemShutdown = false, + CancellationToken cancellationToken = default) + => ShutdownAsync(_testState.System, duration, verifySystemShutdown, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Shuts down the specified system. + /// On failure debug output will be logged about the remaining actors in the system. + /// If verifySystemShutdown is true, then an exception will be thrown on failure. + /// + /// The system to shutdown. + /// The duration to wait for shutdown. Default is 5 seconds multiplied with the config value "akka.test.timefactor" + /// if set to true an exception will be thrown on failure. + /// to cancel the operation + /// TBD + protected virtual void Shutdown( + ActorSystem system, + TimeSpan? duration = null, + bool verifySystemShutdown = false, + CancellationToken cancellationToken = default) + => ShutdownAsync(system, duration, verifySystemShutdown, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); /// /// Shuts down the specified system. @@ -498,20 +521,24 @@ public virtual void Shutdown(TimeSpan? duration = null, bool verifySystemShutdow /// The system to shutdown. /// The duration to wait for shutdown. Default is 5 seconds multiplied with the config value "akka.test.timefactor" /// if set to true an exception will be thrown on failure. + /// to cancel the operation /// TBD - protected virtual void Shutdown(ActorSystem system, TimeSpan? duration = null, bool verifySystemShutdown = false) + protected virtual async Task ShutdownAsync( + ActorSystem system, + TimeSpan? duration = null, + bool verifySystemShutdown = false, + CancellationToken cancellationToken = default) { - if (system == null) system = _testState.System; + system ??= _testState.System; var durationValue = duration.GetValueOrDefault(Dilated(TimeSpan.FromSeconds(5)).Min(TimeSpan.FromSeconds(10))); - var wasShutdownDuringWait = system.Terminate().Wait(durationValue); + var wasShutdownDuringWait = await system.Terminate().AwaitWithTimeout(durationValue, cancellationToken); if(!wasShutdownDuringWait) { const string msg = "Failed to stop [{0}] within [{1}] \n{2}"; if(verifySystemShutdown) throw new TimeoutException(string.Format(msg, system.Name, durationValue, "")); - //TODO: replace "" with system.PrintTree() system.Log.Warning(msg, system.Name, durationValue, ""); //TODO: replace "" with system.PrintTree() } } @@ -522,46 +549,109 @@ protected virtual void Shutdown(ActorSystem system, TimeSpan? duration = null, b /// Child actor props /// Child actor name /// Supervisor strategy for the child actor + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, string name, SupervisorStrategy supervisorStrategy) + public IActorRef ChildActorOf( + Props props, + string name, + SupervisorStrategy supervisorStrategy, + CancellationToken cancellationToken = default) + => ChildActorOfAsync(props, name, supervisorStrategy, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Spawns an actor as a child of this test actor, and returns the child's IActorRef + /// + /// Child actor props + /// Child actor name + /// Supervisor strategy for the child actor + /// to cancel the operation + /// + public async Task ChildActorOfAsync( + Props props, + string name, + SupervisorStrategy supervisorStrategy, + CancellationToken cancellationToken = default) { TestActor.Tell(new TestActor.Spawn(props, name, supervisorStrategy)); - return ExpectMsg(); + return await ExpectMsgAsync(cancellationToken: cancellationToken) + .ConfigureAwait(false); } - + /// /// Spawns an actor as a child of this test actor with an auto-generated name, and returns the child's ActorRef. /// /// Child actor props /// Supervisor strategy for the child actor + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, SupervisorStrategy supervisorStrategy) + public IActorRef ChildActorOf( + Props props, SupervisorStrategy supervisorStrategy, CancellationToken cancellationToken = default) + => ChildActorOfAsync(props, supervisorStrategy, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Spawns an actor as a child of this test actor with an auto-generated name, and returns the child's ActorRef. + /// + /// Child actor props + /// Supervisor strategy for the child actor + /// to cancel the operation + /// + public async Task ChildActorOfAsync( + Props props, SupervisorStrategy supervisorStrategy, CancellationToken cancellationToken = default) { TestActor.Tell(new TestActor.Spawn(props, Option.None, supervisorStrategy)); - return ExpectMsg(); + return await ExpectMsgAsync(cancellationToken: cancellationToken) + .ConfigureAwait(false); } + + /// + /// Spawns an actor as a child of this test actor with a stopping supervisor strategy, and returns the child's ActorRef. + /// + /// Child actor props + /// Child actor name + /// to cancel the operation + /// + public IActorRef ChildActorOf(Props props, string name, CancellationToken cancellationToken = default) + => ChildActorOfAsync(props, name, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); /// /// Spawns an actor as a child of this test actor with a stopping supervisor strategy, and returns the child's ActorRef. /// /// Child actor props /// Child actor name + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, string name) + public async Task ChildActorOfAsync( + Props props, string name, CancellationToken cancellationToken = default) { TestActor.Tell(new TestActor.Spawn(props, name, Option.None)); - return ExpectMsg(); + return await ExpectMsgAsync(cancellationToken: cancellationToken) + .ConfigureAwait(false); } /// /// Spawns an actor as a child of this test actor with an auto-generated name and stopping supervisor strategy, returning the child's ActorRef. /// /// Child actor props + /// to cancel the operation + /// + public IActorRef ChildActorOf(Props props, CancellationToken cancellationToken = default) + => ChildActorOfAsync(props, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Spawns an actor as a child of this test actor with an auto-generated name and stopping supervisor strategy, returning the child's ActorRef. + /// + /// Child actor props + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props) + public async Task ChildActorOfAsync(Props props, CancellationToken cancellationToken = default) { TestActor.Tell(new TestActor.Spawn(props, Option.None, Option.None)); - return ExpectMsg(); + return await ExpectMsgAsync(cancellationToken: cancellationToken) + .ConfigureAwait(false); } /// diff --git a/src/core/Akka.TestKit/TestProbe.cs b/src/core/Akka.TestKit/TestProbe.cs index 4a9f499c202..3acfd6b0d29 100644 --- a/src/core/Akka.TestKit/TestProbe.cs +++ b/src/core/Akka.TestKit/TestProbe.cs @@ -7,6 +7,8 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using Akka.Actor; using Akka.Dispatch.SysMsg; using Akka.Util; @@ -167,70 +169,99 @@ public void SendSystemMessage(ISystemMessage message, IActorRef sender) /// /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. /// - /// /// /// + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, String name, SupervisorStrategy supervisorStrategy) - { - return ((TestKitBase)this).ChildActorOf(props, name, supervisorStrategy); - } + public IActorRef ChildActorOf( + string name, + SupervisorStrategy supervisorStrategy, + CancellationToken cancellationToken = default) + where T : ActorBase + => ChildActorOfAsync(Props.Create(), name, supervisorStrategy, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); - public IActorRef ChildActorOf(String name, SupervisorStrategy supervisorStrategy) + /// + /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. + /// + /// + /// + /// to cancel the operation + /// + public async Task ChildActorOfAsync( + string name, + SupervisorStrategy supervisorStrategy, + CancellationToken cancellationToken = default) where T : ActorBase - { - return ((TestKitBase)this).ChildActorOf(Props.Create(), name, supervisorStrategy); - } + => await ChildActorOfAsync(Props.Create(), name, supervisorStrategy, cancellationToken) + .ConfigureAwait(false); + /// /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. /// - /// /// + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, SupervisorStrategy supervisorStrategy) - { - return ((TestKitBase)this).ChildActorOf(props, supervisorStrategy); - } + public IActorRef ChildActorOf( + SupervisorStrategy supervisorStrategy, CancellationToken cancellationToken = default) + where T : ActorBase + => ChildActorOfAsync(Props.Create(), supervisorStrategy, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); - public IActorRef ChildActorOf(SupervisorStrategy supervisorStrategy) + /// + /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. + /// + /// + /// to cancel the operation + /// + public async Task ChildActorOfAsync( + SupervisorStrategy supervisorStrategy, CancellationToken cancellationToken = default) where T : ActorBase - { - return ((TestKitBase)this).ChildActorOf(Props.Create(), supervisorStrategy); - } + => await ChildActorOfAsync(Props.Create(), supervisorStrategy, cancellationToken) + .ConfigureAwait(false); /// /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. /// - /// /// + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props, String name) - { - return ((TestKitBase)this).ChildActorOf(props, name); - } + public IActorRef ChildActorOf(string name, CancellationToken cancellationToken = default) + where T : ActorBase + => ChildActorOfAsync(Props.Create(), name, cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); - public IActorRef ChildActorOf(String name) + /// + /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. + /// + /// + /// to cancel the operation + /// + public async Task ChildActorOfAsync(string name, CancellationToken cancellationToken = default) where T : ActorBase - { - return ((TestKitBase)this).ChildActorOf(Props.Create(), name); - } + => await ChildActorOfAsync(Props.Create(), name, cancellationToken) + .ConfigureAwait(false); /// /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. /// - /// + /// to cancel the operation /// - public IActorRef ChildActorOf(Props props) - { - return ((TestKitBase)this).ChildActorOf(props); - } + public IActorRef ChildActorOf(CancellationToken cancellationToken = default) + where T : ActorBase + => ChildActorOfAsync(Props.Create(), cancellationToken) + .ConfigureAwait(false).GetAwaiter().GetResult(); - public IActorRef ChildActorOf() + /// + /// Spawns an actor as a child of this test actor, and returns the child's ActorRef. + /// + /// to cancel the operation + /// + public async Task ChildActorOfAsync(CancellationToken cancellationToken = default) where T : ActorBase - { - return ((TestKitBase)this).ChildActorOf(Props.Create()); - } + => await ChildActorOfAsync(Props.Create(), cancellationToken) + .ConfigureAwait(false); /// /// Sends a system message to the test probe