Skip to content

Commit 0c1120e

Browse files
authored
[DependencyInjection] Stashing actor spec (#6689)
* [DependencyInjection] Stashing actor spec * Add both IWithStash and IWithUnboundedStash * Add child actor unit tests
1 parent 7e1cc7b commit 0c1120e

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="ActorWithStashSpec.cs" company="Akka.NET Project">
3+
// Copyright (C) 2013-2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
using Akka.Actor;
8+
using Akka.TestKit;
9+
using FluentAssertions;
10+
using FluentAssertions.Extensions;
11+
using Xunit;
12+
using Xunit.Abstractions;
13+
14+
namespace Akka.DependencyInjection.Tests;
15+
16+
public class ActorWithStashSpec: AkkaSpec, IClassFixture<AkkaDiFixture>
17+
{
18+
public ActorWithStashSpec(AkkaDiFixture fixture, ITestOutputHelper output)
19+
: base(
20+
DependencyResolverSetup.Create(fixture.Provider)
21+
.And(BootstrapSetup.Create().WithConfig(TestKitBase.DefaultConfig)),
22+
output)
23+
{
24+
}
25+
26+
[Fact(DisplayName = "DependencyInjection should create actor with IWithStash interface")]
27+
public void WithStashActorTest()
28+
{
29+
var stashActor = GetActorOf<WithStashActor>(Sys);
30+
31+
stashActor.Tell(GetName.Instance, TestActor);
32+
ExpectNoMsg(0.3.Seconds());
33+
stashActor.Tell(GetName.Instance, TestActor);
34+
ExpectNoMsg(0.3.Seconds());
35+
36+
stashActor.Tell(StartProcessing.Instance, TestActor);
37+
ExpectMsg<string>().Should().StartWith("s");
38+
ExpectMsg<string>().Should().StartWith("s");
39+
ExpectNoMsg(0.3.Seconds());
40+
}
41+
42+
[Fact(DisplayName = "DependencyInjection should create actor with IWithUnboundedStash interface")]
43+
public void WithUnboundedStashActorTest()
44+
{
45+
var stashActor = GetActorOf<WithUnboundedStashActor>(Sys);
46+
47+
stashActor.Tell(GetName.Instance, TestActor);
48+
ExpectNoMsg(0.3.Seconds());
49+
stashActor.Tell(GetName.Instance, TestActor);
50+
ExpectNoMsg(0.3.Seconds());
51+
52+
stashActor.Tell(StartProcessing.Instance, TestActor);
53+
ExpectMsg<string>().Should().StartWith("s");
54+
ExpectMsg<string>().Should().StartWith("s");
55+
ExpectNoMsg(0.3.Seconds());
56+
}
57+
58+
[Fact(DisplayName = "DependencyInjection should create child actor with IWithStash interface")]
59+
public void WithStashChildActorTest()
60+
{
61+
var parentActor = Sys.ActorOf(Props.Create(() => new ParentActor<WithStashActor>()));
62+
63+
parentActor.Tell(GetName.Instance, TestActor);
64+
ExpectNoMsg(0.3.Seconds());
65+
parentActor.Tell(GetName.Instance, TestActor);
66+
ExpectNoMsg(0.3.Seconds());
67+
68+
parentActor.Tell(StartProcessing.Instance, TestActor);
69+
ExpectMsg<string>().Should().StartWith("s");
70+
ExpectMsg<string>().Should().StartWith("s");
71+
ExpectNoMsg(0.3.Seconds());
72+
}
73+
74+
[Fact(DisplayName = "DependencyInjection should create child actor with IWithUnboundedStash interface")]
75+
public void WithUnboundedStashChildActorTest()
76+
{
77+
var parentActor = Sys.ActorOf(Props.Create(() => new ParentActor<WithUnboundedStashActor>()));
78+
79+
parentActor.Tell(GetName.Instance, TestActor);
80+
ExpectNoMsg(0.3.Seconds());
81+
parentActor.Tell(GetName.Instance, TestActor);
82+
ExpectNoMsg(0.3.Seconds());
83+
84+
parentActor.Tell(StartProcessing.Instance, TestActor);
85+
ExpectMsg<string>().Should().StartWith("s");
86+
ExpectMsg<string>().Should().StartWith("s");
87+
ExpectNoMsg(0.3.Seconds());
88+
}
89+
90+
private static IActorRef GetActorOf<T>(ActorSystem actorSystem) where T: ActorBase
91+
=> actorSystem.ActorOf(DependencyResolver.For(actorSystem).Props<T>());
92+
93+
private static IActorRef GetActorOf<T>(IActorContext actorContext, ActorSystem actorSystem) where T: ActorBase
94+
=> actorContext.ActorOf(DependencyResolver.For(actorSystem).Props<T>());
95+
96+
private sealed class WithStashActor: StashingActor, IWithStash
97+
{
98+
public WithStashActor(AkkaDiFixture.IScopedDependency scoped) : base(scoped)
99+
{
100+
}
101+
}
102+
103+
private sealed class WithUnboundedStashActor: StashingActor, IWithUnboundedStash
104+
{
105+
public WithUnboundedStashActor(AkkaDiFixture.IScopedDependency scoped) : base(scoped)
106+
{
107+
}
108+
}
109+
110+
private sealed class ParentActor<T>: ReceiveActor where T: StashingActor
111+
{
112+
public ParentActor()
113+
{
114+
var child = GetActorOf<T>(Context, Context.System);
115+
ReceiveAny(msg => child.Forward(msg));
116+
}
117+
}
118+
119+
private abstract class StashingActor : ReceiveActor
120+
{
121+
private readonly AkkaDiFixture.IScopedDependency _scoped;
122+
123+
protected StashingActor(AkkaDiFixture.IScopedDependency scoped)
124+
{
125+
_scoped = scoped;
126+
Become(Stashing);
127+
}
128+
129+
private bool Stashing(object message)
130+
{
131+
if (message is StartProcessing)
132+
{
133+
Become(Processing);
134+
Stash.UnstashAll();
135+
return true;
136+
}
137+
138+
Stash.Stash();
139+
return true;
140+
}
141+
142+
private bool Processing(object message)
143+
{
144+
if (message is GetName)
145+
{
146+
Sender.Tell(_scoped.Name);
147+
return true;
148+
}
149+
150+
return false;
151+
}
152+
153+
public IStash Stash { get; set; }
154+
}
155+
156+
private sealed class GetName
157+
{
158+
public static readonly GetName Instance = new();
159+
private GetName() { }
160+
}
161+
162+
private sealed class StartProcessing
163+
{
164+
public static readonly StartProcessing Instance = new();
165+
private StartProcessing() { }
166+
}
167+
}

0 commit comments

Comments
 (0)