mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
308 lines
12 KiB
Objective-C
308 lines
12 KiB
Objective-C
/*
|
|
* 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 "FIRAuthKeychainServices.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([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
|