| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /*
- * 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 <TargetConditionals.h>
- #if !TARGET_OS_OSX
- #import <OCMock/OCMock.h>
- #import <XCTest/XCTest.h>
- #import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h"
- #import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h"
- #import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.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([FIRAuthKeychainServices 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
- #endif
|