]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/tests/CKKSNearFutureSchedulerTests.m
Security-59306.41.2.tar.gz
[apple/security.git] / keychain / ckks / tests / CKKSNearFutureSchedulerTests.m
1 /*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #if OCTAGON
25
26 #include <dispatch/dispatch.h>
27 #import <XCTest/XCTest.h>
28 #import "keychain/ckks/CKKSNearFutureScheduler.h"
29 #import "keychain/ckks/CKKSResultOperation.h"
30 #import "keychain/ckks/CKKS.h"
31
32 @interface CKKSNearFutureSchedulerTests : XCTestCase
33 @property NSOperationQueue* operationQueue;
34 @end
35
36 @implementation CKKSNearFutureSchedulerTests
37
38 - (void)setUp {
39 [super setUp];
40
41 self.operationQueue = [[NSOperationQueue alloc] init];
42 }
43
44 - (void)tearDown {
45 [super tearDown];
46 }
47
48 #pragma mark - Block-based tests
49
50 - (void)testBlockOneShot {
51 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
52
53 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true
54 dependencyDescriptionCode:CKKSResultDescriptionNone
55 block:^{
56 [expectation fulfill];
57 }];
58
59 [scheduler trigger];
60
61 [self waitForExpectationsWithTimeout:1 handler:nil];
62 }
63
64 - (void)testBlockOneShotDelay {
65 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
66 toofastexpectation.inverted = YES;
67
68 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
69
70 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false
71 dependencyDescriptionCode:CKKSResultDescriptionNone
72 block:^{
73 [toofastexpectation fulfill];
74 [expectation fulfill];
75 }];
76
77 [scheduler trigger];
78
79 // Make sure it waits at least 0.1 seconds
80 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
81
82 // But finishes within 1.1s (total)
83 [self waitForExpectations: @[expectation] timeout:1];
84 }
85
86 - (void)testBlockOneShotManyTrigger {
87 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
88 toofastexpectation.inverted = YES;
89
90 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
91 expectation.assertForOverFulfill = YES;
92
93 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true
94 dependencyDescriptionCode:CKKSResultDescriptionNone
95 block:^{
96 [toofastexpectation fulfill];
97 [expectation fulfill];
98 }];
99
100 [scheduler trigger];
101 [scheduler trigger];
102 [scheduler trigger];
103 [scheduler trigger];
104 [scheduler trigger];
105 [scheduler trigger];
106 [scheduler trigger];
107 [scheduler trigger];
108
109 // Make sure it waits at least 0.1 seconds
110 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
111
112 // But finishes within .6s (total)
113 [self waitForExpectations: @[expectation] timeout:0.5];
114
115 // Ensure we don't get called again in the next 0.3 s
116 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
117 waitmore.inverted = YES;
118 [self waitForExpectations: @[waitmore] timeout: 0.3];
119 }
120
121
122 - (void)testBlockMultiShot {
123 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
124 first.assertForOverFulfill = NO;
125
126 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
127 second.expectedFulfillmentCount = 2;
128 second.assertForOverFulfill = YES;
129
130 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false
131 dependencyDescriptionCode:CKKSResultDescriptionNone
132 block:^{
133 [first fulfill];
134 [second fulfill];
135 }];
136
137 [scheduler trigger];
138
139 [self waitForExpectations: @[first] timeout:0.4];
140
141 [scheduler trigger];
142 [scheduler trigger];
143 [scheduler trigger];
144
145 [self waitForExpectations: @[second] timeout:0.4];
146
147 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
148 waitmore.inverted = YES;
149 [self waitForExpectations: @[waitmore] timeout: 0.4];
150 }
151
152 - (void)testBlockMultiShotDelays {
153 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
154 first.assertForOverFulfill = NO;
155
156 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"];
157 longdelay.inverted = YES;
158 longdelay.expectedFulfillmentCount = 2;
159
160 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
161 second.expectedFulfillmentCount = 2;
162 second.assertForOverFulfill = YES;
163
164 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:600*NSEC_PER_MSEC keepProcessAlive:false
165 dependencyDescriptionCode:CKKSResultDescriptionNone
166 block:^{
167 [first fulfill];
168 [longdelay fulfill];
169 [second fulfill];
170 }];
171
172 [scheduler trigger];
173
174 [self waitForExpectations: @[first] timeout:0.5];
175
176 [scheduler trigger];
177 [scheduler trigger];
178 [scheduler trigger];
179
180 // longdelay should NOT be fulfilled twice in the first 0.9 seconds
181 [self waitForExpectations: @[longdelay] timeout:0.4];
182
183 // But second should be fulfilled in the first 1.4 seconds
184 [self waitForExpectations: @[second] timeout:0.5];
185
186 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
187 waitmore.inverted = YES;
188 [self waitForExpectations: @[waitmore] timeout: 0.2];
189 }
190
191 - (void)testBlockMultiShotDelaysWithZeroInitialDelay {
192 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
193 first.assertForOverFulfill = NO;
194
195 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"];
196 longdelay.inverted = YES;
197 longdelay.expectedFulfillmentCount = 2;
198
199 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
200 second.expectedFulfillmentCount = 2;
201 second.assertForOverFulfill = YES;
202
203 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test"
204 initialDelay:0*NSEC_PER_MSEC
205 continuingDelay:600*NSEC_PER_MSEC
206 keepProcessAlive:false
207 dependencyDescriptionCode:CKKSResultDescriptionNone
208 block:^{
209 [first fulfill];
210 [longdelay fulfill];
211 [second fulfill];
212 }];
213
214 [scheduler trigger];
215
216 // Watches can be very slow. We expect this to come back immediately, but give them a lot of slack....
217 [self waitForExpectations: @[first] timeout:0.4];
218
219 [scheduler trigger];
220 [scheduler trigger];
221 [scheduler trigger];
222
223 // longdelay should NOT be fulfilled again within 0.3 seconds of the first run
224 [self waitForExpectations: @[longdelay] timeout:0.3];
225
226 // But second should be fulfilled in the first 1.0 seconds
227 [self waitForExpectations: @[second] timeout:0.6];
228
229 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
230 waitmore.inverted = YES;
231 [self waitForExpectations: @[waitmore] timeout: 0.2];
232 }
233
234 - (void)testBlockExponentialDelays {
235 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
236 first.assertForOverFulfill = NO;
237
238 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (twice in 1s)"];
239 longdelay.inverted = YES;
240 longdelay.expectedFulfillmentCount = 2;
241 longdelay.assertForOverFulfill = NO;
242
243 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
244 second.expectedFulfillmentCount = 2;
245 second.assertForOverFulfill = NO;
246
247 XCTestExpectation *longdelay2 = [self expectationWithDescription:@"FutureScheduler fired (three in 2s)"];
248 longdelay2.inverted = YES;
249 longdelay2.expectedFulfillmentCount = 3;
250 longdelay2.assertForOverFulfill = NO;
251
252 XCTestExpectation *third = [self expectationWithDescription:@"FutureScheduler fired (three)"];
253 third.expectedFulfillmentCount = 3;
254 third.assertForOverFulfill = NO;
255
256 XCTestExpectation *final = [self expectationWithDescription:@"FutureScheduler fired (fourth)"];
257 final.expectedFulfillmentCount = 4;
258 final.assertForOverFulfill = YES;
259
260 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test"
261 initialDelay:500*NSEC_PER_MSEC
262 expontialBackoff:2
263 maximumDelay:30*NSEC_PER_SEC
264 keepProcessAlive:false
265 dependencyDescriptionCode:CKKSResultDescriptionNone
266 block:^{
267 [first fulfill];
268 [longdelay fulfill];
269 [second fulfill];
270 [longdelay2 fulfill];
271 [third fulfill];
272 [final fulfill];
273 }];
274
275 [scheduler trigger];
276
277 // first should be fulfilled in the first 0.6 seconds
278 [self waitForExpectations: @[first] timeout:0.6];
279
280 [scheduler trigger];
281
282 // longdelay should NOT be fulfilled twice in the first 1.3-1.4 seconds
283 [self waitForExpectations: @[longdelay] timeout:0.8];
284
285 // But second should be fulfilled in the first 1.6 seconds
286 [self waitForExpectations: @[second] timeout:0.3];
287
288 [scheduler trigger];
289
290 // and longdelay2 should NOT be fulfilled three times in the first 2.3-2.4 seconds
291 [self waitForExpectations: @[longdelay2] timeout:0.9];
292
293 // But third should be fulfilled in the first 3.6 seconds
294 [self waitForExpectations: @[third] timeout:1.2];
295
296 // Wait out the 4s reset delay...
297 XCTestExpectation *reset = [self expectationWithDescription:@"reset"];
298 reset.inverted = YES;
299 [self waitForExpectations: @[reset] timeout:4.2];
300
301 // and it should use a 0.5s delay after trigger
302 [scheduler trigger];
303
304 [self waitForExpectations: @[final] timeout:0.6];
305 }
306
307 - (void)testBlockCancel {
308 XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"];
309 cancelexpectation.inverted = YES;
310
311 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true
312 dependencyDescriptionCode:CKKSResultDescriptionNone
313 block:^{
314 [cancelexpectation fulfill];
315 }];
316
317 [scheduler trigger];
318 [scheduler cancel];
319
320 // Make sure it does not fire in 0.5 s
321 [self waitForExpectations: @[cancelexpectation] timeout:0.2];
322 }
323
324 - (void)testBlockDelayedNoShot {
325 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
326 toofastexpectation.inverted = YES;
327
328 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false
329 dependencyDescriptionCode:CKKSResultDescriptionNone
330 block:^{
331 [toofastexpectation fulfill];
332 }];
333
334 // Tell the scheduler to wait, but don't trigger it. It shouldn't fire.
335 [scheduler waitUntil: 50*NSEC_PER_MSEC];
336
337 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
338 }
339
340 - (void)testBlockDelayedOneShot {
341 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
342 first.assertForOverFulfill = NO;
343
344 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
345 toofastexpectation.inverted = YES;
346
347 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false
348 dependencyDescriptionCode:CKKSResultDescriptionNone
349 block:^{
350 [first fulfill];
351 [toofastexpectation fulfill];
352 }];
353
354 [scheduler waitUntil: 150*NSEC_PER_MSEC];
355 [scheduler trigger];
356
357 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
358 [self waitForExpectations: @[first] timeout:0.5];
359 }
360
361 - (void)testBlockWaitedMultiShot {
362 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
363 first.assertForOverFulfill = NO;
364
365 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
366 toofastexpectation.expectedFulfillmentCount = 2;
367 toofastexpectation.inverted = YES;
368
369 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
370 second.expectedFulfillmentCount = 2;
371 second.assertForOverFulfill = YES;
372
373 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false
374 dependencyDescriptionCode:CKKSResultDescriptionNone
375 block:^{
376 [first fulfill];
377 [second fulfill];
378 [toofastexpectation fulfill];
379 }];
380
381 [scheduler trigger];
382 [self waitForExpectations: @[first] timeout:0.5];
383
384 [scheduler waitUntil: 150*NSEC_PER_MSEC];
385 [scheduler trigger];
386
387 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
388 [self waitForExpectations: @[second] timeout:0.3];
389 }
390
391 #pragma mark - Operation-based tests
392
393 - (NSOperation*)operationFulfillingExpectations:(NSArray<XCTestExpectation*>*)expectations {
394 return [NSBlockOperation named:@"test" withBlock:^{
395 for(XCTestExpectation* e in expectations) {
396 [e fulfill];
397 }
398 }];
399 }
400
401 - (void)addOperationFulfillingExpectations:(NSArray<XCTestExpectation*>*)expectations scheduler:(CKKSNearFutureScheduler*)scheduler {
402 NSOperation* op = [self operationFulfillingExpectations:expectations];
403 XCTAssertNotNil(scheduler.operationDependency, "Should be an operation dependency");
404 XCTAssertTrue([scheduler.operationDependency isPending], "operation dependency shouldn't have run yet");
405 [op addDependency:scheduler.operationDependency];
406 [self.operationQueue addOperation:op];
407 }
408
409 - (void)testOperationOneShot {
410 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
411
412 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true
413 dependencyDescriptionCode:CKKSResultDescriptionNone
414 block:^{}];
415 [self addOperationFulfillingExpectations:@[expectation] scheduler:scheduler];
416
417 [scheduler trigger];
418
419 [self waitForExpectationsWithTimeout:1 handler:nil];
420 }
421
422 - (void)testOperationOneShotDelay {
423 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
424 toofastexpectation.inverted = YES;
425
426 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
427
428 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false
429 dependencyDescriptionCode:CKKSResultDescriptionNone
430 block:^{}];
431 [self addOperationFulfillingExpectations:@[expectation,toofastexpectation] scheduler:scheduler];
432
433 [scheduler trigger];
434
435 // Make sure it waits at least 0.1 seconds
436 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
437
438 // But finishes within 1.1s (total)
439 [self waitForExpectations: @[expectation] timeout:1];
440 }
441
442 - (void)testOperationOneShotManyTrigger {
443 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
444 toofastexpectation.inverted = YES;
445
446 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
447 expectation.assertForOverFulfill = YES;
448
449 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true
450 dependencyDescriptionCode:CKKSResultDescriptionNone
451 block:^{}];
452 [self addOperationFulfillingExpectations:@[expectation,toofastexpectation] scheduler:scheduler];
453
454 [scheduler trigger];
455 [scheduler trigger];
456 [scheduler trigger];
457 [scheduler trigger];
458 [scheduler trigger];
459 [scheduler trigger];
460 [scheduler trigger];
461 [scheduler trigger];
462
463 // Make sure it waits at least 0.1 seconds
464 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
465
466 // But finishes within .6s (total)
467 [self waitForExpectations: @[expectation] timeout:0.5];
468
469 // Ensure we don't get called again in the next 0.3 s
470 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
471 waitmore.inverted = YES;
472 [self waitForExpectations: @[waitmore] timeout: 0.3];
473 }
474
475
476 - (void)testOperationMultiShot {
477 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
478
479 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
480
481 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false
482 dependencyDescriptionCode:CKKSResultDescriptionNone
483 block:^{}];
484
485 [self addOperationFulfillingExpectations:@[first] scheduler:scheduler];
486
487 [scheduler trigger];
488
489 [self waitForExpectations: @[first] timeout:0.2];
490
491 [self addOperationFulfillingExpectations:@[second] scheduler:scheduler];
492
493 [scheduler trigger];
494 [scheduler trigger];
495 [scheduler trigger];
496
497 [self waitForExpectations: @[second] timeout:0.2];
498
499 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
500 waitmore.inverted = YES;
501 [self waitForExpectations: @[waitmore] timeout: 0.2];
502 }
503
504 - (void)testOperationMultiShotDelays {
505 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
506
507 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"];
508 longdelay.inverted = YES;
509 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
510
511 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:300*NSEC_PER_MSEC keepProcessAlive:false
512 dependencyDescriptionCode:CKKSResultDescriptionNone
513 block:^{}];
514
515 [self addOperationFulfillingExpectations:@[first] scheduler:scheduler];
516
517 [scheduler trigger];
518
519 [self waitForExpectations: @[first] timeout:0.2];
520
521 [self addOperationFulfillingExpectations:@[second,longdelay] scheduler:scheduler];
522
523 [scheduler trigger];
524 [scheduler trigger];
525 [scheduler trigger];
526
527 // longdelay shouldn't be fulfilled in the first 0.2 seconds
528 [self waitForExpectations: @[longdelay] timeout:0.2];
529
530 // But second should be fulfilled in the next 0.5 seconds
531 [self waitForExpectations: @[second] timeout:0.5];
532
533 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
534 waitmore.inverted = YES;
535 [self waitForExpectations: @[waitmore] timeout: 0.2];
536 }
537
538 - (void)testOperationCancel {
539 XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"];
540 cancelexpectation.inverted = YES;
541
542 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true
543 dependencyDescriptionCode:CKKSResultDescriptionNone
544 block:^{}];
545
546 [self addOperationFulfillingExpectations:@[cancelexpectation] scheduler:scheduler];
547
548 [scheduler trigger];
549 [scheduler cancel];
550
551 // Make sure it does not fire in 0.5 s
552 [self waitForExpectations: @[cancelexpectation] timeout:0.2];
553 }
554
555 - (void)testOperationDelayedNoShot {
556 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
557 toofastexpectation.inverted = YES;
558
559 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false
560 dependencyDescriptionCode:CKKSResultDescriptionNone
561 block:^{}];
562 [self addOperationFulfillingExpectations:@[toofastexpectation] scheduler:scheduler];
563
564 // Tell the scheduler to wait, but don't trigger it. It shouldn't fire.
565 [scheduler waitUntil: 50*NSEC_PER_MSEC];
566
567 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
568 }
569
570 - (void)testOperationDelayedOneShot {
571 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
572 first.assertForOverFulfill = NO;
573
574 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
575 toofastexpectation.inverted = YES;
576
577 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false
578 dependencyDescriptionCode:CKKSResultDescriptionNone
579 block:^{}];
580 [self addOperationFulfillingExpectations:@[first,toofastexpectation] scheduler:scheduler];
581
582 [scheduler waitUntil: 150*NSEC_PER_MSEC];
583 [scheduler trigger];
584
585 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
586 [self waitForExpectations: @[first] timeout:0.5];
587 }
588
589 - (void)testChangeDelay {
590 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
591 first.assertForOverFulfill = NO;
592
593 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
594 second.expectedFulfillmentCount = 2;
595 second.assertForOverFulfill = YES;
596
597 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_SEC keepProcessAlive:false
598 dependencyDescriptionCode:CKKSResultDescriptionNone
599 block:^{
600 [first fulfill];
601 [second fulfill];
602 }];
603
604 [scheduler changeDelays:100*NSEC_PER_MSEC continuingDelay:100*NSEC_PER_MSEC];
605 [scheduler trigger];
606
607 [self waitForExpectations: @[first] timeout:0.4];
608
609 [scheduler trigger];
610 [scheduler trigger];
611 [scheduler trigger];
612
613 [self waitForExpectations: @[second] timeout:0.4];
614 }
615
616 - (void)testTriggerAtFromNoTimer {
617 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
618 first.inverted = YES;
619
620 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
621 second.assertForOverFulfill = YES;
622
623 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test"
624 delay:1*NSEC_PER_MSEC
625 keepProcessAlive:false
626 dependencyDescriptionCode:CKKSResultDescriptionNone
627 block:^{
628 [first fulfill];
629 [second fulfill];
630 }];
631
632 [scheduler triggerAt:300*NSEC_PER_MSEC];
633 [self waitForExpectations: @[first] timeout:0.1];
634 [self waitForExpectations: @[second] timeout:2];
635 }
636
637 - (void)testTriggerAtShortensTriggerDelay {
638 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
639 first.inverted = YES;
640
641 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
642 second.assertForOverFulfill = YES;
643
644 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test"
645 delay:10*NSEC_PER_SEC
646 keepProcessAlive:false
647 dependencyDescriptionCode:CKKSResultDescriptionNone
648 block:^{
649 [first fulfill];
650 [second fulfill];
651 }];
652
653 // Triggers a 10 second invocation, then invoke a triggerAt
654 [scheduler trigger];
655 [scheduler triggerAt:300*NSEC_PER_MSEC];
656
657 [self waitForExpectations: @[first] timeout:0.1];
658 [self waitForExpectations: @[second] timeout:2];
659 }
660
661 - (void)testTriggerAtLengthensTriggerDelay {
662 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
663 first.inverted = YES;
664
665 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
666 second.assertForOverFulfill = YES;
667
668 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test"
669 delay:400*NSEC_PER_MSEC
670 keepProcessAlive:false
671 dependencyDescriptionCode:CKKSResultDescriptionNone
672 block:^{
673 [first fulfill];
674 [second fulfill];
675 }];
676
677 // Triggers a 400 millisecond invocation, then invoke a triggerAt
678 [scheduler trigger];
679 [scheduler triggerAt:1*NSEC_PER_SEC];
680
681 [self waitForExpectations: @[first] timeout:0.5];
682 [self waitForExpectations: @[second] timeout:2];
683 }
684
685 @end
686
687 #endif /* OCTAGON */