FIRAppCheckTests.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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 <FirebaseAppCheckInterop/FirebaseAppCheckInterop.h>
  20. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheck.h"
  21. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckErrors.h"
  22. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckProvider.h"
  23. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckProviderFactory.h"
  24. #import "FirebaseAppCheck/Sources/Core/Errors/FIRAppCheckErrorUtil.h"
  25. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckSettings.h"
  26. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckToken+Internal.h"
  27. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h"
  28. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  29. // The FAC token value returned when an error occurs.
  30. static NSString *const kDummyToken = @"eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ==";
  31. extern void FIRResetLogger(void);
  32. @interface FIRAppCheck (Tests) <FIRAppCheckInterop, GACAppCheckTokenDelegate>
  33. - (instancetype)initWithAppName:(NSString *)appName
  34. appCheckCore:(GACAppCheck *)appCheckCore
  35. appCheckProvider:(id<FIRAppCheckProvider>)appCheckProvider
  36. notificationCenter:(NSNotificationCenter *)notificationCenter
  37. settings:(FIRAppCheckSettings *)settings;
  38. - (nullable instancetype)initWithApp:(FIRApp *)app;
  39. - (void)tokenDidUpdate:(nonnull GACAppCheckToken *)token
  40. serviceName:(nonnull NSString *)serviceName;
  41. @end
  42. @interface FIRAppCheckTests : XCTestCase
  43. @property(nonatomic) NSString *appName;
  44. @property(nonatomic) OCMockObject<FIRAppCheckProvider> *mockAppCheckProvider;
  45. @property(nonatomic) id mockSettings;
  46. @property(nonatomic) NSNotificationCenter *notificationCenter;
  47. @property(nonatomic) id mockAppCheckCore;
  48. @property(nonatomic) FIRAppCheck<FIRAppCheckInterop> *appCheck;
  49. @end
  50. @implementation FIRAppCheckTests
  51. - (void)setUp {
  52. [super setUp];
  53. FIRResetLogger();
  54. self.appName = @"FIRAppCheckTests";
  55. self.mockAppCheckProvider = OCMStrictProtocolMock(@protocol(FIRAppCheckProvider));
  56. self.mockSettings = OCMStrictClassMock([FIRAppCheckSettings class]);
  57. self.notificationCenter = [[NSNotificationCenter alloc] init];
  58. self.mockAppCheckCore = OCMStrictClassMock([GACAppCheck class]);
  59. self.appCheck = [[FIRAppCheck alloc] initWithAppName:self.appName
  60. appCheckCore:self.mockAppCheckCore
  61. appCheckProvider:self.mockAppCheckProvider
  62. notificationCenter:self.notificationCenter
  63. settings:self.mockSettings];
  64. }
  65. - (void)tearDown {
  66. self.appCheck = nil;
  67. self.mockAppCheckCore = nil;
  68. self.mockAppCheckProvider = nil;
  69. [super tearDown];
  70. }
  71. - (void)testInitWithApp {
  72. NSString *projectID = @"testInitWithApp_projectID";
  73. NSString *googleAppID = @"testInitWithApp_googleAppID";
  74. NSString *appName = @"testInitWithApp_appName";
  75. NSString *appGroupID = @"testInitWithApp_appGroupID";
  76. // 1. Stub FIRApp and validate usage.
  77. FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:googleAppID GCMSenderID:@""];
  78. options.projectID = projectID;
  79. options.appGroupID = appGroupID;
  80. FIRApp *app = [[FIRApp alloc] initInstanceWithName:appName options:options];
  81. // The following disables automatic token refresh, which could interfere with tests.
  82. app.dataCollectionDefaultEnabled = NO;
  83. // 2. Stub attestation provider.
  84. OCMockObject<FIRAppCheckProviderFactory> *mockProviderFactory =
  85. OCMStrictProtocolMock(@protocol(FIRAppCheckProviderFactory));
  86. OCMockObject<FIRAppCheckProvider> *mockProvider =
  87. OCMStrictProtocolMock(@protocol(FIRAppCheckProvider));
  88. OCMExpect([mockProviderFactory createProviderWithApp:app]).andReturn(mockProvider);
  89. [FIRAppCheck setAppCheckProviderFactory:mockProviderFactory];
  90. // 3. Set the Firebase logging level to Debug.
  91. FIRSetLoggerLevel(FIRLoggerLevelDebug);
  92. // 4. Call init.
  93. FIRAppCheck *appCheck = [[FIRAppCheck alloc] initWithApp:app];
  94. XCTAssert([appCheck isKindOfClass:[FIRAppCheck class]]);
  95. // 5. Verify mocks.
  96. OCMVerifyAll(mockProviderFactory);
  97. OCMVerifyAll(mockProvider);
  98. // 6. Verify that the App Check Core logging level is also Debug.
  99. XCTAssertEqual(GACAppCheckLogger.logLevel, GACAppCheckLogLevelDebug);
  100. }
  101. - (void)testAppCheckInstanceForApp {
  102. FIROptions *options =
  103. [[FIROptions alloc] initWithGoogleAppID:@"1:100000000000:ios:aaaaaaaaaaaaaaaaaaaaaaaa"
  104. GCMSenderID:@"sender_id"];
  105. options.APIKey = @"api_key";
  106. options.projectID = @"project_id";
  107. FIRApp *app = [[FIRApp alloc] initInstanceWithName:@"testAppCheckInstanceForApp" options:options];
  108. // The following disables automatic token refresh, which could interfere with tests.
  109. app.dataCollectionDefaultEnabled = NO;
  110. XCTAssertNotNil(app);
  111. XCTAssertNotNil([FIRAppCheck appCheckWithApp:app]);
  112. // Verify that the App Check Core logging level is the default (Warning).
  113. XCTAssertEqual(GACAppCheckLogger.logLevel, GACAppCheckLogLevelWarning);
  114. }
  115. #pragma mark - Public Get Token
  116. - (void)testGetToken_Success {
  117. // 1. Create expected token and configure expectations.
  118. FIRAppCheckToken *expectedToken = [self validToken];
  119. NSArray * /*[tokenNotification, getToken]*/ expectations =
  120. [self configuredExpectations_TokenForcingRefresh_withExpectedToken:expectedToken];
  121. // 2. Request token and verify result.
  122. [self.appCheck
  123. tokenForcingRefresh:NO
  124. completion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  125. [expectations.lastObject fulfill];
  126. XCTAssertNotNil(token);
  127. XCTAssertEqualObjects(token.token, expectedToken.token);
  128. XCTAssertNil(error);
  129. }];
  130. // 3. Wait for expectations and validate mocks.
  131. [self waitForExpectations:expectations timeout:0.5];
  132. [self verifyAllMocks];
  133. }
  134. - (void)testGetToken_AppCheckProviderError {
  135. // 1. Create expected token and error and configure expectations.
  136. FIRAppCheckToken *cachedToken = [self soonExpiringToken];
  137. NSError *providerError = [NSError errorWithDomain:@"FIRAppCheckTests" code:-1 userInfo:nil];
  138. NSArray * /*[tokenNotification, getToken]*/ expectations =
  139. [self configuredExpectations_GetTokenWhenError_withError:providerError andToken:cachedToken];
  140. // 2. Request token and verify result.
  141. [self.appCheck
  142. tokenForcingRefresh:NO
  143. completion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  144. [expectations.lastObject fulfill];
  145. XCTAssertNil(token);
  146. XCTAssertNotNil(error);
  147. XCTAssertNotEqualObjects(error, providerError);
  148. XCTAssertEqualObjects(error.domain, FIRAppCheckErrorDomain);
  149. XCTAssertEqualObjects(error.userInfo[NSUnderlyingErrorKey], providerError);
  150. }];
  151. // 3. Wait for expectations and validate mocks.
  152. [self waitForExpectations:expectations timeout:0.5];
  153. [self verifyAllMocks];
  154. }
  155. - (void)testGetToken_ServerUnreachableError {
  156. // 1. Create expected error and configure expectations.
  157. NSError *serverError = [self appCheckCoreErrorWithCode:GACAppCheckErrorCodeServerUnreachable
  158. failureReason:@"API request error."
  159. underlyingError:[self internalError]];
  160. NSError *publicServerError = [FIRAppCheckErrorUtil publicDomainErrorWithError:serverError];
  161. NSArray * /*[tokenNotification, getToken]*/ expectations =
  162. [self configuredExpectations_GetTokenWhenError_withError:serverError andToken:nil];
  163. // 2. Request token and verify result.
  164. [self.appCheck
  165. tokenForcingRefresh:NO
  166. completion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  167. [expectations.lastObject fulfill];
  168. XCTAssertNil(token);
  169. XCTAssertNotNil(error);
  170. XCTAssertEqualObjects(error, publicServerError);
  171. XCTAssertEqualObjects(error.domain, FIRAppCheckErrorDomain);
  172. XCTAssertEqual(error.code, FIRAppCheckErrorCodeServerUnreachable);
  173. XCTAssertEqualObjects(error.userInfo, serverError.userInfo);
  174. }];
  175. // 3. Wait for expectations and validate mocks.
  176. [self waitForExpectations:expectations timeout:0.5];
  177. [self verifyAllMocks];
  178. }
  179. - (void)testGetToken_UnsupportedError {
  180. // 1. Create expected error and configure expectations.
  181. NSError *providerError = [self appCheckCoreErrorWithCode:GACAppCheckErrorCodeUnsupported
  182. failureReason:@"AppAttestProvider unsupported"
  183. underlyingError:nil];
  184. NSError *publicProviderError = [FIRAppCheckErrorUtil publicDomainErrorWithError:providerError];
  185. NSArray * /*[tokenNotification, getToken]*/ expectations =
  186. [self configuredExpectations_GetTokenWhenError_withError:providerError andToken:nil];
  187. // 2. Request token and verify result.
  188. [self.appCheck
  189. tokenForcingRefresh:NO
  190. completion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  191. [expectations.lastObject fulfill];
  192. XCTAssertNil(token);
  193. XCTAssertNotNil(error);
  194. XCTAssertEqualObjects(error, publicProviderError);
  195. XCTAssertEqualObjects(error.domain, FIRAppCheckErrorDomain);
  196. XCTAssertEqual(error.code, FIRAppCheckErrorCodeUnsupported);
  197. XCTAssertEqualObjects(error.userInfo, providerError.userInfo);
  198. }];
  199. // 3. Wait for expectations and validate mocks.
  200. [self waitForExpectations:expectations timeout:0.5];
  201. [self verifyAllMocks];
  202. }
  203. #pragma mark - FIRAppCheckInterop Get Token
  204. - (void)testInteropGetTokenForcingRefresh_Success {
  205. // 1. Create expected token and configure expectations.
  206. FIRAppCheckToken *expectedToken = [self validToken];
  207. NSArray * /*[tokenNotification, getToken]*/ expectations =
  208. [self configuredExpectations_TokenForcingRefresh_withExpectedToken:expectedToken];
  209. // 2. Request token and verify result.
  210. [self.appCheck getTokenForcingRefresh:NO
  211. completion:^(id<FIRAppCheckTokenResultInterop> tokenResult) {
  212. [expectations.lastObject fulfill];
  213. XCTAssertNotNil(tokenResult);
  214. XCTAssertEqualObjects(tokenResult.token, expectedToken.token);
  215. XCTAssertNil(tokenResult.error);
  216. }];
  217. // 3. Wait for expectations and validate mocks.
  218. [self waitForExpectations:expectations timeout:0.5];
  219. [self verifyAllMocks];
  220. }
  221. - (void)testInteropGetTokenForcingRefresh_AppCheckProviderError {
  222. // 1. Create expected tokens and errors and configure expectations.
  223. FIRAppCheckToken *cachedToken = [self soonExpiringToken];
  224. NSError *providerError = [NSError errorWithDomain:@"FIRAppCheckTests" code:-1 userInfo:nil];
  225. NSArray * /*[tokenNotification, getToken]*/ expectations =
  226. [self configuredExpectations_GetTokenWhenError_withError:providerError andToken:cachedToken];
  227. // 2. Request token and verify result.
  228. [self.appCheck
  229. getTokenForcingRefresh:NO
  230. completion:^(id<FIRAppCheckTokenResultInterop> result) {
  231. [expectations.lastObject fulfill];
  232. XCTAssertNotNil(result);
  233. XCTAssertEqualObjects(result.token, kDummyToken);
  234. XCTAssertEqualObjects(result.error, providerError);
  235. // Interop API does not wrap errors in public domain.
  236. XCTAssertNotEqualObjects(result.error.domain, FIRAppCheckErrorDomain);
  237. }];
  238. // 3. Wait for expectations and validate mocks.
  239. [self waitForExpectations:expectations timeout:0.5];
  240. [self verifyAllMocks];
  241. }
  242. - (void)testLimitedUseTokenWithSuccess {
  243. // 1. Expect token requested from app check provider.
  244. FIRAppCheckToken *expectedToken = [self validToken];
  245. GACAppCheckToken *expectedInternalToken = [expectedToken internalToken];
  246. GACAppCheckTokenResult *expectedTokenResult =
  247. [[GACAppCheckTokenResult alloc] initWithToken:expectedInternalToken];
  248. id completionArg = [OCMArg invokeBlockWithArgs:expectedTokenResult, nil];
  249. OCMStub([self.mockAppCheckCore limitedUseTokenWithCompletion:completionArg]);
  250. // 2. Don't expect token update notification to be sent.
  251. XCTestExpectation *notificationExpectation = [self tokenUpdateNotificationNotPosted];
  252. // 3. Expect token request to be completed.
  253. XCTestExpectation *getTokenExpectation = [self expectationWithDescription:@"getToken"];
  254. [self.appCheck
  255. limitedUseTokenWithCompletion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  256. [getTokenExpectation fulfill];
  257. XCTAssertNotNil(token);
  258. XCTAssertEqualObjects(token.token, expectedToken.token);
  259. XCTAssertNil(error);
  260. }];
  261. [self waitForExpectations:@[ notificationExpectation, getTokenExpectation ] timeout:0.5];
  262. [self verifyAllMocks];
  263. }
  264. - (void)testLimitedUseToken_WhenTokenGenerationErrors {
  265. // 1. Expect error when requesting token from app check provider.
  266. NSError *providerError = [self appCheckCoreErrorWithCode:GACAppCheckErrorCodeKeychain
  267. failureReason:@"Keychain access error."
  268. underlyingError:[self internalError]];
  269. NSError *publicProviderError = [FIRAppCheckErrorUtil publicDomainErrorWithError:providerError];
  270. GACAppCheckTokenResult *expectedTokenResult =
  271. [[GACAppCheckTokenResult alloc] initWithError:providerError];
  272. id completionArg = [OCMArg invokeBlockWithArgs:expectedTokenResult, nil];
  273. OCMStub([self.mockAppCheckCore limitedUseTokenWithCompletion:completionArg]);
  274. // 2. Don't expect token requested from app check provider.
  275. OCMReject([self.mockAppCheckProvider getTokenWithCompletion:[OCMArg any]]);
  276. // 3. Don't expect token update notification to be sent.
  277. XCTestExpectation *notificationExpectation = [self tokenUpdateNotificationNotPosted];
  278. // 4. Expect token request to be completed.
  279. XCTestExpectation *getTokenExpectation = [self expectationWithDescription:@"getToken"];
  280. [self.appCheck
  281. limitedUseTokenWithCompletion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) {
  282. [getTokenExpectation fulfill];
  283. XCTAssertNotNil(error);
  284. XCTAssertNil(token.token);
  285. XCTAssertEqualObjects(error, publicProviderError);
  286. XCTAssertEqualObjects(error.domain, FIRAppCheckErrorDomain);
  287. XCTAssertEqual(error.code, FIRAppCheckErrorCodeKeychain);
  288. XCTAssertEqualObjects(error.userInfo, providerError.userInfo);
  289. }];
  290. [self waitForExpectations:@[ notificationExpectation, getTokenExpectation ] timeout:0.5];
  291. [self verifyAllMocks];
  292. }
  293. #pragma mark - Token update notifications
  294. - (void)testTokenUpdateNotificationKeys {
  295. XCTAssertEqualObjects([self.appCheck tokenDidChangeNotificationName],
  296. @"FIRAppCheckAppCheckTokenDidChangeNotification");
  297. XCTAssertEqualObjects([self.appCheck notificationAppNameKey],
  298. @"FIRAppCheckAppNameNotificationKey");
  299. XCTAssertEqualObjects([self.appCheck notificationTokenKey], @"FIRAppCheckTokenNotificationKey");
  300. }
  301. #pragma mark - Auto-refresh enabled
  302. - (void)testIsTokenAutoRefreshEnabled {
  303. // Expect value from settings to be used.
  304. [[[self.mockSettings expect] andReturnValue:@(NO)] isTokenAutoRefreshEnabled];
  305. XCTAssertFalse(self.appCheck.isTokenAutoRefreshEnabled);
  306. [[[self.mockSettings expect] andReturnValue:@(YES)] isTokenAutoRefreshEnabled];
  307. XCTAssertTrue(self.appCheck.isTokenAutoRefreshEnabled);
  308. OCMVerifyAll(self.mockSettings);
  309. }
  310. - (void)testSetIsTokenAutoRefreshEnabled {
  311. OCMExpect([self.mockSettings setIsTokenAutoRefreshEnabled:YES]);
  312. self.appCheck.isTokenAutoRefreshEnabled = YES;
  313. OCMExpect([self.mockSettings setIsTokenAutoRefreshEnabled:NO]);
  314. self.appCheck.isTokenAutoRefreshEnabled = NO;
  315. OCMVerifyAll(self.mockSettings);
  316. }
  317. #pragma mark - Helpers
  318. - (NSError *)internalError {
  319. return [NSError errorWithDomain:@"com.internal.error" code:-1 userInfo:nil];
  320. }
  321. - (NSError *)appCheckCoreErrorWithCode:(GACAppCheckErrorCode)code
  322. failureReason:(nullable NSString *)failureReason
  323. underlyingError:(nullable NSError *)underlyingError {
  324. NSMutableDictionary<NSErrorUserInfoKey, id> *userInfo = [NSMutableDictionary dictionary];
  325. userInfo[NSUnderlyingErrorKey] = underlyingError;
  326. userInfo[NSLocalizedFailureReasonErrorKey] = failureReason;
  327. return [NSError errorWithDomain:GACAppCheckErrorDomain code:code userInfo:userInfo];
  328. }
  329. - (FIRAppCheckToken *)validToken {
  330. return [[FIRAppCheckToken alloc] initWithToken:[NSUUID UUID].UUIDString
  331. expirationDate:[NSDate distantFuture]];
  332. }
  333. - (FIRAppCheckToken *)soonExpiringToken {
  334. NSDate *soonExpiringTokenDate = [NSDate dateWithTimeIntervalSinceNow:4.5 * 60];
  335. return [[FIRAppCheckToken alloc] initWithToken:@"valid" expirationDate:soonExpiringTokenDate];
  336. }
  337. - (XCTestExpectation *)tokenUpdateNotificationWithExpectedToken:(NSString *)expectedToken {
  338. XCTestExpectation *expectation =
  339. [self expectationForNotification:[self.appCheck tokenDidChangeNotificationName]
  340. object:nil
  341. notificationCenter:self.notificationCenter
  342. handler:^BOOL(NSNotification *_Nonnull notification) {
  343. XCTAssertEqualObjects(
  344. notification.userInfo[[self.appCheck notificationAppNameKey]],
  345. self.appName);
  346. XCTAssertEqualObjects(
  347. notification.userInfo[[self.appCheck notificationTokenKey]],
  348. expectedToken);
  349. XCTAssertEqualObjects(notification.object, self.appCheck);
  350. return YES;
  351. }];
  352. return expectation;
  353. }
  354. - (XCTestExpectation *)tokenUpdateNotificationNotPosted {
  355. XCTNSNotificationExpectation *expectation = [[XCTNSNotificationExpectation alloc]
  356. initWithName:[self.appCheck tokenDidChangeNotificationName]
  357. object:nil
  358. notificationCenter:self.notificationCenter];
  359. expectation.inverted = YES;
  360. return expectation;
  361. }
  362. - (NSArray<XCTestExpectation *> *)configuredExpectations_TokenForcingRefresh_withExpectedToken:
  363. (FIRAppCheckToken *)expectedToken {
  364. // 1. Expect token requested from app check core.
  365. GACAppCheckToken *expectedInternalToken = [expectedToken internalToken];
  366. GACAppCheckTokenResult *expectedTokenResult =
  367. [[GACAppCheckTokenResult alloc] initWithToken:expectedInternalToken];
  368. id completionArg = [OCMArg invokeBlockWithArgs:expectedTokenResult, nil];
  369. OCMExpect([self.mockAppCheckCore tokenForcingRefresh:NO completion:completionArg])
  370. .andDo(^(NSInvocation *invocation) {
  371. [self.appCheck tokenDidUpdate:expectedInternalToken serviceName:self.appName];
  372. })
  373. .ignoringNonObjectArgs();
  374. // 2. Expect token update notification to be sent.
  375. XCTestExpectation *tokenNotificationExpectation =
  376. [self tokenUpdateNotificationWithExpectedToken:expectedToken.token];
  377. // 3. Expect token request to be completed.
  378. XCTestExpectation *getTokenExpectation = [self expectationWithDescription:@"getToken"];
  379. return @[ tokenNotificationExpectation, getTokenExpectation ];
  380. }
  381. - (NSArray<XCTestExpectation *> *)
  382. configuredExpectations_GetTokenWhenError_withError:(NSError *_Nonnull)error
  383. andToken:(FIRAppCheckToken *_Nullable)token {
  384. // 1. Expect token requested from app check core.
  385. GACAppCheckTokenResult *expectedTokenResult =
  386. [[GACAppCheckTokenResult alloc] initWithError:error];
  387. id completionArg = [OCMArg invokeBlockWithArgs:expectedTokenResult, nil];
  388. OCMExpect([self.mockAppCheckCore tokenForcingRefresh:NO completion:completionArg])
  389. .ignoringNonObjectArgs();
  390. // 2. Don't expect token requested from app check provider.
  391. OCMReject([self.mockAppCheckProvider getTokenWithCompletion:[OCMArg any]]);
  392. // 3. Expect token update notification to be sent.
  393. XCTestExpectation *notificationExpectation = [self tokenUpdateNotificationNotPosted];
  394. // 4. Expect token request to be completed.
  395. XCTestExpectation *getTokenExpectation = [self expectationWithDescription:@"getToken"];
  396. return @[ notificationExpectation, getTokenExpectation ];
  397. }
  398. - (void)verifyAllMocks {
  399. OCMVerifyAll(self.mockAppCheckProvider);
  400. OCMVerifyAll(self.mockSettings);
  401. OCMVerifyAll(self.mockAppCheckCore);
  402. }
  403. @end