/*
* Copyright (c) 2017 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#if OCTAGON
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "OTTestsBase.h"
static NSString* const testContextID = @"Foo";
static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer";
@interface UnitTestOTContext : OTTestsBase
@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord;
@end
@implementation UnitTestOTContext
- (void)setUp
{
[super setUp];
self.continueAfterFailure = NO;
}
- (void)tearDown
{
self.zones = nil;
self.operationQueue = nil;
[super tearDown];
}
-(void) testEnroll
{
NSError* error = nil;
NSString* escrowRecordID = [self currentIdentity:&error].spID;
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil:
NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
[self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
[self startCKKSSubsystem];
OTPreflightInfo* info = nil;
XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info: XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(info, @"preflight info should not be nil: XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil:
OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
XCTAssertNotNil(bprecord, @"bprecord should not be nil:
XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:escrowRecordID error:&error], @"launch should succeed");
XCTAssertNil(error, @"error should be nil: [self releaseCloudKitFetchHold];
[self expectCKFetch];
XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record");
}
-(void) testEnrollAndRestore
{
NSError* error = nil;
[self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
NSString* escrowRecordID = [self currentIdentity:&error].spID;
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil:
NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
[self startCKKSSubsystem];
OTPreflightInfo* info = nil;
XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(info, @"preflight info should not be nil: XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil:
OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
XCTAssertNotNil(bprecord, @"bprecord should not be nil:
[self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error], @"should create bottled peer record");
XCTAssertNil(error, "error should be nil");
[self waitForCKModifications];
[self releaseCloudKitFetchHold];
OTBottledPeerSigned* bp = [self.context restoreFromEscrowRecordID:escrowRecordID secret:self.secret error:&error];
[self waitForCKModifications];
XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record");
[self waitForCKModifications];
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(bp, @"signed bottled peer should not be nil: XCTAssertTrue([bp.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match");
XCTAssertTrue([bp.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match");
}
-(void)testEnrollAndRestoreFromCloudKit
{
NSError* error = nil;
[self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
[self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
[self startCKKSSubsystem];
OTPreflightInfo* info = nil;
XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(info, @"preflight info should not be nil: XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil:
OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
XCTAssertNotNil(bprecord, @"bprecord should not be nil:
XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed");
XCTAssertNil(error, @"error should be nil:
[self waitForCKModifications];
OCMVerifyAllWithDelay(self.mockDatabase, 8);
[self releaseCloudKitFetchHold];
XCTAssertTrue([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have multiple records");
OTIdentity *identity = [self currentIdentity:&error];
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(self.escrowKeys, @"escrow keys should not be nil:
NSString* recordName = [OTBottledPeerRecord constructRecordID:identity.spID escrowSigningSPKI:[self.escrowKeys.signingKey.publicKey asSPKI]];
OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&error];
XCTAssertNotNil(rec.signatureUsingEscrowKey, @"signatureUsingEscrow should not be nil:
XCTAssertNotNil(rec.signatureUsingPeerKey, @"signatureUsingPeerKey should not be nil:
XCTAssertNotNil(rec.bottle, @"bottle should not be nil:
OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec
escrowKeys:self.escrowKeys
error:&error];
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(bps, @"signed bottled peer should not be nil: XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match");
XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match");
}
-(void) testScrubbing
{
NSError* error = nil;
NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
[self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
[self startCKKSSubsystem];
OTPreflightInfo* info = nil;
XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(info, @"preflight info should not be nil: XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil:
XCTAssertTrue([self.context scrubBottledPeer:testContextID bottleID:info.bottleID error:&error], @"scrubbing bottled peer should succeed");
XCTAssertNil(error, @"error should be nil: NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error];
XCTAssertTrue([list count] == 0, @"there should be 0 records in localstore");
}
-(void) testGettingListOfRecordIDS
{
NSError* error = nil;
NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
[self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
[self startCKKSSubsystem];
OTPreflightInfo* info = nil;
XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
XCTAssertNil(error, @"error should be nil: XCTAssertNotNil(info, @"preflight info should not be nil: XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil:
OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
XCTAssertNotNil(bprecord, @"bprecord should not be nil:
XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed");
XCTAssertNil(error, @"error should be nil:
[self waitForCKModifications];
OCMVerifyAllWithDelay(self.mockDatabase, 8);
[self releaseCloudKitFetchHold];
NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error];
XCTAssertNotNil(list, @"list should not be nil");
XCTAssertTrue([list count] > 0, @"list of escrow record ids should not be empty");
}
- (nullable OTIdentity *)currentIdentity:(NSError**)error {
return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:@"sos peer id" peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error];
}
@end
#endif