Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Akka.Tests.Actor tests to async/await - ActorLifeCycle #5760

Merged
merged 5 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 88 additions & 79 deletions src/core/Akka.Tests/Actor/ActorLifeCycleSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,82 +107,82 @@ protected override void PreStart()
}

[Fact(DisplayName = "invoke preRestart, preStart, postRestart when using OneForOneStrategy")]
public void Actor_lifecycle_test1()
public async Task Actor_lifecycle_test1()
{
var generationProvider = new AtomicCounter();
string id = Guid.NewGuid().ToString();
var supervisor = Sys.ActorOf(Props.Create(() => new Supervisor(new OneForOneStrategy(3, TimeSpan.FromSeconds(1000), x => Directive.Restart))));
var restarterProps = Props.Create(() => new LifeCycleTestActor(TestActor, id, generationProvider));
var restarter = supervisor.Ask<IActorRef>(restarterProps).Result;
var restarter = await supervisor.Ask<IActorRef>(restarterProps);

ExpectMsg(("preStart", id, 0));
await ExpectMsgAsync(("preStart", id, 0));
restarter.Tell(Kill.Instance);
ExpectMsg(("preRestart", id, 0));
ExpectMsg(("postRestart", id, 1));
await ExpectMsgAsync(("preRestart", id, 0));
await ExpectMsgAsync(("postRestart", id, 1));
restarter.Tell("status");
ExpectMsg(("OK", id, 1));
await ExpectMsgAsync(("OK", id, 1));
restarter.Tell(Kill.Instance);
ExpectMsg(("preRestart", id, 1));
ExpectMsg(("postRestart", id, 2));
await ExpectMsgAsync(("preRestart", id, 1));
await ExpectMsgAsync(("postRestart", id, 2));
restarter.Tell("status");
ExpectMsg(("OK", id, 2));
await ExpectMsgAsync(("OK", id, 2));
restarter.Tell(Kill.Instance);
ExpectMsg(("preRestart", id, 2));
ExpectMsg(("postRestart", id, 3));
await ExpectMsgAsync(("preRestart", id, 2));
await ExpectMsgAsync(("postRestart", id, 3));
restarter.Tell("status");
ExpectMsg(("OK", id, 3));
await ExpectMsgAsync(("OK", id, 3));
restarter.Tell(Kill.Instance);
ExpectMsg(("postStop", id, 3));
ExpectNoMsg(TimeSpan.FromSeconds(1));
await ExpectMsgAsync(("postStop", id, 3));
await ExpectNoMsgAsync(TimeSpan.FromSeconds(1));
Sys.Stop(supervisor);
}

[Fact(DisplayName="default for preRestart and postRestart is to call postStop and preStart respectively")]
public void Actor_lifecycle_test2()
public async Task Actor_lifecycle_test2()
{
var generationProvider = new AtomicCounter();
string id = Guid.NewGuid().ToString();
var supervisor = Sys.ActorOf(Props.Create(() => new Supervisor(new OneForOneStrategy(3, TimeSpan.FromSeconds(1000), x => Directive.Restart))));
var restarterProps = Props.Create(() => new LifeCycleTest2Actor(TestActor, id, generationProvider));
var restarter = supervisor.Ask<IActorRef>(restarterProps).Result;
var restarter = await supervisor.Ask<IActorRef>(restarterProps);

ExpectMsg(("preStart", id, 0));
await ExpectMsgAsync(("preStart", id, 0));
restarter.Tell(Kill.Instance);
ExpectMsg(("postStop", id, 0));
ExpectMsg(("preStart", id, 1));
await ExpectMsgAsync(("postStop", id, 0));
await ExpectMsgAsync(("preStart", id, 1));
restarter.Tell("status");
ExpectMsg(("OK", id, 1));
await ExpectMsgAsync(("OK", id, 1));
restarter.Tell(Kill.Instance);
ExpectMsg(("postStop", id, 1));
ExpectMsg(("preStart", id, 2));
await ExpectMsgAsync(("postStop", id, 1));
await ExpectMsgAsync(("preStart", id, 2));
restarter.Tell("status");
ExpectMsg(("OK", id, 2));
await ExpectMsgAsync(("OK", id, 2));
restarter.Tell(Kill.Instance);
ExpectMsg(("postStop", id, 2));
ExpectMsg(("preStart", id, 3));
await ExpectMsgAsync(("postStop", id, 2));
await ExpectMsgAsync(("preStart", id, 3));
restarter.Tell("status");
ExpectMsg(("OK", id, 3));
await ExpectMsgAsync(("OK", id, 3));
restarter.Tell(Kill.Instance);
ExpectMsg(("postStop", id, 3));
ExpectNoMsg(TimeSpan.FromSeconds(1));
await ExpectMsgAsync(("postStop", id, 3));
await ExpectNoMsgAsync(TimeSpan.FromSeconds(1));
Sys.Stop(supervisor);
}

[Fact(DisplayName="not invoke preRestart and postRestart when never restarted using OneForOneStrategy")]
public void Actor_lifecycle_test3()
public async Task Actor_lifecycle_test3()
{
var generationProvider = new AtomicCounter();
string id = Guid.NewGuid().ToString();
var supervisor = Sys.ActorOf(Props.Create(() => new Supervisor(new OneForOneStrategy(3, TimeSpan.FromSeconds(1000), x => Directive.Restart))));
var restarterProps = Props.Create(() => new LifeCycleTest2Actor(TestActor, id, generationProvider));
var restarter = supervisor.Ask<IInternalActorRef>(restarterProps).Result;
var restarter = await supervisor.Ask<IInternalActorRef>(restarterProps);

ExpectMsg(("preStart", id, 0));
await ExpectMsgAsync(("preStart", id, 0));
restarter.Tell("status");
ExpectMsg(("OK", id, 0));
await ExpectMsgAsync(("OK", id, 0));
restarter.Stop();
ExpectMsg(("postStop", id, 0));
ExpectNoMsg(TimeSpan.FromSeconds(1));
await ExpectMsgAsync(("postStop", id, 0));
await ExpectNoMsgAsync(TimeSpan.FromSeconds(1));
}


Expand All @@ -199,10 +199,10 @@ protected override void PostStop()
}

[Fact(DisplayName="log failures in postStop")]
public void Log_failures_in_PostStop()
public async Task Log_failures_in_PostStop()
{
var a = Sys.ActorOf<EmptyActor>();
EventFilter.Exception<Exception>(message: "hurrah").ExpectOne(() =>
await EventFilter.Exception<Exception>(message: "hurrah").ExpectOneAsync(() =>
{
a.Tell(PoisonPill.Instance);
});
Expand Down Expand Up @@ -255,20 +255,20 @@ protected void OnBecome(object message)
}

[Fact]
public void Clear_behavior_stack_upon_restart()
public async Task Clear_behavior_stack_upon_restart()
{
var a = Sys.ActorOf(Props.Create(() => new BecomeActor(TestActor)));

a.Tell("hello");
ExpectMsg(42);
await ExpectMsgAsync(42);
a.Tell(new Become());
ExpectMsg("ok");
await ExpectMsgAsync("ok");
a.Tell("hello");
ExpectMsg(43);
await ExpectMsgAsync(43);

EventFilter.Exception<Exception>("buh").ExpectOne(() => a.Tell("fail"));
await EventFilter.Exception<Exception>("buh").ExpectOneAsync(() => a.Tell("fail"));
a.Tell("hello");
ExpectMsg(42);
await ExpectMsgAsync(42);
}

public class SupervisorTestActor : UntypedActor
Expand All @@ -281,24 +281,33 @@ public SupervisorTestActor(IActorRef testActor)

protected override void OnReceive(object message)
{
PatternMatch.Match(message)
.With<Spawn>(m =>
{
Context.ActorOf(Props.Create(() => new KillableActor(testActor)), m.Name);
testActor.Tell(("Created", m.Name));
})
.With<ContextStop>(m =>
{
var child = Context.Child(m.Name);
Context.Stop(child);
})
.With<Stop>(m =>
{
var child = Context.Child(m.Name);
((IInternalActorRef)child).Stop();
})
.With<Count>(m =>
testActor.Tell(Context.GetChildren().Count()));
switch (message)
{
case Spawn m:
{
Context.ActorOf(Props.Create(() => new KillableActor(testActor)), m.Name);
testActor.Tell(("Created", m.Name));
}
break;
case ContextStop m:
{
var child = Context.Child(m.Name);
Context.Stop(child);
}
break;
case Stop m:
{
var child = Context.Child(m.Name);
((IInternalActorRef)child).Stop();
}
break;
case Count m:
default:
Arkatufus marked this conversation as resolved.
Show resolved Hide resolved
{
testActor.Tell(Context.GetChildren().Count());
}
break;
}
}

public class Spawn
Expand Down Expand Up @@ -339,47 +348,47 @@ protected override void OnReceive(object message)
}

[Fact(DisplayName="If a parent receives a Terminated event for a child actor, the parent should no longer supervise it")]
public void Clear_child_upon_terminated()
public async Task Clear_child_upon_terminated()
{
var names = new[] {"Bob", "Jameson", "Natasha"};
var supervisor = Sys.ActorOf(Props.Create(() => new SupervisorTestActor(TestActor)));
supervisor.Tell(new SupervisorTestActor.Spawn(){ Name = names[0] });
ExpectMsg(("Created",names[0]));
await ExpectMsgAsync(("Created",names[0]));
supervisor.Tell(new SupervisorTestActor.Count());
ExpectMsg(1);
await ExpectMsgAsync(1);
supervisor.Tell(new SupervisorTestActor.Spawn() { Name = names[1] });
ExpectMsg(("Created", names[1]));
await ExpectMsgAsync(("Created", names[1]));
supervisor.Tell(new SupervisorTestActor.Count());
ExpectMsg(2);
await ExpectMsgAsync(2);
supervisor.Tell(new SupervisorTestActor.ContextStop() { Name = names[1] });
ExpectMsg(("Terminated", names[1]));
await ExpectMsgAsync(("Terminated", names[1]));

//we need to wait for the child actor to unregister itself from the parent.
//this is done after PostStop so we have no way to wait for it
//ideas?
Task.Delay(100).Wait();
await Task.Delay(100);
supervisor.Tell(new SupervisorTestActor.Count());
ExpectMsg(1);
await ExpectMsgAsync(1);
supervisor.Tell(new SupervisorTestActor.Spawn() { Name = names[2] });
ExpectMsg(("Created", names[2]));
Task.Delay(100).Wait();
await ExpectMsgAsync(("Created", names[2]));
await Task.Delay(100);
supervisor.Tell(new SupervisorTestActor.Count());
ExpectMsg(2);
await ExpectMsgAsync(2);
supervisor.Tell(new SupervisorTestActor.Stop() { Name = names[0] });
ExpectMsg(("Terminated", names[0]));
await ExpectMsgAsync(("Terminated", names[0]));
supervisor.Tell(new SupervisorTestActor.Stop() { Name = names[2] });
ExpectMsg(("Terminated", names[2]));
await ExpectMsgAsync(("Terminated", names[2]));

Task.Delay(100).Wait();
await Task.Delay(100);
supervisor.Tell(new SupervisorTestActor.Count());
ExpectMsg(0);
await ExpectMsgAsync(0);
}


class MyCustomException : Exception {}

[Fact(DisplayName="PreRestart should receive correct cause, message and sender")]
public void Call_PreStart_with_correct_message_and_sender()
public async Task Call_PreStart_with_correct_message_and_sender()
{
var broken = ActorOf(c =>
{
Expand All @@ -400,9 +409,9 @@ public void Call_PreStart_with_correct_message_and_sender()

broken.Tell(message);

ExpectMsg<MyCustomException>();
ExpectMsg(message);
ExpectMsg(TestActor);
await ExpectMsgAsync<MyCustomException>();
await ExpectMsgAsync(message);
await ExpectMsgAsync(TestActor);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/Akka.Tests/Actor/DeadLettersSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------

using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;
using Akka.TestKit;
Expand All @@ -16,11 +17,11 @@ namespace Akka.Tests
public class DeadLettersSpec : AkkaSpec
{
[Fact]
public void Can_send_messages_to_dead_letters()
public async Task Can_send_messages_to_dead_letters()
{
Sys.EventStream.Subscribe(TestActor, typeof(DeadLetter));
Sys.DeadLetters.Tell("foobar");
ExpectMsg<DeadLetter>(deadLetter=>deadLetter.Message.Equals("foobar"));
await ExpectMsgAsync<DeadLetter>(deadLetter=>deadLetter.Message.Equals("foobar"));
}
}
}
Expand Down