GACDeviceCheckProviderTests.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright 2020 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <XCTest/XCTest.h>
  17. #import <OCMock/OCMock.h>
  18. #import "FBLPromise+Testing.h"
  19. #import "AppCheckCore/Sources/DeviceCheckProvider/API/GACDeviceCheckAPIService.h"
  20. #import "AppCheckCore/Sources/DeviceCheckProvider/GACDeviceCheckTokenGenerator.h"
  21. #import "AppCheckCore/Sources/Public/AppCheckCore/GACAppCheckToken.h"
  22. #import "AppCheckCore/Sources/Public/AppCheckCore/GACDeviceCheckProvider.h"
  23. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  24. #import "AppCheckCore/Tests/Utils/AppCheckBackoffWrapperFake/GACAppCheckBackoffWrapperFake.h"
  25. #if GAC_DEVICE_CHECK_SUPPORTED_TARGETS
  26. GAC_DEVICE_CHECK_PROVIDER_AVAILABILITY
  27. @interface GACDeviceCheckProvider (Tests)
  28. - (instancetype)initWithAPIService:(id<GACDeviceCheckAPIServiceProtocol>)APIService
  29. deviceTokenGenerator:(id<GACDeviceCheckTokenGenerator>)deviceTokenGenerator
  30. backoffWrapper:(id<GACAppCheckBackoffWrapperProtocol>)backoffWrapper;
  31. @end
  32. GAC_DEVICE_CHECK_PROVIDER_AVAILABILITY
  33. @interface GACDeviceCheckProviderTests : XCTestCase
  34. @property(nonatomic) GACDeviceCheckProvider *provider;
  35. @property(nonatomic) id fakeAPIService;
  36. @property(nonatomic) id fakeTokenGenerator;
  37. @property(nonatomic) GACAppCheckBackoffWrapperFake *fakeBackoffWrapper;
  38. @end
  39. @implementation GACDeviceCheckProviderTests
  40. - (void)setUp {
  41. [super setUp];
  42. self.fakeAPIService = OCMProtocolMock(@protocol(GACDeviceCheckAPIServiceProtocol));
  43. self.fakeTokenGenerator = OCMProtocolMock(@protocol(GACDeviceCheckTokenGenerator));
  44. self.fakeBackoffWrapper = [[GACAppCheckBackoffWrapperFake alloc] init];
  45. // Don't backoff by default.
  46. self.fakeBackoffWrapper.isNextOperationAllowed = YES;
  47. self.provider = [[GACDeviceCheckProvider alloc] initWithAPIService:self.fakeAPIService
  48. deviceTokenGenerator:self.fakeTokenGenerator
  49. backoffWrapper:self.fakeBackoffWrapper];
  50. }
  51. - (void)tearDown {
  52. self.provider = nil;
  53. self.fakeAPIService = nil;
  54. self.fakeTokenGenerator = nil;
  55. self.fakeBackoffWrapper = nil;
  56. }
  57. - (void)testInitWithValidApp {
  58. FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"app_id" GCMSenderID:@"sender_id"];
  59. options.APIKey = @"api_key";
  60. options.projectID = @"project_id";
  61. FIRApp *app = [[FIRApp alloc] initInstanceWithName:@"testInitWithValidApp" options:options];
  62. XCTAssertNotNil([[GACDeviceCheckProvider alloc]
  63. initWithServiceName:app.name
  64. resourceName:[GACDeviceCheckProviderTests resourceNameFromApp:app]
  65. APIKey:app.options.APIKey
  66. requestHooks:nil]);
  67. }
  68. - (void)testGetTokenSuccess {
  69. // 1. Expect device token to be generated.
  70. NSData *deviceToken = [NSData data];
  71. id generateTokenArg = [OCMArg invokeBlockWithArgs:deviceToken, [NSNull null], nil];
  72. OCMExpect([self.fakeTokenGenerator generateTokenWithCompletionHandler:generateTokenArg]);
  73. // 2. Expect FAA token to be requested.
  74. GACAppCheckToken *validToken = [[GACAppCheckToken alloc] initWithToken:@"valid_token"
  75. expirationDate:[NSDate distantFuture]
  76. receivedAtDate:[NSDate date]];
  77. OCMExpect([self.fakeAPIService appCheckTokenWithDeviceToken:deviceToken])
  78. .andReturn([FBLPromise resolvedWith:validToken]);
  79. // 3. Expect backoff wrapper to be used.
  80. self.fakeBackoffWrapper.backoffExpectation = [self expectationWithDescription:@"Backoff"];
  81. // 4. Call getToken and validate the result.
  82. XCTestExpectation *completionExpectation =
  83. [self expectationWithDescription:@"completionExpectation"];
  84. [self.provider
  85. getTokenWithCompletion:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) {
  86. [completionExpectation fulfill];
  87. XCTAssertEqualObjects(token.token, validToken.token);
  88. XCTAssertEqualObjects(token.expirationDate, validToken.expirationDate);
  89. XCTAssertEqualObjects(token.receivedAtDate, validToken.receivedAtDate);
  90. XCTAssertNil(error);
  91. }];
  92. [self waitForExpectations:@[ self.fakeBackoffWrapper.backoffExpectation, completionExpectation ]
  93. timeout:0.5
  94. enforceOrder:YES];
  95. // 5. Verify.
  96. XCTAssertNil(self.fakeBackoffWrapper.operationError);
  97. GACAppCheckToken *wrapperResult =
  98. [self.fakeBackoffWrapper.operationResult isKindOfClass:[GACAppCheckToken class]]
  99. ? self.fakeBackoffWrapper.operationResult
  100. : nil;
  101. XCTAssertEqualObjects(wrapperResult.token, validToken.token);
  102. OCMVerifyAll(self.fakeAPIService);
  103. OCMVerifyAll(self.fakeTokenGenerator);
  104. }
  105. - (void)testGetTokenWhenDeviceTokenFails {
  106. NSError *deviceTokenError = [NSError errorWithDomain:@"GACDeviceCheckProviderTests"
  107. code:-1
  108. userInfo:nil];
  109. // 0.1. Expect backoff wrapper to be used.
  110. self.fakeBackoffWrapper.backoffExpectation = [self expectationWithDescription:@"Backoff"];
  111. // 0.2. Expect default error handler to be used.
  112. XCTestExpectation *errorHandlerExpectation = [self expectationWithDescription:@"Error handler"];
  113. self.fakeBackoffWrapper.defaultErrorHandler = ^GACAppCheckBackoffType(NSError *_Nonnull error) {
  114. XCTAssertEqualObjects(error, deviceTokenError);
  115. [errorHandlerExpectation fulfill];
  116. return GACAppCheckBackoffType1Day;
  117. };
  118. // 1. Expect device token to be generated.
  119. id generateTokenArg = [OCMArg invokeBlockWithArgs:[NSNull null], deviceTokenError, nil];
  120. OCMExpect([self.fakeTokenGenerator generateTokenWithCompletionHandler:generateTokenArg]);
  121. // 2. Don't expect FAA token to be requested.
  122. OCMReject([self.fakeAPIService appCheckTokenWithDeviceToken:[OCMArg any]]);
  123. // 3. Call getToken and validate the result.
  124. XCTestExpectation *completionExpectation =
  125. [self expectationWithDescription:@"completionExpectation"];
  126. [self.provider
  127. getTokenWithCompletion:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) {
  128. [completionExpectation fulfill];
  129. XCTAssertNil(token);
  130. XCTAssertEqualObjects(error, deviceTokenError);
  131. }];
  132. [self waitForExpectations:@[
  133. self.fakeBackoffWrapper.backoffExpectation, errorHandlerExpectation, completionExpectation
  134. ]
  135. timeout:0.5
  136. enforceOrder:YES];
  137. // 4. Verify.
  138. OCMVerifyAll(self.fakeAPIService);
  139. OCMVerifyAll(self.fakeTokenGenerator);
  140. XCTAssertEqualObjects(self.fakeBackoffWrapper.operationError, deviceTokenError);
  141. XCTAssertNil(self.fakeBackoffWrapper.operationResult);
  142. }
  143. - (void)testGetTokenWhenAPIServiceFails {
  144. NSError *APIServiceError = [NSError errorWithDomain:@"GACDeviceCheckProviderTests"
  145. code:-1
  146. userInfo:nil];
  147. // 0.1. Expect backoff wrapper to be used.
  148. self.fakeBackoffWrapper.backoffExpectation = [self expectationWithDescription:@"Backoff"];
  149. // 0.2. Expect default error handler to be used.
  150. XCTestExpectation *errorHandlerExpectation = [self expectationWithDescription:@"Error handler"];
  151. self.fakeBackoffWrapper.defaultErrorHandler = ^GACAppCheckBackoffType(NSError *_Nonnull error) {
  152. XCTAssertEqualObjects(error, APIServiceError);
  153. [errorHandlerExpectation fulfill];
  154. return GACAppCheckBackoffType1Day;
  155. };
  156. // 1. Expect device token to be generated.
  157. NSData *deviceToken = [NSData data];
  158. id generateTokenArg = [OCMArg invokeBlockWithArgs:deviceToken, [NSNull null], nil];
  159. OCMExpect([self.fakeTokenGenerator generateTokenWithCompletionHandler:generateTokenArg]);
  160. // 2. Expect FAA token to be requested.
  161. FBLPromise *rejectedPromise = [FBLPromise pendingPromise];
  162. [rejectedPromise reject:APIServiceError];
  163. OCMExpect([self.fakeAPIService appCheckTokenWithDeviceToken:deviceToken])
  164. .andReturn(rejectedPromise);
  165. // 3. Call getToken and validate the result.
  166. XCTestExpectation *completionExpectation =
  167. [self expectationWithDescription:@"completionExpectation"];
  168. [self.provider
  169. getTokenWithCompletion:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) {
  170. [completionExpectation fulfill];
  171. XCTAssertNil(token);
  172. XCTAssertEqualObjects(error, APIServiceError);
  173. }];
  174. [self waitForExpectations:@[
  175. self.fakeBackoffWrapper.backoffExpectation, errorHandlerExpectation, completionExpectation
  176. ]
  177. timeout:0.5
  178. enforceOrder:YES];
  179. // 4. Verify.
  180. OCMVerifyAll(self.fakeAPIService);
  181. OCMVerifyAll(self.fakeTokenGenerator);
  182. XCTAssertEqualObjects(self.fakeBackoffWrapper.operationError, APIServiceError);
  183. XCTAssertNil(self.fakeBackoffWrapper.operationResult);
  184. }
  185. #pragma mark - Backoff tests
  186. - (void)testGetTokenBackoff {
  187. // 1. Configure backoff.
  188. self.fakeBackoffWrapper.isNextOperationAllowed = NO;
  189. self.fakeBackoffWrapper.backoffExpectation = [self expectationWithDescription:@"Backoff"];
  190. // 2. Don't expect any operations.
  191. OCMReject([self.fakeAPIService appCheckTokenWithDeviceToken:[OCMArg any]]);
  192. OCMReject([self.fakeTokenGenerator generateTokenWithCompletionHandler:OCMOCK_ANY]);
  193. // 3. Call getToken and validate the result.
  194. XCTestExpectation *completionExpectation =
  195. [self expectationWithDescription:@"completionExpectation"];
  196. [self.provider
  197. getTokenWithCompletion:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) {
  198. [completionExpectation fulfill];
  199. XCTAssertNil(token);
  200. XCTAssertEqualObjects(error, self.fakeBackoffWrapper.backoffError);
  201. }];
  202. [self waitForExpectations:@[ self.fakeBackoffWrapper.backoffExpectation, completionExpectation ]
  203. timeout:0.5
  204. enforceOrder:YES];
  205. // 4. Verify.
  206. OCMVerifyAll(self.fakeAPIService);
  207. OCMVerifyAll(self.fakeTokenGenerator);
  208. }
  209. #pragma mark - Helpers
  210. // TODO(andrewheard): Remove from generic App Check SDK.
  211. // FIREBASE_APP_CHECK_ONLY_BEGIN
  212. + (NSString *)resourceNameFromApp:(FIRApp *)app {
  213. return [NSString
  214. stringWithFormat:@"projects/%@/apps/%@", app.options.projectID, app.options.googleAppID];
  215. }
  216. // FIREBASE_APP_CHECK_ONLY_END
  217. @end
  218. #endif // GAC_DEVICE_CHECK_SUPPORTED_TARGETS