diff options
Diffstat (limited to 'Example/Auth/Tests/FIRAuthAppCredentialManagerTests.m')
-rw-r--r-- | Example/Auth/Tests/FIRAuthAppCredentialManagerTests.m | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/Example/Auth/Tests/FIRAuthAppCredentialManagerTests.m b/Example/Auth/Tests/FIRAuthAppCredentialManagerTests.m new file mode 100644 index 0000000..32af8cd --- /dev/null +++ b/Example/Auth/Tests/FIRAuthAppCredentialManagerTests.m @@ -0,0 +1,307 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <XCTest/XCTest.h> + +#import "FIRAuthAppCredential.h" +#import "FIRAuthAppCredentialManager.h" +#import "FIRAuthKeychain.h" +#import <OCMock/OCMock.h> + +#define ANY_ERROR_POINTER ((NSError *__autoreleasing *_Nullable)[OCMArg anyPointer]) +#define SAVE_TO(var) [OCMArg checkWithBlock:^BOOL(id arg) { var = arg; return YES; }] + +/** @var kReceipt + @brief A fake receipt used for testing. + */ +static NSString *const kReceipt = @"FAKE_RECEIPT"; + +/** @var kAnotherReceipt + @brief Another fake receipt used for testing. + */ +static NSString *const kAnotherReceipt = @"OTHER_RECEIPT"; + +/** @var kSecret + @brief A fake secret used for testing. + */ +static NSString *const kSecret = @"FAKE_SECRET"; + +/** @var kAnotherSecret + @brief Another fake secret used for testing. + */ +static NSString *const kAnotherSecret = @"OTHER_SECRET"; + +/** @var kVerificationTimeout + @brief The verification timeout used for testing. + */ +static const NSTimeInterval kVerificationTimeout = 1; + +/** @var kExpectationTimeout + @brief The test expectation timeout. + @remarks This must be considerably greater than @c kVerificationTimeout . + */ +static const NSTimeInterval kExpectationTimeout = 2; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthAppCredentialManagerTests + @brief Unit tests for @c FIRAuthAppCredentialManager . + */ +@interface FIRAuthAppCredentialManagerTests : XCTestCase +@end +@implementation FIRAuthAppCredentialManagerTests { + /** @var _mockKeychain + @brief The mock keychain for testing. + */ + id _mockKeychain; +} + +- (void)setUp { + _mockKeychain = OCMClassMock([FIRAuthKeychain class]); +} + +/** @fn testCompletion + @brief Tests a successfully completed verification flow. + */ +- (void)testCompletion { + // Initial empty state. + OCMExpect([_mockKeychain dataForKey:OCMOCK_ANY error:ANY_ERROR_POINTER]).andReturn(nil); + FIRAuthAppCredentialManager *manager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification. + XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + [manager didStartVerificationWithReceipt:kReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + XCTAssertEqualObjects(credential.receipt, kReceipt); + XCTAssertEqualObjects(credential.secret, kSecret); + [expectation fulfill]; + }]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Mismatched receipt shouldn't finish verification. + XCTAssertFalse([manager canFinishVerificationWithReceipt:kAnotherReceipt secret:kAnotherSecret]); + XCTAssertNil(manager.credential); + + // Finish verification. + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + XCTAssertTrue([manager canFinishVerificationWithReceipt:kReceipt secret:kSecret]); + [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; + XCTAssertNotNil(manager.credential); + XCTAssertEqualObjects(manager.credential.receipt, kReceipt); + XCTAssertEqualObjects(manager.credential.secret, kSecret); + OCMVerifyAll(_mockKeychain); + + // Repeated receipt should have no effect. + XCTAssertFalse([manager canFinishVerificationWithReceipt:kReceipt secret:kAnotherSecret]); + XCTAssertEqualObjects(manager.credential.secret, kSecret); +} + +/** @fn testTimeout + @brief Tests a verification flow that times out. + */ +- (void)testTimeout { + // Initial empty state. + OCMExpect([_mockKeychain dataForKey:OCMOCK_ANY error:ANY_ERROR_POINTER]).andReturn(nil); + FIRAuthAppCredentialManager *manager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification. + XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + [manager didStartVerificationWithReceipt:kReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + XCTAssertEqualObjects(credential.receipt, kReceipt); + XCTAssertNil(credential.secret); + [expectation fulfill]; + }]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Time-out. + [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; + XCTAssertNil(manager.credential); + + // Completion after timeout. + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + XCTAssertTrue([manager canFinishVerificationWithReceipt:kReceipt secret:kSecret]); + XCTAssertNotNil(manager.credential); + XCTAssertEqualObjects(manager.credential.receipt, kReceipt); + XCTAssertEqualObjects(manager.credential.secret, kSecret); + OCMVerifyAll(_mockKeychain); +} + +/** @fn testMaximumPendingReceipt + @brief Tests the maximum allowed number of pending receipt. + */ +- (void)testMaximumPendingReceipt { + // Initial empty state. + OCMExpect([_mockKeychain dataForKey:OCMOCK_ANY error:ANY_ERROR_POINTER]).andReturn(nil); + FIRAuthAppCredentialManager *manager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification of the target receipt. + XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + [manager didStartVerificationWithReceipt:kReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + XCTAssertEqualObjects(credential.receipt, kReceipt); + XCTAssertEqualObjects(credential.secret, kSecret); + [expectation fulfill]; + }]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification of a number of random receipts without overflowing. + for (NSUInteger i = 1; i < manager.maximumNumberOfPendingReceipts; i++) { + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + NSString *randomReceipt = [NSString stringWithFormat:@"RANDOM_%lu", (unsigned long)i]; + XCTestExpectation *randomExpectation = [self expectationWithDescription:randomReceipt]; + [manager didStartVerificationWithReceipt:randomReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + // They all should get full credential because one is available at this point. + XCTAssertEqualObjects(credential.receipt, kReceipt); + XCTAssertEqualObjects(credential.secret, kSecret); + [randomExpectation fulfill]; + }]; + } + + // Finish verification of target receipt. + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + XCTAssertTrue([manager canFinishVerificationWithReceipt:kReceipt secret:kSecret]); + [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; + XCTAssertNotNil(manager.credential); + XCTAssertEqualObjects(manager.credential.receipt, kReceipt); + XCTAssertEqualObjects(manager.credential.secret, kSecret); + OCMVerifyAll(_mockKeychain); + + // Clear credential to prepare for next round. + [manager clearCredential]; + XCTAssertNil(manager.credential); + + // Start verification of another target receipt. + expectation = [self expectationWithDescription:@"another callback"]; + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + [manager didStartVerificationWithReceipt:kAnotherReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + XCTAssertEqualObjects(credential.receipt, kAnotherReceipt); + XCTAssertNil(credential.secret); + [expectation fulfill]; + }]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification of a number of random receipts to overflow. + for (NSUInteger i = 0; i < manager.maximumNumberOfPendingReceipts; i++) { + OCMExpect([_mockKeychain setData:OCMOCK_ANY forKey:OCMOCK_ANY error:ANY_ERROR_POINTER]) + .andReturn(YES); + NSString *randomReceipt = [NSString stringWithFormat:@"RANDOM_%lu", (unsigned long)i]; + XCTestExpectation *randomExpectation = [self expectationWithDescription:randomReceipt]; + [manager didStartVerificationWithReceipt:randomReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + // They all should get partial credential because verification has never completed. + XCTAssertEqualObjects(credential.receipt, randomReceipt); + XCTAssertNil(credential.secret); + [randomExpectation fulfill]; + }]; + } + + // Finish verification of the other target receipt. + XCTAssertFalse([manager canFinishVerificationWithReceipt:kAnotherReceipt secret:kAnotherSecret]); + [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; + XCTAssertNil(manager.credential); +} + +/** @fn testKeychain + @brief Tests state preservation in the keychain. + */ +- (void)testKeychain { + // Initial empty state. + OCMExpect([_mockKeychain dataForKey:OCMOCK_ANY error:ANY_ERROR_POINTER]).andReturn(nil); + FIRAuthAppCredentialManager *manager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Start verification. + XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; + __block NSString *key; + __block NSString *data; + OCMExpect([_mockKeychain setData:SAVE_TO(data) forKey:SAVE_TO(key) error:ANY_ERROR_POINTER]) + .andReturn(YES); + [manager didStartVerificationWithReceipt:kReceipt + timeout:kVerificationTimeout + callback:^(FIRAuthAppCredential *credential) { + XCTAssertEqualObjects(credential.receipt, kReceipt); + XCTAssertNil(credential.secret); + [expectation fulfill]; + }]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Time-out. + [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; + XCTAssertNil(manager.credential); + + // Start a new manager with saved data in keychain. + OCMExpect([_mockKeychain dataForKey:key error:ANY_ERROR_POINTER]).andReturn(data); + manager = [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNil(manager.credential); + OCMVerifyAll(_mockKeychain); + + // Finish verification. + OCMExpect([_mockKeychain setData:SAVE_TO(data) forKey:SAVE_TO(key) error:ANY_ERROR_POINTER]) + .andReturn(YES); + XCTAssertTrue([manager canFinishVerificationWithReceipt:kReceipt secret:kSecret]); + XCTAssertNotNil(manager.credential); + XCTAssertEqualObjects(manager.credential.receipt, kReceipt); + XCTAssertEqualObjects(manager.credential.secret, kSecret); + OCMVerifyAll(_mockKeychain); + + // Start yet another new manager with saved data in keychain. + OCMExpect([_mockKeychain dataForKey:key error:ANY_ERROR_POINTER]).andReturn(data); + manager = [[FIRAuthAppCredentialManager alloc] initWithKeychain:_mockKeychain]; + XCTAssertNotNil(manager.credential); + XCTAssertEqualObjects(manager.credential.receipt, kReceipt); + XCTAssertEqualObjects(manager.credential.secret, kSecret); + OCMVerifyAll(_mockKeychain); +} + +@end + +NS_ASSUME_NONNULL_END |