]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/tests/CKKSNearFutureSchedulerTests.m
Security-58286.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 #include <dispatch/dispatch.h>
25 #import <XCTest/XCTest.h>
26 #import "keychain/ckks/CKKSNearFutureScheduler.h"
27 #import "keychain/ckks/CKKSResultOperation.h"
28
29 @interface CKKSNearFutureSchedulerTests : XCTestCase
30 @property NSOperationQueue* operationQueue;
31 @end
32
33 @implementation CKKSNearFutureSchedulerTests
34
35 - (void)setUp {
36 [super setUp];
37
38 self.operationQueue = [[NSOperationQueue alloc] init];
39 }
40
41 - (void)tearDown {
42 [super tearDown];
43 }
44
45 #pragma mark - Block-based tests
46
47 - (void)testBlockOneShot {
48 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
49
50 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true block:^{
51 [expectation fulfill];
52 }];
53
54 [scheduler trigger];
55
56 [self waitForExpectationsWithTimeout:1 handler:nil];
57 }
58
59 - (void)testBlockOneShotDelay {
60 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
61 toofastexpectation.inverted = YES;
62
63 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
64
65 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false block:^{
66 [toofastexpectation fulfill];
67 [expectation fulfill];
68 }];
69
70 [scheduler trigger];
71
72 // Make sure it waits at least 0.1 seconds
73 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
74
75 // But finishes within 1.1s (total)
76 [self waitForExpectations: @[expectation] timeout:1];
77 }
78
79 - (void)testBlockOneShotManyTrigger {
80 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
81 toofastexpectation.inverted = YES;
82
83 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
84 expectation.assertForOverFulfill = YES;
85
86 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true block:^{
87 [toofastexpectation fulfill];
88 [expectation fulfill];
89 }];
90
91 [scheduler trigger];
92 [scheduler trigger];
93 [scheduler trigger];
94 [scheduler trigger];
95 [scheduler trigger];
96 [scheduler trigger];
97 [scheduler trigger];
98 [scheduler trigger];
99
100 // Make sure it waits at least 0.1 seconds
101 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
102
103 // But finishes within .6s (total)
104 [self waitForExpectations: @[expectation] timeout:0.5];
105
106 // Ensure we don't get called again in the next 0.3 s
107 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
108 waitmore.inverted = YES;
109 [self waitForExpectations: @[waitmore] timeout: 0.3];
110 }
111
112
113 - (void)testBlockMultiShot {
114 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
115 first.assertForOverFulfill = NO;
116
117 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
118 second.expectedFulfillmentCount = 2;
119 second.assertForOverFulfill = YES;
120
121 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false block:^{
122 [first fulfill];
123 [second fulfill];
124 }];
125
126 [scheduler trigger];
127
128 [self waitForExpectations: @[first] timeout:0.4];
129
130 [scheduler trigger];
131 [scheduler trigger];
132 [scheduler trigger];
133
134 [self waitForExpectations: @[second] timeout:0.4];
135
136 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
137 waitmore.inverted = YES;
138 [self waitForExpectations: @[waitmore] timeout: 0.4];
139 }
140
141 - (void)testBlockMultiShotDelays {
142 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
143 first.assertForOverFulfill = NO;
144
145 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"];
146 longdelay.inverted = YES;
147 longdelay.expectedFulfillmentCount = 2;
148
149 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
150 second.expectedFulfillmentCount = 2;
151 second.assertForOverFulfill = YES;
152
153 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:600*NSEC_PER_MSEC keepProcessAlive:false block:^{
154 [first fulfill];
155 [longdelay fulfill];
156 [second fulfill];
157 }];
158
159 [scheduler trigger];
160
161 [self waitForExpectations: @[first] timeout:0.5];
162
163 [scheduler trigger];
164 [scheduler trigger];
165 [scheduler trigger];
166
167 // longdelay should NOT be fulfilled twice in the first 0.9 seconds
168 [self waitForExpectations: @[longdelay] timeout:0.4];
169
170 // But second should be fulfilled in the first 1.4 seconds
171 [self waitForExpectations: @[second] timeout:0.5];
172
173 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
174 waitmore.inverted = YES;
175 [self waitForExpectations: @[waitmore] timeout: 0.2];
176 }
177
178 - (void)testBlockCancel {
179 XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"];
180 cancelexpectation.inverted = YES;
181
182 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true block:^{
183 [cancelexpectation fulfill];
184 }];
185
186 [scheduler trigger];
187 [scheduler cancel];
188
189 // Make sure it does not fire in 0.5 s
190 [self waitForExpectations: @[cancelexpectation] timeout:0.2];
191 }
192
193 - (void)testBlockDelayedNoShot {
194 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
195 toofastexpectation.inverted = YES;
196
197 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{
198 [toofastexpectation fulfill];
199 }];
200
201 // Tell the scheduler to wait, but don't trigger it. It shouldn't fire.
202 [scheduler waitUntil: 50*NSEC_PER_MSEC];
203
204 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
205 }
206
207 - (void)testBlockDelayedOneShot {
208 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
209 first.assertForOverFulfill = NO;
210
211 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
212 toofastexpectation.inverted = YES;
213
214 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{
215 [first fulfill];
216 [toofastexpectation fulfill];
217 }];
218
219 [scheduler waitUntil: 150*NSEC_PER_MSEC];
220 [scheduler trigger];
221
222 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
223 [self waitForExpectations: @[first] timeout:0.5];
224 }
225
226 - (void)testBlockWaitedMultiShot {
227 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
228 first.assertForOverFulfill = NO;
229
230 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
231 toofastexpectation.expectedFulfillmentCount = 2;
232 toofastexpectation.inverted = YES;
233
234 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
235 second.expectedFulfillmentCount = 2;
236 second.assertForOverFulfill = YES;
237
238 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{
239 [first fulfill];
240 [second fulfill];
241 [toofastexpectation fulfill];
242 }];
243
244 [scheduler trigger];
245 [self waitForExpectations: @[first] timeout:0.5];
246
247 [scheduler waitUntil: 150*NSEC_PER_MSEC];
248 [scheduler trigger];
249
250 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
251 [self waitForExpectations: @[second] timeout:0.3];
252 }
253
254 #pragma mark - Operation-based tests
255
256 - (NSOperation*)operationFulfillingExpectations:(NSArray<XCTestExpectation*>*)expectations {
257 return [NSBlockOperation named:@"test" withBlock:^{
258 for(XCTestExpectation* e in expectations) {
259 [e fulfill];
260 }
261 }];
262 }
263
264 - (void)addOperationFulfillingExpectations:(NSArray<XCTestExpectation*>*)expectations scheduler:(CKKSNearFutureScheduler*)scheduler {
265 NSOperation* op = [self operationFulfillingExpectations:expectations];
266 XCTAssertNotNil(scheduler.operationDependency, "Should be an operation dependency");
267 XCTAssertTrue([scheduler.operationDependency isPending], "operation dependency shouldn't have run yet");
268 [op addDependency:scheduler.operationDependency];
269 [self.operationQueue addOperation:op];
270 }
271
272 - (void)testOperationOneShot {
273 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
274
275 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true block:^{}];
276 [self addOperationFulfillingExpectations:@[expectation] scheduler:scheduler];
277
278 [scheduler trigger];
279
280 [self waitForExpectationsWithTimeout:1 handler:nil];
281 }
282
283 - (void)testOperationOneShotDelay {
284 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
285 toofastexpectation.inverted = YES;
286
287 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
288
289 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false block:^{}];
290 [self addOperationFulfillingExpectations:@[expectation,toofastexpectation] scheduler:scheduler];
291
292 [scheduler trigger];
293
294 // Make sure it waits at least 0.1 seconds
295 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
296
297 // But finishes within 1.1s (total)
298 [self waitForExpectations: @[expectation] timeout:1];
299 }
300
301 - (void)testOperationOneShotManyTrigger {
302 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
303 toofastexpectation.inverted = YES;
304
305 XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"];
306 expectation.assertForOverFulfill = YES;
307
308 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true block:^{}];
309 [self addOperationFulfillingExpectations:@[expectation,toofastexpectation] scheduler:scheduler];
310
311 [scheduler trigger];
312 [scheduler trigger];
313 [scheduler trigger];
314 [scheduler trigger];
315 [scheduler trigger];
316 [scheduler trigger];
317 [scheduler trigger];
318 [scheduler trigger];
319
320 // Make sure it waits at least 0.1 seconds
321 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
322
323 // But finishes within .6s (total)
324 [self waitForExpectations: @[expectation] timeout:0.5];
325
326 // Ensure we don't get called again in the next 0.3 s
327 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
328 waitmore.inverted = YES;
329 [self waitForExpectations: @[waitmore] timeout: 0.3];
330 }
331
332
333 - (void)testOperationMultiShot {
334 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
335
336 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
337
338 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false block:^{}];
339
340 [self addOperationFulfillingExpectations:@[first] scheduler:scheduler];
341
342 [scheduler trigger];
343
344 [self waitForExpectations: @[first] timeout:0.2];
345
346 [self addOperationFulfillingExpectations:@[second] scheduler:scheduler];
347
348 [scheduler trigger];
349 [scheduler trigger];
350 [scheduler trigger];
351
352 [self waitForExpectations: @[second] timeout:0.2];
353
354 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
355 waitmore.inverted = YES;
356 [self waitForExpectations: @[waitmore] timeout: 0.2];
357 }
358
359 - (void)testOperationMultiShotDelays {
360 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
361
362 XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"];
363 longdelay.inverted = YES;
364 XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"];
365
366 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:300*NSEC_PER_MSEC keepProcessAlive:false block:^{}];
367
368 [self addOperationFulfillingExpectations:@[first] scheduler:scheduler];
369
370 [scheduler trigger];
371
372 [self waitForExpectations: @[first] timeout:0.2];
373
374 [self addOperationFulfillingExpectations:@[second,longdelay] scheduler:scheduler];
375
376 [scheduler trigger];
377 [scheduler trigger];
378 [scheduler trigger];
379
380 // longdelay shouldn't be fulfilled in the first 0.2 seconds
381 [self waitForExpectations: @[longdelay] timeout:0.2];
382
383 // But second should be fulfilled in the next 0.5 seconds
384 [self waitForExpectations: @[second] timeout:0.5];
385
386 XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"];
387 waitmore.inverted = YES;
388 [self waitForExpectations: @[waitmore] timeout: 0.2];
389 }
390
391 - (void)testOperationCancel {
392 XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"];
393 cancelexpectation.inverted = YES;
394
395 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true block:^{}];
396
397 [self addOperationFulfillingExpectations:@[cancelexpectation] scheduler:scheduler];
398
399 [scheduler trigger];
400 [scheduler cancel];
401
402 // Make sure it does not fire in 0.5 s
403 [self waitForExpectations: @[cancelexpectation] timeout:0.2];
404 }
405
406 - (void)testOperationDelayedNoShot {
407 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
408 toofastexpectation.inverted = YES;
409
410 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{}];
411 [self addOperationFulfillingExpectations:@[toofastexpectation] scheduler:scheduler];
412
413 // Tell the scheduler to wait, but don't trigger it. It shouldn't fire.
414 [scheduler waitUntil: 50*NSEC_PER_MSEC];
415
416 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
417 }
418
419 - (void)testOperationDelayedOneShot {
420 XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"];
421 first.assertForOverFulfill = NO;
422
423 XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"];
424 toofastexpectation.inverted = YES;
425
426 CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{}];
427 [self addOperationFulfillingExpectations:@[first,toofastexpectation] scheduler:scheduler];
428
429 [scheduler waitUntil: 150*NSEC_PER_MSEC];
430 [scheduler trigger];
431
432 [self waitForExpectations: @[toofastexpectation] timeout:0.1];
433 [self waitForExpectations: @[first] timeout:0.5];
434 }
435
436 @end