Skip to content

Commit 66c3186

Browse files
authored
test: add stashing tests (#2253)
1 parent 1d9bcc5 commit 66c3186

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="StashingTests.cs" company="Asynkron AB">
3+
// Copyright (C) 2015-2025 Asynkron AB All rights reserved
4+
// </copyright>
5+
// -----------------------------------------------------------------------
6+
7+
using System.Collections.Generic;
8+
using System.Threading.Tasks;
9+
using FluentAssertions;
10+
using Xunit;
11+
12+
namespace Proto.Tests;
13+
14+
// actor that stashes first string message and processes it when Receive is called
15+
public class StashingActor : IActor
16+
{
17+
private readonly List<string> _processed;
18+
private CapturedContext? _captured;
19+
private bool _stashed;
20+
21+
public StashingActor(List<string> processed)
22+
{
23+
_processed = processed;
24+
}
25+
26+
public Task ReceiveAsync(IContext context)
27+
{
28+
return context.Message switch
29+
{
30+
string msg when msg == "unstash" => HandleUnstash(),
31+
string msg => HandleString(msg, context),
32+
_ => Task.CompletedTask
33+
};
34+
35+
Task HandleUnstash()
36+
{
37+
return _captured?.Receive() ?? Task.CompletedTask;
38+
}
39+
40+
Task HandleString(string msg, IContext ctx)
41+
{
42+
if (!_stashed)
43+
{
44+
_captured = ctx.Capture();
45+
_stashed = true;
46+
return Task.CompletedTask; // do not process yet
47+
}
48+
49+
_processed.Add(msg); // processed on replay
50+
return Task.CompletedTask;
51+
}
52+
}
53+
}
54+
55+
// actor used to test Apply()
56+
public class ApplyActor : IActor
57+
{
58+
private readonly List<string> _observed;
59+
private CapturedContext? _captured;
60+
61+
public bool ContextCorrupted { get; private set; }
62+
63+
public ApplyActor(List<string> observed) => _observed = observed;
64+
65+
public Task ReceiveAsync(IContext context)
66+
{
67+
return context.Message switch
68+
{
69+
string msg when msg == "stash" => HandleStash(context),
70+
string msg when msg == "apply" => HandleApply(context),
71+
_ => Task.CompletedTask
72+
};
73+
74+
Task HandleStash(IContext ctx)
75+
{
76+
_captured = ctx.Capture();
77+
return Task.CompletedTask;
78+
}
79+
80+
Task HandleApply(IContext ctx)
81+
{
82+
var current = ctx.Capture(); // capture current context
83+
84+
_captured?.Apply(); // restore stashed envelope
85+
_observed.Add(ctx.Message?.ToString() ?? string.Empty); // record restored message
86+
87+
current.Apply(); // restore current message
88+
if (!Equals(ctx.Message, current.MessageEnvelope.Message))
89+
{
90+
ContextCorrupted = true;
91+
}
92+
93+
_observed.Add(ctx.Message?.ToString() ?? string.Empty); // record current message after restore
94+
95+
return Task.CompletedTask;
96+
}
97+
}
98+
}
99+
100+
public class StashingTests
101+
{
102+
[Fact]
103+
public async Task Replayed_message_is_processed_only_once()
104+
{
105+
var system = new ActorSystem();
106+
await using var _ = system;
107+
var processed = new List<string>();
108+
109+
var props = Props.FromProducer(() => new StashingActor(processed));
110+
var pid = system.Root.Spawn(props);
111+
112+
system.Root.Send(pid, "hello"); // stashed
113+
processed.Should().BeEmpty();
114+
115+
system.Root.Send(pid, "unstash");
116+
await system.Root.PoisonAsync(pid);
117+
118+
processed.Should().BeEquivalentTo(new[] { "hello" });
119+
}
120+
121+
[Fact]
122+
public async Task Apply_restores_message_without_corrupting_context()
123+
{
124+
var system = new ActorSystem();
125+
await using var _ = system;
126+
var processed = new List<string>();
127+
ApplyActor? actor = null;
128+
129+
var props = Props.FromProducer(() => actor = new ApplyActor(processed));
130+
var pid = system.Root.Spawn(props);
131+
132+
system.Root.Send(pid, "stash");
133+
system.Root.Send(pid, "apply");
134+
135+
await system.Root.PoisonAsync(pid);
136+
137+
processed.Should().BeEquivalentTo(new[] { "stash", "apply" });
138+
actor!.ContextCorrupted.Should().BeFalse();
139+
}
140+
}
141+

0 commit comments

Comments
 (0)