Skip to content

Commit abee7c2

Browse files
condronjoshkempner
authored andcommitted
Remove IsModelVersion and replace with AtLeastModelVersion due to test instability.
Replace Await with thread sleep in EvaluateAfterDelay
1 parent 3fea388 commit abee7c2

File tree

3 files changed

+38
-64
lines changed

3 files changed

+38
-64
lines changed

src/ReactiveDomain.Foundation.Tests/when_using_read_model_base.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void can_start_streams_by_aggregate()
6262
var s1 = Namer.GenerateForAggregate(typeof(TestAggregate), aggId);
6363
AppendEvents(1, _conn, s1, 7);
6464
Start<TestAggregate>(aggId);
65-
AssertEx.IsModelVersion(this, 2, 1000, msg: $"Expected 2 got {Version}"); // 1 message + CatchupSubscriptionBecameLive
65+
AssertEx.AtLeastModelVersion(this, 2, 1000, msg: $"Expected 2 got {Version}"); // 1 message + CatchupSubscriptionBecameLive
6666
AssertEx.IsOrBecomesTrue(() => Sum == 7);
6767
}
6868
[Fact]
@@ -75,14 +75,14 @@ public void can_start_streams_by_aggregate_category()
7575
AppendEvents(1, _conn, s2, 5);
7676
Start<ReadModelTestCategoryAggregate>(null, true);
7777

78-
AssertEx.IsModelVersion(this, 3, 1000, msg: $"Expected 3 got {Version}");
78+
AssertEx.AtLeastModelVersion(this, 3, 1000, msg: $"Expected 3 got {Version}");
7979
AssertEx.IsOrBecomesTrue(() => Sum == 12);
8080
}
8181
[Fact]
8282
public void can_read_one_stream()
8383
{
8484
Start(_stream1);
85-
AssertEx.IsModelVersion(this, 11, 1000, msg: $"Expected 11 got {Version}");
85+
AssertEx.AtLeastModelVersion(this, 11, 1000, msg: $"Expected 11 got {Version}");
8686
AssertEx.IsOrBecomesTrue(() => Sum == 20);
8787
//confirm checkpoints
8888
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -93,7 +93,7 @@ public void can_read_two_streams()
9393
{
9494
Start(_stream1);
9595
Start(_stream2);
96-
AssertEx.IsModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
96+
AssertEx.AtLeastModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
9797
AssertEx.IsOrBecomesTrue(() => Sum == 50);
9898
//confirm checkpoints
9999
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -105,29 +105,29 @@ public void can_read_two_streams()
105105
public void can_wait_for_one_stream_to_go_live()
106106
{
107107
Start(_stream1, null, true);
108-
AssertEx.IsModelVersion(this, 11, 100, msg: $"Expected 11 got {Version}");
108+
AssertEx.AtLeastModelVersion(this, 11, 100, msg: $"Expected 11 got {Version}");
109109
AssertEx.IsOrBecomesTrue(() => Sum == 20, 100);
110110
}
111111
[Fact]
112112
public void can_wait_for_two_streams_to_go_live()
113113
{
114114
Start(_stream1, null, true);
115-
AssertEx.IsModelVersion(this, 11, 100, msg: $"Expected 11 got {Version}");
116-
AssertEx.IsOrBecomesTrue(() => Sum == 20, 100);
115+
AssertEx.AtLeastModelVersion(this, 11, 100, msg: $"Expected 11 got {Version}");
116+
AssertEx.IsOrBecomesTrue(() => Sum == 20, 150);
117117

118118
Start(_stream2, null, true);
119-
AssertEx.IsModelVersion(this, 21, 100, msg: $"Expected 21 got {Version}");
119+
AssertEx.AtLeastModelVersion(this, 21, 100, msg: $"Expected 21 got {Version}");
120120
AssertEx.IsOrBecomesTrue(() => Sum == 50, 150);
121121
}
122122
[Fact]
123123
public void can_listen_to_one_stream()
124124
{
125125
Start(_stream1);
126-
AssertEx.IsModelVersion(this, 11, 1000, msg: $"Expected 11 got {Version}");
126+
AssertEx.AtLeastModelVersion(this, 11, 1000, msg: $"Expected 11 got {Version}");
127127
AssertEx.IsOrBecomesTrue(() => Sum == 20);
128128
//add more messages
129129
AppendEvents(10, _conn, _stream1, 5);
130-
AssertEx.IsModelVersion(this, 21, 1000, msg: $"Expected 21 got {Version}");
130+
AssertEx.AtLeastModelVersion(this, 21, 1000, msg: $"Expected 21 got {Version}");
131131
AssertEx.IsOrBecomesTrue(() => Sum == 70);
132132
//confirm checkpoints
133133
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -139,12 +139,12 @@ public void can_listen_to_two_streams()
139139
{
140140
Start(_stream1);
141141
Start(_stream2);
142-
AssertEx.IsModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
142+
AssertEx.AtLeastModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
143143
AssertEx.IsOrBecomesTrue(() => Sum == 50);
144144
//add more messages
145145
AppendEvents(10, _conn, _stream1, 5);
146146
AppendEvents(10, _conn, _stream2, 7);
147-
AssertEx.IsModelVersion(this, 42, 1000, msg: $"Expected 42 got {Version}");
147+
AssertEx.AtLeastModelVersion(this, 42, 1000, msg: $"Expected 42 got {Version}");
148148
AssertEx.IsOrBecomesTrue(() => Sum == 170);
149149
//confirm checkpoints
150150
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -161,11 +161,11 @@ public void can_use_checkpoint_on_one_stream()
161161
//start at the checkpoint
162162
Start(_stream1, checkPoint);
163163
//add the one recorded event
164-
AssertEx.IsModelVersion(this, 2, 100, msg: $"Expected 2 got {Version}");
164+
AssertEx.AtLeastModelVersion(this, 2, 100, msg: $"Expected 2 got {Version}");
165165
AssertEx.IsOrBecomesTrue(() => Sum == 20);
166166
//add more messages
167167
AppendEvents(10, _conn, _stream1, 5);
168-
AssertEx.IsModelVersion(this, 12, 100, msg: $"Expected 12 got {Version}");
168+
AssertEx.AtLeastModelVersion(this, 12, 100, msg: $"Expected 12 got {Version}");
169169
AssertEx.IsOrBecomesTrue(() => Sum == 70);
170170
//confirm checkpoints
171171
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -181,12 +181,12 @@ public void can_use_checkpoint_on_two_streams()
181181
Start(_stream1, checkPoint1);
182182
Start(_stream2, checkPoint2);
183183
//add the recorded events 2 on stream 1 & 5 on stream 2
184-
AssertEx.IsModelVersion(this, 7, 1000, msg: $"Expected 7 got {Version}");
184+
AssertEx.AtLeastModelVersion(this, 7, 1000, msg: $"Expected 7 got {Version}");
185185
AssertEx.IsOrBecomesTrue(() => Sum == 50, msg: $"Expected 50 got {Sum}");
186186
//add more messages
187187
AppendEvents(10, _conn, _stream1, 5);
188188
AppendEvents(10, _conn, _stream2, 7);
189-
AssertEx.IsModelVersion(this, 27, 1000, msg: $"Expected 27 got {Version}");
189+
AssertEx.AtLeastModelVersion(this, 27, 1000, msg: $"Expected 27 got {Version}");
190190
AssertEx.IsOrBecomesTrue(() => Sum == 170);
191191
//confirm checkpoints
192192
Assert.Equal(_stream1, GetCheckpoint()[0].Item1);
@@ -203,11 +203,11 @@ public void can_listen_to_the_same_stream_twice()
203203
Start(_stream1);
204204
Start(_stream1);
205205
//double events
206-
AssertEx.IsModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
206+
AssertEx.AtLeastModelVersion(this, 22, 1000, msg: $"Expected 22 got {Version}");
207207
AssertEx.IsOrBecomesTrue(() => Sum == 40);
208208
//even more doubled events
209209
AppendEvents(10, _conn, _stream1, 5);
210-
AssertEx.IsModelVersion(this, 42, 2000, msg: $"Expected 42 got {Version}");
210+
AssertEx.AtLeastModelVersion(this, 42, 2000, msg: $"Expected 42 got {Version}");
211211
AssertEx.IsOrBecomesTrue(() => Sum == 140);
212212
}
213213

src/ReactiveDomain.Testing/AssertEx.cs

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,31 @@ public static void ArraySegmentEqual<T>(
4747
/// Repeatedly evaluates the function until false is returned or the timeout expires.
4848
/// Will return immediately when the condition is false.
4949
/// Evaluates the condition on an exponential back off up to 250 ms until timeout.
50-
/// Will yield the thread after each evaluation, use the hint yieldThread if it is known the function should yield before evaluation.
50+
/// Will yield the thread after each evaluation.
5151
/// </summary>
5252
/// <param name="func">The function to evaluate.</param>
5353
/// <param name="timeout">A timeout in milliseconds. If not specified, defaults to 1000.</param>
5454
/// <param name="msg">A message to display if the condition is not satisfied.</param>
55-
/// <param name="yieldThread">Execution hint to yield thread before evaluation</param>
55+
/// <param name="yieldThread">Ignored, will be removed in a future release</param>
5656
public static void IsOrBecomesFalse(Func<bool> func, int? timeout = null, string msg = null, bool yieldThread = false)
5757
{
58-
IsOrBecomesTrue(() => !func(), timeout, msg, yieldThread);
58+
IsOrBecomesTrue(() => !func(), timeout, msg);
5959
}
6060

6161
/// <summary>
6262
/// Asserts the given function will return true before the timeout expires.
6363
/// Repeatedly evaluates the function until true is returned or the timeout expires.
6464
/// Will return immediately when the condition is true.
6565
/// Evaluates the condition on an exponential back off up to 250 ms until timeout.
66-
/// Will yield the thread after each evaluation, use the hint yieldThread if it is known the function should yield before evaluation.
66+
/// Will yield the thread after each evaluation.
6767
/// </summary>
6868
/// <param name="func">The function to evaluate.</param>
6969
/// <param name="timeout">A timeout in milliseconds. If not specified, defaults to 1000.</param>
7070
/// <param name="msg">A message to display if the condition is not satisfied.</param>
71-
/// <param name="yieldThread">Execution hint to yield thread before evaluation</param>
71+
/// <param name="yieldThread">Ignored, will be removed in a future release</param>
7272
public static void IsOrBecomesTrue(Func<bool> func, int? timeout = null, string msg = null, bool yieldThread = false)
7373
{
74-
if (!yieldThread && func() == true)
74+
if (func() == true)
7575
{
7676
Assert.True(true, msg ?? "");
7777
return;
@@ -85,67 +85,45 @@ public static void IsOrBecomesTrue(Func<bool> func, int? timeout = null, string
8585
var delay = 1;
8686
while (true)
8787
{
88-
using (var task = EvaluateAfterDelay(func, TimeSpan.FromMilliseconds(delay)))
88+
if (EvaluateAfterDelay(func, TimeSpan.FromMilliseconds(delay)))
8989
{
90-
task.Wait();
91-
if (task.Result == true)
92-
{
93-
result = true;
94-
break;
95-
}
90+
result = true;
91+
break;
9692
}
93+
9794
var now = Environment.TickCount;
9895
if ((endTime - now) <= 0) { break; }
9996
if (delay < 250)
10097
{
10198
delay = delay << 1;
102-
}
99+
}
103100
delay = Math.Min(delay, endTime - now);
104101
}
105102
Assert.True(result, msg ?? "");
106103
}
107104

108-
/// <summary>
109-
/// Asserts that the given read model will have exactly the expected version before the timeout expires.
110-
/// This can make tests fragile and should generally not be used unless the exact number of messages
111-
/// handled is critical to your tests. In most cases you should use <see cref="AtLeastModelVersion"/>
112-
/// instead.
113-
/// </summary>
114-
/// <param name="readModel">The read model.</param>
115-
/// <param name="expectedVersion">The read model's expected version.</param>
116-
/// <param name="timeout">A timeout in milliseconds. If not specified, defaults to 1000.</param>
117-
/// <param name="msg">A message to display if the condition is not satisfied.</param>
118-
/// <param name="yieldThread">If true, the thread relinquishes the remainder of its time
119-
/// slice to any thread of equal priority that is ready to run.</param>
120-
public static void IsModelVersion(ReadModelBase readModel, int expectedVersion, int? timeout = null, string msg = null, bool yieldThread = false)
121-
{
122-
IsOrBecomesTrue(() => readModel.Version == expectedVersion, timeout, msg, yieldThread);
123-
}
124-
125105
/// <summary>
126106
/// Asserts that the given read model will have at least the expected version before the
127-
/// timeout expires. This is generally preferred to <see cref="IsModelVersion"/>.
107+
/// timeout expires. If a test needs to check an exact model version use 'IsOrBecomesTrue(()=> ReadModel.Version == [expectedVersion], [timeout])'.
128108
/// </summary>
129109
/// <param name="readModel">The read model.</param>
130110
/// <param name="expectedVersion">The read model's expected minimum version.</param>
131111
/// <param name="timeout">A timeout in milliseconds. If not specified, defaults to 1000.</param>
132112
/// <param name="msg">A message to display if the condition is not satisfied.</param>
133-
/// <param name="yieldThread">If true, the thread relinquishes the remainder of its time
134-
/// slice to any thread of equal priority that is ready to run.</param>
135-
public static void AtLeastModelVersion(ReadModelBase readModel, int expectedVersion, int? timeout = null, string msg = null, bool yieldThread = false)
113+
public static void AtLeastModelVersion(ReadModelBase readModel, int expectedVersion, int? timeout = null, string msg = null)
136114
{
137-
IsOrBecomesTrue(() => readModel.Version >= expectedVersion, timeout, msg, yieldThread);
115+
IsOrBecomesTrue(() => readModel.Version >= expectedVersion, timeout, msg);
138116
}
117+
139118
/// <summary>
140119
/// Evaluates the given function after the supplied delay.
141120
/// The current thread will yield at the start of the delay.
142121
/// </summary>
143122
/// <param name="func">The function to evaluate.</param>
144123
/// <param name="delay">A delay timeSpan.</param>
145-
/// <param name="cancellationToken">A token to cancel evaluation, TaskCanceledException will be thrown.</param>
146-
public static async Task<bool> EvaluateAfterDelay(Func<bool> func, TimeSpan delay, CancellationToken cancellationToken = default)
124+
public static bool EvaluateAfterDelay(Func<bool> func, TimeSpan delay)
147125
{
148-
await Task.Delay(delay, cancellationToken);
126+
Thread.Sleep(delay);
149127
return func();
150128
}
151129
}

src/ReactiveDomain.Testing/Specifications/TestQueue.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,11 @@ public void WaitForMultiple<T>(uint num, TimeSpan timeout) where T : IMessage
126126
var endTime = startTime + (int)timeout.TotalMilliseconds;
127127

128128
var delay = 1;
129-
while (true)
129+
//Evaluating the entire queue is a bit heavy, but is required to support waiting on base types, interfaces, etc.
130+
while (!AssertEx.EvaluateAfterDelay(() => Messages.Count(x => x is T) >= num, TimeSpan.FromMilliseconds(delay)))
130131
{
131132
if (_disposed) { throw new ObjectDisposedException(nameof(TestQueue)); }
132-
//Evaluating the entire queue is a bit heavy, but is required to support waiting on base types, interfaces, etc.
133-
using (var task = AssertEx.EvaluateAfterDelay(() => Messages.Count(x => x is T) >= num, TimeSpan.FromMilliseconds(delay)))
134-
{
135-
task.Wait();
136-
if (task.Result == true) { break; }
137-
}
133+
138134
var now = Environment.TickCount;
139135
if ((endTime - now) <= 0) { throw new TimeoutException(); }
140136

0 commit comments

Comments
 (0)