@@ -41,10 +41,13 @@ public void Dispose()
4141 }
4242
4343 [ Theory ]
44- [ InlineData ( WorkType . Async ) ]
45- [ InlineData ( WorkType . Sync ) ]
46- public void ShouldBeAbleToScheduleWorkToRepeatAtAFixedInterval ( WorkType workType )
44+ [ InlineData ( WorkType . Async , ActorScheduleOptions . Default ) ]
45+ [ InlineData ( WorkType . Async , ActorScheduleOptions . NoInitialDelay ) ]
46+ [ InlineData ( WorkType . Sync , ActorScheduleOptions . Default ) ]
47+ [ InlineData ( WorkType . Sync , ActorScheduleOptions . NoInitialDelay ) ]
48+ public void ShouldBeAbleToScheduleWorkToRepeatAtAFixedInterval ( WorkType workType , ActorScheduleOptions actorScheduleOptions )
4749 {
50+ var barrier = new TaskCompletionSource < bool > ( ) ;
4851 var expectedInterval = TimeSpan . FromMilliseconds ( 100 ) ;
4952 var times = new List < DateTime > ( ) ;
5053 var sampleSize = 5 ;
@@ -56,23 +59,27 @@ public void ShouldBeAbleToScheduleWorkToRepeatAtAFixedInterval(WorkType workType
5659 {
5760 times . Add ( DateTime . UtcNow ) ;
5861 }
62+
63+ if ( times . Count == sampleSize )
64+ {
65+ // Block here so that we can assess something that's not moving
66+ barrier . Task . Wait ( ) ;
67+ }
5968 } ;
6069
6170 switch ( workType )
6271 {
6372 case WorkType . Sync :
64- {
65- _scheduler . Schedule ( adder , expectedInterval ) ;
66- }
73+ _scheduler . Schedule ( adder , expectedInterval , actorScheduleOptions ) ;
6774 break ;
6875 case WorkType . Async :
69- {
7076 _scheduler . Schedule ( async ( ) =>
7177 {
7278 await Task . Yield ( ) ;
7379 adder ( ) ;
74- } , expectedInterval ) ;
75- }
80+ } ,
81+ expectedInterval ,
82+ actorScheduleOptions ) ;
7683 break ;
7784 default :
7885 throw new Exception ( $ "Unhandled test case { workType } .") ;
@@ -82,47 +89,15 @@ public void ShouldBeAbleToScheduleWorkToRepeatAtAFixedInterval(WorkType workType
8289
8390 var actualIntervals = times . Take ( sampleSize - 1 ) . Zip ( times . Skip ( 1 ) , ( x , y ) => y - x ) . ToList ( ) ;
8491
85- actualIntervals . Should ( ) . OnlyContain ( x => Math . Abs ( ( expectedInterval - x ) . TotalMilliseconds ) < 30 ) ;
86- }
92+ actualIntervals . Should ( ) . OnlyContain ( x => x >= expectedInterval ) ;
8793
88- [ Theory ]
89- [ InlineData ( WorkType . Async ) ]
90- [ InlineData ( WorkType . Sync ) ]
91- public void ShouldBeAbleToScheduleWorkToStartImmediatelyBeforeRepeatingAtIntervals ( WorkType workType )
92- {
93- var expectedInterval = TimeSpan . FromMilliseconds ( 5000 ) ;
94- var scheduleTime = DateTime . UtcNow ;
95- DateTime ? firstWork = null ;
96-
97- switch ( workType )
98- {
99- case WorkType . Sync :
100- _scheduler . Schedule ( ( ) =>
101- {
102- if ( ! firstWork . HasValue )
103- {
104- firstWork = DateTime . UtcNow ;
105- }
106- } , expectedInterval , ActorScheduleOptions . NoInitialDelay ) ;
107- break ;
108- case WorkType . Async :
109- _scheduler . Schedule ( async ( ) =>
110- {
111- await Task . Yield ( ) ;
112-
113- if ( ! firstWork . HasValue )
114- {
115- firstWork = DateTime . UtcNow ;
116- }
117- } , expectedInterval , ActorScheduleOptions . NoInitialDelay ) ;
118- break ;
119- default :
120- throw new Exception ( $ "Unhandled test case { workType } .") ;
121- }
94+ var expectedNumberOfDelays = sampleSize - ( actorScheduleOptions . HasFlag ( ActorScheduleOptions . NoInitialDelay ) ? 1 : 0 ) ;
12295
123- Within . FiveSeconds ( ( ) => firstWork . HasValue . Should ( ) . BeTrue ( ) ) ;
96+ Expect . That ( ( ) => Mock . Get ( _actorTaskFactory )
97+ . Verify ( x => x . CreateDelay ( expectedInterval , It . IsAny < CancellationToken > ( ) ) , Times . Exactly ( expectedNumberOfDelays ) ) )
98+ . ShouldNotThrow ( ) ;
12499
125- ( firstWork . Value - scheduleTime ) . Should ( ) . BeLessThan ( TimeSpan . FromMilliseconds ( 1000 ) ) ;
100+ barrier . SetResult ( true ) ;
126101 }
127102
128103 [ Fact ]
@@ -193,19 +168,21 @@ public void ASecondCallToScheduleShouldCancelTheWorkPreviouslyScheduled(WorkType
193168 var output = new List < string > ( ) ;
194169 var interval = TimeSpan . FromMilliseconds ( 100 ) ;
195170 var task1 = default ( Task ) ;
196- var haveThreeTwos = new TaskCompletionSource < bool > ( ) ;
171+ var firstTwoAddedPromise = new TaskCompletionSource < bool > ( ) ;
172+ var gotAOneAfterATwoPromise = new TaskCompletionSource < bool > ( ) ;
197173
198174 Action < string > adder =
199175 x =>
200176 {
201- if ( ! haveThreeTwos . Task . IsCompleted )
202- {
203- output . Add ( x ) ;
177+ output . Add ( x ) ;
204178
205- if ( output . Count ( y => y == "two" ) == 3 )
206- {
207- haveThreeTwos . SetResult ( true ) ;
208- }
179+ if ( x == "two" )
180+ {
181+ firstTwoAddedPromise . TrySetResult ( true ) ;
182+ }
183+ else if ( firstTwoAddedPromise . Task . IsCompleted && x == "one" )
184+ {
185+ gotAOneAfterATwoPromise . TrySetResult ( true ) ;
209186 }
210187 } ;
211188
@@ -243,11 +220,9 @@ public void ASecondCallToScheduleShouldCancelTheWorkPreviouslyScheduled(WorkType
243220 throw new Exception ( $ "Unhandled test case { workType2 } .") ;
244221 }
245222
246- haveThreeTwos . Task . AwaitingShouldCompleteIn ( TimeSpan . FromSeconds ( 5 ) ) ;
247-
248- var firstTwoIndex = output . IndexOf ( "two" ) ;
223+ firstTwoAddedPromise . Task . AwaitingShouldCompleteIn ( TimeSpan . FromSeconds ( 5 ) ) ;
249224
250- output . Skip ( firstTwoIndex ) . Should ( ) . OnlyContain ( x => x == "two" ) ;
225+ For . OneSecond ( ( ) => gotAOneAfterATwoPromise . Task . IsCompleted . Should ( ) . BeFalse ( "The first bit of work is still being scheduled." ) ) ;
251226
252227 task1 . IsCanceled . Should ( ) . BeTrue ( ) ;
253228 }
@@ -313,7 +288,6 @@ public void WhenAnUnhandledErrorOccursInTheWorkTheScheduleShouldStopAndEmitTheEr
313288 switch ( workType )
314289 {
315290 case WorkType . Sync :
316- {
317291 task = _scheduler . Schedule ( ( ) =>
318292 {
319293 times . Add ( DateTime . UtcNow ) ;
@@ -323,21 +297,18 @@ public void WhenAnUnhandledErrorOccursInTheWorkTheScheduleShouldStopAndEmitTheEr
323297 throw new Exception ( "Pah!" ) ;
324298 }
325299 } , interval , ActorScheduleOptions . NoInitialDelay ) ;
326- }
327300 break ;
328301 case WorkType . Async :
329- {
330302 task = _scheduler . Schedule ( async ( ) =>
331303 {
332304 times . Add ( DateTime . UtcNow ) ;
333305 await Task . Yield ( ) ;
334-
306+
335307 if ( times . Count == 3 )
336308 {
337309 throw new Exception ( "Pah!" ) ;
338310 }
339311 } , interval , ActorScheduleOptions . NoInitialDelay ) ;
340- }
341312 break ;
342313 default :
343314 throw new Exception ( $ "Unhandled test case { workType } .") ;
0 commit comments