3 #import <XCTest/XCTest.h>
4 #import <OCMock/OCMock.h>
6 #import "keychain/ckks/CKKSLockStateTracker.h"
7 #import "tests/secdmockaks/mockaks.h"
9 @interface CKKSTests_LockStateTracker : XCTestCase
10 @property bool aksLockState;
11 @property (nullable) id mockLockStateTracker;
12 @property CKKSLockStateTracker* lockStateTracker;
15 @implementation CKKSTests_LockStateTracker
17 @synthesize aksLockState = _aksLockState;
22 self.aksLockState = false; // Lie and say AKS is always unlocked
23 self.mockLockStateTracker = OCMClassMock([CKKSLockStateTracker class]);
24 OCMStub([self.mockLockStateTracker queryAKSLocked]).andCall(self, @selector(aksLockState));
26 self.lockStateTracker = [[CKKSLockStateTracker alloc] init];
33 [self.mockLockStateTracker stopMocking];
34 self.lockStateTracker = nil;
42 - (void)setAksLockState:(bool)aksLockState
46 [SecMockAKS lockClassA];
48 [SecMockAKS unlockAllClasses];
50 _aksLockState = aksLockState;
53 - (void)testLockedBehindOurBack {
56 * check that we detect that lock errors force a recheck
59 NSError *lockError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInteractionNotAllowed userInfo:nil];
60 NSError *fileError = [NSError errorWithDomain:NSOSStatusErrorDomain code:ENOENT userInfo:nil];
62 XCTAssertFalse([self.lockStateTracker isLocked], "should start out unlocked");
63 XCTAssertTrue([self.lockStateTracker isLockedError:lockError], "errSecInteractionNotAllowed is a lock errors");
64 XCTAssertFalse([self.lockStateTracker isLocked], "should be unlocked after lock failure");
66 XCTAssertFalse([self.lockStateTracker isLockedError:fileError], "file errors are not lock errors");
67 XCTAssertFalse([self.lockStateTracker isLocked], "should be unlocked after lock failure");
69 self.aksLockState = true;
70 XCTAssertFalse([self.lockStateTracker isLocked], "should be reporting unlocked since we 'missed' the notification");
72 XCTAssertFalse([self.lockStateTracker isLockedError:fileError], "file errors are not lock errors");
73 XCTAssertFalse([self.lockStateTracker isLocked], "should be 'unlocked' after file errors");
75 XCTAssertTrue([self.lockStateTracker isLockedError:lockError], "errSecInteractionNotAllowed is a lock errors");
76 XCTAssertTrue([self.lockStateTracker isLocked], "should be locked after lock failure");
78 self.aksLockState = false;
79 [self.lockStateTracker recheck];
81 XCTAssertFalse([self.lockStateTracker isLocked], "should be unlocked");
84 - (void)testWaitForUnlock {
86 self.aksLockState = true;
87 [self.lockStateTracker recheck];
89 XCTestExpectation* expectation = [self expectationWithDescription: @"unlock occurs"];
91 NSBlockOperation *unlockEvent = [NSBlockOperation blockOperationWithBlock:^{
92 [expectation fulfill];
94 [unlockEvent addDependency:[self.lockStateTracker unlockDependency]];
95 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
97 [queue addOperation:unlockEvent];
99 self.aksLockState = false;
100 [self.lockStateTracker recheck];
102 [self waitForExpectations:@[expectation] timeout:5];