2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #import <Foundation/Foundation.h>
28 #import <XCTest/XCTest.h>
29 #import <OCMock/OCMock.h>
31 #import "OTTestsBase.h"
33 static NSString* const testContextID = @"Foo";
34 static NSString* const testDSID = @"123456789";
36 static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer";
37 /* Octagon Trust BottledPeerSchema */
38 static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID";
39 static NSString* OTCKRecordRecordID = @"bottledPeerRecordID";
40 static NSString* OTCKRecordSPID = @"spID";
41 static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI";
42 static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI";
43 static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey";
44 static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey";
45 static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow";
46 static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey";
47 static NSString* OTCKRecordBottle = @"bottle";
49 static NSString* OTCKRecordPeerID = @"peerID";
51 @interface OTLockStateNetworkingTests : OTTestsBase
52 @property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord;
55 @implementation OTLockStateNetworkingTests
60 self.continueAfterFailure = NO;
63 OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error];
65 XCTAssertNotNil(bp, @"plaintext should not be nil");
66 XCTAssertNil(error, @"error should be nil");
67 XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil");
68 XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil");
70 OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error];
72 self.fakeBottledPeerRecord = [bpSigned asRecord:self.sosPeerID];
74 [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
85 -(void) testGrabbingBottleLocallyCheckPerfectConditions
87 [self setUpRampRecordsInCloudKitWithFeatureOn];
88 [self startCKKSSubsystem];
90 __block NSData* localEntropy = nil;
91 __block NSString* localBottleID = nil;
93 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
95 [self.otControl preflightBottledPeer:testContextID
97 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
98 [self.spiBlockExpectation fulfill];
99 localEntropy = entropy;
100 localBottleID = bottleID;
101 XCTAssertNotNil(entropy, "entropy should not be nil");
102 XCTAssertNotNil(bottleID, "bottle id should not be nil");
103 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
104 XCTAssertNil(error, "error should be nil");
106 [self waitForExpectationsWithTimeout:1.0 handler:nil];
108 self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"];
110 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
112 [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
114 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
115 [self.spiBlockExpectation fulfill];
116 XCTAssertNil(error, "error should be nil");
119 [self waitForExpectationsWithTimeout:1.0 handler:nil];
121 NSError* localError = nil;
122 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
123 XCTAssertNil(localError, "error should be nil");
126 -(void) testGrabbingBottleFromCloudKitCheckPerfectConditions
128 [self setUpRampRecordsInCloudKitWithFeatureOn];
130 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType];
131 newRecord[OTCKRecordPeerID] = self.fakeBottledPeerRecord.peerID;
132 newRecord[OTCKRecordSPID] = @"spID";
133 newRecord[OTCKRecordEscrowSigningSPKI] = self.fakeBottledPeerRecord.escrowedSigningSPKI;
134 newRecord[OTCKRecordPeerSigningSPKI] = self.fakeBottledPeerRecord.peerSigningSPKI;
135 newRecord[OTCKRecordEscrowRecordID] = self.fakeBottledPeerRecord.escrowRecordID;
136 newRecord[OTCKRecordBottle] = self.fakeBottledPeerRecord.bottle;
137 newRecord[OTCKRecordSignatureFromEscrow] = self.fakeBottledPeerRecord.signatureUsingEscrowKey;
138 newRecord[OTCKRecordSignatureFromPeerKey] = self.fakeBottledPeerRecord.signatureUsingPeerKey;
140 [self.otFakeZone addToZone:newRecord];
142 [self startCKKSSubsystem];
144 NSError* localError = nil;
145 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
146 XCTAssertNil(localError, "error should be nil");
149 -(void) testBottleCheckWhenLocked
151 NSError* error = nil;
152 self.aksLockState = true;
153 [self.lockStateTracker recheck];
154 [self setUpRampRecordsInCloudKitWithFeatureOff];
156 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
158 XCTAssertNotNil(error, "error should not be nil");
159 XCTAssertTrue(error.code == -25308, @"error should be interaction not allowed");
162 -(void) testBottleCheckWithNoNetwork
164 NSError* error = nil;
165 self.accountStatus = CKAccountStatusAvailable;
166 [self startCKKSSubsystem];
168 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
170 self.reachabilityFlags = 0;
171 [self.reachabilityTracker recheck];
172 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
173 XCTAssertTrue(error.code == OTErrorNoNetwork, @"should have returned no network error");
176 -(void) testBottleCheckWhenNotSignedIn
178 NSError* error = nil;
180 self.accountStatus = CKAccountStatusNoAccount;
181 [self startCKKSSubsystem];
183 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
185 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
186 XCTAssertTrue(error.code == OTErrorNotSignedIn, @"should have returned not signed in error");
191 -(void)testPreflightNotSignedIn
193 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
195 [self setUpRampRecordsInCloudKitWithFeatureOn];
197 self.accountStatus = CKAccountStatusNoAccount;
199 [self startCKKSSubsystem];
201 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
203 [self.otControl preflightBottledPeer:testContextID
205 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
206 [self.spiBlockExpectation fulfill];
207 XCTAssertNil(entropy, "entropy should not be nil");
208 XCTAssertNil(bottleID, "bottle id should not be nil");
209 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
210 XCTAssertTrue(error.code == OTErrorNotSignedIn, @"should have returned not signed in error");
213 [self waitForExpectationsWithTimeout:1.0 handler:nil];
217 -(void) testPreflightWithNoNetwork
219 self.accountStatus = CKAccountStatusAvailable;
220 [self startCKKSSubsystem];
222 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
224 self.reachabilityFlags = 0;
225 [self.reachabilityTracker recheck];
227 [self.otControl preflightBottledPeer:testContextID
229 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
230 [self.spiBlockExpectation fulfill];
231 XCTAssertNil(entropy, "entropy should not be nil");
232 XCTAssertNil(bottleID, "bottle id should not be nil");
233 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
234 XCTAssertTrue(error.code == OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error");
239 -(void) testPreflightWhenLocked
241 self.aksLockState = true;
242 [self.lockStateTracker recheck];
244 [self.otControl preflightBottledPeer:testContextID
246 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
247 [self.spiBlockExpectation fulfill];
248 XCTAssertNil(entropy, "entropy should not be nil");
249 XCTAssertNil(bottleID, "bottle id should not be nil");
250 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
251 XCTAssertTrue(error.code == errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error");
255 //Launch Bottle tests
256 -(void)testLaunchNotSignedIn
258 [self setUpRampRecordsInCloudKitWithFeatureOn];
260 self.accountStatus = CKAccountStatusNoAccount;
262 [self startCKKSSubsystem];
264 [self.enroll.accountTracker notifyCKAccountStatusChangeAndWaitForSignal];
265 [self.context.accountTracker notifyCKAccountStatusChangeAndWaitForSignal];
267 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
269 [self.otControl preflightBottledPeer:OTDefaultContext
271 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
272 [self.spiBlockExpectation fulfill];
273 XCTAssertNil(entropy, "shouldn't return any entropy");
274 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
275 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
276 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
278 [self waitForCKModifications];
279 OCMVerifyAllWithDelay(self.mockDatabase, 8);
280 [self waitForExpectationsWithTimeout:1.0 handler:nil];
282 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
283 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
285 NSString* localBottleID = @"random bottle id";
286 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
287 [self.spiBlockExpectation fulfill];
288 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
291 [self waitForCKModifications];
292 OCMVerifyAllWithDelay(self.mockDatabase, 8);
293 [self waitForExpectationsWithTimeout:1.0 handler:nil];
296 -(void) testLaunchWithNoNetwork
298 [self setUpRampRecordsInCloudKitWithFeatureOn];
300 self.accountStatus = CKAccountStatusAvailable;
301 [self startCKKSSubsystem];
303 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
305 self.reachabilityFlags = 0;
306 [self.reachabilityTracker recheck];
308 [self startCKKSSubsystem];
310 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
312 [self.otControl preflightBottledPeer:OTDefaultContext
314 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
315 [self.spiBlockExpectation fulfill];
316 XCTAssertNil(entropy, "shouldn't return any entropy");
317 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
318 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
319 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
321 [self waitForCKModifications];
322 OCMVerifyAllWithDelay(self.mockDatabase, 8);
323 [self waitForExpectationsWithTimeout:1.0 handler:nil];
326 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
327 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
329 NSString* localBottleID = @"random bottle id";
330 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
331 [self.spiBlockExpectation fulfill];
332 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
335 [self waitForCKModifications];
336 OCMVerifyAllWithDelay(self.mockDatabase, 8);
337 [self waitForExpectationsWithTimeout:1.0 handler:nil];
340 -(void) testLaunchWhenLocked
342 [self setUpRampRecordsInCloudKitWithFeatureOn];
344 self.aksLockState = true;
345 [self.lockStateTracker recheck];
347 [self startCKKSSubsystem];
349 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
351 [self.otControl preflightBottledPeer:OTDefaultContext
353 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
354 [self.spiBlockExpectation fulfill];
355 XCTAssertNil(entropy, "shouldn't return any entropy");
356 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
357 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
358 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
360 [self waitForCKModifications];
361 OCMVerifyAllWithDelay(self.mockDatabase, 8);
362 [self waitForExpectationsWithTimeout:1.0 handler:nil];
365 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
366 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
368 NSString* localBottleID = @"random bottle id";
369 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
370 [self.spiBlockExpectation fulfill];
371 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
374 [self waitForCKModifications];
375 OCMVerifyAllWithDelay(self.mockDatabase, 8);
376 [self waitForExpectationsWithTimeout:1.0 handler:nil];
380 -(void)testScrubNotSignedIn
382 [self setUpRampRecordsInCloudKitWithFeatureOn];
384 self.accountStatus = CKAccountStatusNoAccount;
385 [self startCKKSSubsystem];
387 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
389 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
390 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
392 [self.otControl preflightBottledPeer:testContextID
394 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
395 [self.spiBlockExpectation fulfill];
396 XCTAssertNil(entropy, "entropy should be nil");
397 XCTAssertNil(bottleID, "bottle id should be nil");
398 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
399 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
402 [self waitForExpectationsWithTimeout:1.0 handler:nil];
404 __block NSString* localBottleID = @"random bottle id";
405 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
406 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
408 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
409 [self.spiBlockExpectation fulfill];
410 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
413 [self waitForCKModifications];
414 OCMVerifyAllWithDelay(self.mockDatabase, 8);
415 [self waitForExpectationsWithTimeout:1.0 handler:nil];
419 -(void) testScrubWithNoNetwork
421 [self setUpRampRecordsInCloudKitWithFeatureOn];
423 self.accountStatus = CKAccountStatusAvailable;
424 [self startCKKSSubsystem];
426 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
428 self.reachabilityFlags = 0;
429 [self.reachabilityTracker recheck];
431 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
432 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
434 [self.otControl preflightBottledPeer:testContextID
436 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
437 [self.spiBlockExpectation fulfill];
438 XCTAssertNil(entropy, "entropy should be nil");
439 XCTAssertNil(bottleID, "bottle id should be nil");
440 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
441 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
444 [self waitForExpectationsWithTimeout:1.0 handler:nil];
446 __block NSString* localBottleID = @"random bottle id";
447 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
448 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
450 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
451 [self.spiBlockExpectation fulfill];
452 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
455 [self waitForCKModifications];
456 OCMVerifyAllWithDelay(self.mockDatabase, 8);
457 [self waitForExpectationsWithTimeout:1.0 handler:nil];
460 -(void) testScrubWhenLocked
462 [self setUpRampRecordsInCloudKitWithFeatureOn];
464 self.aksLockState = true;
465 [self.lockStateTracker recheck];
467 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
468 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
470 [self.otControl preflightBottledPeer:testContextID
472 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
473 [self.spiBlockExpectation fulfill];
474 XCTAssertNil(entropy, "entropy should be nil");
475 XCTAssertNil(bottleID, "bottle id should be nil");
476 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
477 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
480 [self waitForExpectationsWithTimeout:1.0 handler:nil];
482 __block NSString* localBottleID = @"random bottle id";
483 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
484 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
486 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
487 [self.spiBlockExpectation fulfill];
488 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
491 [self waitForCKModifications];
492 OCMVerifyAllWithDelay(self.mockDatabase, 8);
493 [self waitForExpectationsWithTimeout:1.0 handler:nil];
497 -(void)testRestoreNotSignedIn
499 [self setUpRampRecordsInCloudKitWithFeatureOn];
501 self.accountStatus = CKAccountStatusNoAccount;
502 [self startCKKSSubsystem];
504 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
506 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
507 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
509 [self.otControl restore:testContextID
512 escrowRecordID:self.sosPeerID
513 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
514 [self.spiBlockExpectation fulfill];
515 XCTAssertNil(signingKeyData, "Signing key data should be nil");
516 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
517 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
519 [self waitForCKModifications];
520 OCMVerifyAllWithDelay(self.mockDatabase, 8);
521 [self waitForExpectationsWithTimeout:1.0 handler:nil];
525 -(void) testRestoreWithNoNetwork
527 [self setUpRampRecordsInCloudKitWithFeatureOn];
529 self.accountStatus = CKAccountStatusAvailable;
530 [self startCKKSSubsystem];
532 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
534 self.reachabilityFlags = 0;
535 [self.reachabilityTracker recheck];
537 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
538 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
540 [self.otControl restore:testContextID
543 escrowRecordID:self.sosPeerID
544 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
545 [self.spiBlockExpectation fulfill];
546 XCTAssertNil(signingKeyData, "Signing key data should be nil");
547 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
548 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
550 [self waitForCKModifications];
551 OCMVerifyAllWithDelay(self.mockDatabase, 8);
552 [self waitForExpectationsWithTimeout:1.0 handler:nil];
555 -(void) testRestoreWhenLocked
557 [self setUpRampRecordsInCloudKitWithFeatureOn];
559 self.aksLockState = true;
560 [self.lockStateTracker recheck];
562 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
563 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
565 [self.otControl restore:testContextID
568 escrowRecordID:self.sosPeerID
569 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
570 [self.spiBlockExpectation fulfill];
571 XCTAssertNil(signingKeyData, "Signing key data should be nil");
572 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
573 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
575 [self waitForCKModifications];
576 OCMVerifyAllWithDelay(self.mockDatabase, 8);
577 [self waitForExpectationsWithTimeout:1.0 handler:nil];
581 -(void)testEnrollRampNotSignedIn
583 [self setUpRampRecordsInCloudKitWithFeatureOn];
585 NSError* error = nil;
586 NSInteger retryAfter = 0;
588 self.accountStatus = CKAccountStatusNoAccount;
589 [self startCKKSSubsystem];
591 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
593 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
595 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
599 -(void) testEnrollRampWithNoNetwork
601 [self setUpRampRecordsInCloudKitWithFeatureOn];
603 NSError* error = nil;
604 NSInteger retryAfter = 0;
606 self.accountStatus = CKAccountStatusAvailable;
607 [self startCKKSSubsystem];
609 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
611 self.reachabilityFlags = 0;
612 [self.reachabilityTracker recheck];
614 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
616 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
619 -(void) testEnrollRampWhenLocked
621 [self setUpRampRecordsInCloudKitWithFeatureOn];
623 NSError* error = nil;
624 NSInteger retryAfter = 0;
626 self.aksLockState = true;
627 [self.lockStateTracker recheck];
629 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
631 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
634 -(void) testTimeBetweenCFUAttempts
636 [self setUpRampRecordsInCloudKitWithFeatureOn];
638 NSError* error = nil;
640 [self.manager scheduledCloudKitRampCheck:&error];
641 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
642 NSDate* firstTime = self.manager.lastPostedCoreFollowUp;
646 [self.manager scheduledCloudKitRampCheck:&error];
647 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
648 NSDate* secondTime = self.manager.lastPostedCoreFollowUp;
650 XCTAssertTrue([secondTime timeIntervalSinceDate:firstTime] >= 2, "time difference should be slightly more than 2 seconds");