17
17
using Xunit ;
18
18
using Xunit . Abstractions ;
19
19
using System . Collections . Generic ;
20
- using Akka . Actor ;
21
- using Akka . Streams . Actors ;
22
20
using Akka . Streams . TestKit . Tests ;
23
- using Akka . Streams . Tests . Actor ;
24
- using Reactive . Streams ;
25
21
using System . Runtime . CompilerServices ;
26
22
using Akka . Util ;
27
23
using FluentAssertions . Extensions ;
28
24
29
25
namespace Akka . Streams . Tests . Dsl
30
26
{
31
- #if NETCOREAPP
27
+ #if ! NETFRAMEWORK // disabling this causes .NET Framework 4.7.2 builds to fail on Linux
32
28
public class AsyncEnumerableSpec : AkkaSpec
33
29
{
34
30
private ActorMaterializer Materializer { get ; }
35
31
private ITestOutputHelper _helper ;
32
+
36
33
public AsyncEnumerableSpec ( ITestOutputHelper helper ) : base (
37
34
AkkaSpecConfig . WithFallback ( StreamTestDefaultMailbox . DefaultConfig ) ,
38
35
helper )
@@ -50,7 +47,7 @@ public async Task RunAsAsyncEnumerable_Uses_CancellationToken()
50
47
51
48
var cts = new CancellationTokenSource ( ) ;
52
49
var token = cts . Token ;
53
-
50
+
54
51
var asyncEnumerable = Source . From ( input ) . RunAsAsyncEnumerable ( Materializer ) ;
55
52
var output = input . ToArray ( ) ;
56
53
bool caught = false ;
@@ -65,7 +62,7 @@ public async Task RunAsAsyncEnumerable_Uses_CancellationToken()
65
62
{
66
63
caught = true ;
67
64
}
68
-
65
+
69
66
caught . ShouldBeTrue ( ) ;
70
67
}
71
68
@@ -80,6 +77,7 @@ public async Task RunAsAsyncEnumerable_must_return_an_IAsyncEnumerableT_from_a_S
80
77
( output [ 0 ] == a ) . ShouldBeTrue ( "Did not get elements in order!" ) ;
81
78
output = output . Skip ( 1 ) . ToArray ( ) ;
82
79
}
80
+
83
81
output . Length . ShouldBe ( 0 , "Did not receive all elements!" ) ;
84
82
}
85
83
@@ -94,14 +92,16 @@ public async Task RunAsAsyncEnumerable_must_allow_multiple_enumerations()
94
92
( output [ 0 ] == a ) . ShouldBeTrue ( "Did not get elements in order!" ) ;
95
93
output = output . Skip ( 1 ) . ToArray ( ) ;
96
94
}
95
+
97
96
output . Length . ShouldBe ( 0 , "Did not receive all elements!" ) ;
98
-
97
+
99
98
output = input . ToArray ( ) ;
100
99
await foreach ( var a in asyncEnumerable )
101
100
{
102
101
( output [ 0 ] == a ) . ShouldBeTrue ( "Did not get elements in order!" ) ;
103
102
output = output . Skip ( 1 ) . ToArray ( ) ;
104
103
}
104
+
105
105
output . Length . ShouldBe ( 0 , "Did not receive all elements in second enumeration!!" ) ;
106
106
}
107
107
@@ -112,7 +112,7 @@ public async Task RunAsAsyncEnumerable_Throws_on_Abrupt_Stream_termination()
112
112
var materializer = ActorMaterializer . Create ( Sys ) ;
113
113
var probe = this . CreatePublisherProbe < int > ( ) ;
114
114
var task = Source . FromPublisher ( probe ) . RunAsAsyncEnumerable ( materializer ) ;
115
-
115
+
116
116
var a = Task . Run ( async ( ) =>
117
117
{
118
118
await foreach ( var notused in task )
@@ -140,7 +140,7 @@ public async Task RunAsAsyncEnumerable_Throws_on_Abrupt_Stream_termination()
140
140
141
141
thrown . ShouldBeTrue ( ) ;
142
142
}
143
-
143
+
144
144
[ Fact ]
145
145
public async Task RunAsAsyncEnumerable_Throws_if_materializer_gone_before_Enumeration ( )
146
146
{
@@ -155,7 +155,7 @@ async Task ShouldThrow()
155
155
{
156
156
}
157
157
}
158
-
158
+
159
159
await Assert . ThrowsAsync < IllegalStateException > ( ShouldThrow ) ;
160
160
}
161
161
@@ -187,7 +187,7 @@ public void AsyncEnumerableSource_Must_Process_All_Elements()
187
187
subscription . Request ( 101 ) ;
188
188
189
189
subscriber . ExpectNextN ( Enumerable . Range ( 0 , 100 ) ) ;
190
-
190
+
191
191
subscriber . ExpectComplete ( ) ;
192
192
}
193
193
@@ -206,7 +206,7 @@ public void AsyncEnumerableSource_Must_Process_Source_That_Immediately_Throws()
206
206
subscriber . ExpectNextN ( Enumerable . Range ( 0 , 50 ) ) ;
207
207
208
208
var exception = subscriber . ExpectError ( ) ;
209
-
209
+
210
210
// Exception should be automatically unrolled, this SHOULD NOT be AggregateException
211
211
exception . Should ( ) . BeOfType < TestException > ( ) ;
212
212
exception . Message . Should ( ) . Be ( "BOOM!" ) ;
@@ -231,13 +231,54 @@ public async Task AsyncEnumerableSource_Must_Cancel_Running_Source_If_Downstream
231
231
await WithinAsync ( 3 . Seconds ( ) , async ( ) => latch . Value ) ;
232
232
}
233
233
234
- private static async IAsyncEnumerable < int > RangeAsync ( int start , int count ,
234
+ /// <summary>
235
+ /// Reproduction for https://github.com/akkadotnet/akka.net/issues/6280
236
+ /// </summary>
237
+ [ Fact ]
238
+ public async Task AsyncEnumerableSource_BugFix6280 ( )
239
+ {
240
+ async IAsyncEnumerable < int > GenerateInts ( )
241
+ {
242
+ foreach ( var i in Enumerable . Range ( 0 , 100 ) )
243
+ {
244
+ if ( i > 50 )
245
+ await Task . Delay ( 1000 ) ;
246
+ yield return i ;
247
+ }
248
+ }
249
+
250
+ var source = Source . From ( GenerateInts ) ;
251
+ var subscriber = this . CreateManualSubscriberProbe < int > ( ) ;
252
+
253
+ await EventFilter . Warning ( ) . ExpectAsync ( 0 , async ( ) =>
254
+ {
255
+ var mat = source
256
+ . WatchTermination ( Keep . Right )
257
+ . ToMaterialized ( Sink . FromSubscriber ( subscriber ) , Keep . Left ) ;
258
+
259
+ #pragma warning disable CS4014
260
+ var task = mat . Run ( Materializer ) ;
261
+ #pragma warning restore CS4014
262
+
263
+ var subscription = subscriber . ExpectSubscription ( ) ;
264
+ subscription . Request ( 50 ) ;
265
+ subscriber . ExpectNextN ( Enumerable . Range ( 0 , 50 ) ) ;
266
+ subscription . Request ( 10 ) ; // the iterator is going to start delaying 1000ms per item here
267
+ subscription . Cancel ( ) ;
268
+
269
+
270
+ // The cancellation token inside the IAsyncEnumerable should be cancelled
271
+ await task ;
272
+ } ) ;
273
+ }
274
+
275
+ private static async IAsyncEnumerable < int > RangeAsync ( int start , int count ,
235
276
[ EnumeratorCancellation ] CancellationToken token = default )
236
277
{
237
278
foreach ( var i in Enumerable . Range ( start , count ) )
238
279
{
239
280
await Task . Delay ( 10 , token ) ;
240
- if ( token . IsCancellationRequested )
281
+ if ( token . IsCancellationRequested )
241
282
yield break ;
242
283
yield return i ;
243
284
}
@@ -248,33 +289,28 @@ private static async IAsyncEnumerable<int> ThrowingRangeAsync(int start, int cou
248
289
{
249
290
foreach ( var i in Enumerable . Range ( start , count ) )
250
291
{
251
- if ( token . IsCancellationRequested )
292
+ if ( token . IsCancellationRequested )
252
293
yield break ;
253
294
254
295
if ( i == throwAt )
255
296
throw new TestException ( "BOOM!" ) ;
256
-
297
+
257
298
yield return i ;
258
299
}
259
300
}
260
301
261
302
private static async IAsyncEnumerable < int > ProbeableRangeAsync ( int start , int count , AtomicBoolean latch ,
262
303
[ EnumeratorCancellation ] CancellationToken token = default )
263
304
{
264
- token . Register ( ( ) =>
265
- {
266
- latch . GetAndSet ( true ) ;
267
- } ) ;
305
+ token . Register ( ( ) => { latch . GetAndSet ( true ) ; } ) ;
268
306
foreach ( var i in Enumerable . Range ( start , count ) )
269
307
{
270
- if ( token . IsCancellationRequested )
308
+ if ( token . IsCancellationRequested )
271
309
yield break ;
272
310
273
311
yield return i ;
274
312
}
275
313
}
276
-
277
314
}
278
- #else
279
315
#endif
280
316
}
0 commit comments