FIRInstallationsIDControllerTests.m 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  1. /*
  2. * Copyright 2019 Google
  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 <FirebaseCore/FIRAppInternal.h>
  19. #import "FBLPromise+Testing.h"
  20. #import "FIRInstallationsErrorUtil+Tests.h"
  21. #import "FIRInstallationsItem+Tests.h"
  22. #import "FIRInstallations.h"
  23. #import "FIRInstallationsAPIService.h"
  24. #import "FIRInstallationsErrorUtil.h"
  25. #import "FIRInstallationsHTTPError.h"
  26. #import "FIRInstallationsIDController.h"
  27. #import "FIRInstallationsIIDStore.h"
  28. #import "FIRInstallationsIIDTokenStore.h"
  29. #import "FIRInstallationsStore.h"
  30. #import "FIRInstallationsStoredAuthToken.h"
  31. @interface FIRInstallationsIDController (Tests)
  32. - (instancetype)initWithGoogleAppID:(NSString *)appID
  33. appName:(NSString *)appName
  34. installationsStore:(FIRInstallationsStore *)installationsStore
  35. APIService:(FIRInstallationsAPIService *)APIService
  36. IIDStore:(FIRInstallationsIIDStore *)IIDStore
  37. IIDTokenStore:(FIRInstallationsIIDTokenStore *)IIDTokenStore;
  38. @end
  39. @interface FIRInstallationsIDControllerTests : XCTestCase
  40. @property(nonatomic) FIRInstallationsIDController *controller;
  41. @property(nonatomic) id mockInstallationsStore;
  42. @property(nonatomic) id mockAPIService;
  43. @property(nonatomic) id mockIIDStore;
  44. @property(nonatomic) id mockIIDTokenStore;
  45. @property(nonatomic) NSString *appID;
  46. @property(nonatomic) NSString *appName;
  47. @end
  48. @implementation FIRInstallationsIDControllerTests
  49. - (void)setUp {
  50. [self setUpWithAppName:kFIRDefaultAppName];
  51. }
  52. - (void)setUpWithAppName:(NSString *)appName {
  53. self.appID = @"appID";
  54. self.appName = appName;
  55. self.mockInstallationsStore = OCMStrictClassMock([FIRInstallationsStore class]);
  56. self.mockAPIService = OCMStrictClassMock([FIRInstallationsAPIService class]);
  57. self.mockIIDStore = OCMStrictClassMock([FIRInstallationsIIDStore class]);
  58. self.mockIIDTokenStore = OCMStrictClassMock([FIRInstallationsIIDTokenStore class]);
  59. self.controller =
  60. [[FIRInstallationsIDController alloc] initWithGoogleAppID:self.appID
  61. appName:self.appName
  62. installationsStore:self.mockInstallationsStore
  63. APIService:self.mockAPIService
  64. IIDStore:self.mockIIDStore
  65. IIDTokenStore:self.mockIIDTokenStore];
  66. }
  67. - (void)tearDown {
  68. self.controller = nil;
  69. self.mockIIDStore = nil;
  70. self.mockAPIService = nil;
  71. self.mockInstallationsStore = nil;
  72. self.appID = nil;
  73. self.appName = nil;
  74. }
  75. #pragma mark - Get Installation
  76. - (void)testGetInstallationItem_WhenFIDExists_ThenItIsReturned {
  77. FIRInstallationsItem *storedInstallations =
  78. [FIRInstallationsItem createRegisteredInstallationItem];
  79. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  80. .andReturn([FBLPromise resolvedWith:storedInstallations]);
  81. // Don't expect FIRInstallationIDDidChangeNotification to be sent.
  82. XCTestExpectation *notificationExpectation =
  83. [self installationIDDidChangeNotificationExpectation];
  84. notificationExpectation.inverted = YES;
  85. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getInstallationItem];
  86. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  87. XCTAssertNil(promise.error);
  88. XCTAssertEqual(promise.value, storedInstallations);
  89. OCMVerifyAll(self.mockInstallationsStore);
  90. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  91. }
  92. - (void)testGetInstallationItem_WhenNoFIDAndNoIID_ThenFIDIsCreatedAndRegistered {
  93. // 1. Stub store get installation.
  94. [self expectInstallationsStoreGetInstallationNotFound];
  95. // 2. Stub store save installation.
  96. __block FIRInstallationsItem *createdInstallation;
  97. OCMExpect([self.mockInstallationsStore
  98. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  99. [self assertValidCreatedInstallation:obj];
  100. createdInstallation = obj;
  101. return YES;
  102. }]])
  103. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  104. // 3. Stub API register installation.
  105. // 3.1. Verify installation to be registered.
  106. id registerInstallationValidation = [OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  107. [self assertValidCreatedInstallation:obj];
  108. XCTAssertEqual(obj.firebaseInstallationID.length, 22);
  109. return YES;
  110. }];
  111. // 3.2. Expect for `registerInstallation` to be called.
  112. FBLPromise<FIRInstallationsItem *> *registerPromise = [FBLPromise pendingPromise];
  113. OCMExpect([self.mockAPIService registerInstallation:registerInstallationValidation])
  114. .andReturn(registerPromise);
  115. // 4. Expect IIDStore to be checked for existing IID.
  116. [self expectStoredIIDNotFound];
  117. // 5. Call get installation and check.
  118. FBLPromise<FIRInstallationsItem *> *getInstallationPromise =
  119. [self.controller getInstallationItem];
  120. // 5.1. Wait for the stored item to be read and saved.
  121. OCMVerifyAllWithDelay(self.mockInstallationsStore, 0.5);
  122. // 5.2. Wait for `registerInstallation` to be called.
  123. OCMVerifyAllWithDelay(self.mockAPIService, 0.5);
  124. // 5.3. Expect for the registered installation to be saved.
  125. FIRInstallationsItem *registeredInstallation = [FIRInstallationsItem
  126. createRegisteredInstallationItemWithAppID:createdInstallation.appID
  127. appName:createdInstallation.firebaseAppName];
  128. OCMExpect([self.mockInstallationsStore
  129. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  130. XCTAssertEqual(registeredInstallation, obj);
  131. return YES;
  132. }]])
  133. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  134. // 5.5. Resolve `registerPromise` to simulate finished registration.
  135. [registerPromise fulfill:registeredInstallation];
  136. // 5.4. Wait for the task to complete.
  137. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  138. XCTAssertNil(getInstallationPromise.error);
  139. // We expect the initially created installation to be returned - must not wait for registration to
  140. // complete here.
  141. XCTAssertEqual(getInstallationPromise.value, createdInstallation);
  142. // 5.5. Verify registered installation was saved.
  143. OCMVerifyAll(self.mockInstallationsStore);
  144. OCMVerifyAll(self.mockIIDStore);
  145. }
  146. - (void)testGetInstallationItem_WhenThereIsIIDAndNoFIDNotDefaultApp_ThenIIDIsUsedAsFID {
  147. // 0. Configure controller with not default app.
  148. NSString *appName = @"appName";
  149. [self setUpWithAppName:appName];
  150. // 1. Stub store get installation.
  151. [self expectInstallationsStoreGetInstallationNotFound];
  152. // 2. Don't expect IIDStore to be checked for existing IID (not default app).
  153. OCMReject([self.mockIIDStore existingIID]);
  154. // 3. Stub store save installation.
  155. __block FIRInstallationsItem *createdInstallation;
  156. OCMExpect([self.mockInstallationsStore
  157. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  158. [self assertValidCreatedInstallation:obj];
  159. createdInstallation = obj;
  160. return YES;
  161. }]])
  162. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  163. // 4. Stub API register installation.
  164. // 4.1. Verify installation to be registered.
  165. id registerInstallationValidation = [OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  166. [self assertValidCreatedInstallation:obj];
  167. return YES;
  168. }];
  169. // 4.2. Expect for `registerInstallation` to be called.
  170. FBLPromise<FIRInstallationsItem *> *registerPromise = [FBLPromise pendingPromise];
  171. OCMExpect([self.mockAPIService registerInstallation:registerInstallationValidation])
  172. .andReturn(registerPromise);
  173. // 5. Call get installation and check.
  174. FBLPromise<FIRInstallationsItem *> *getInstallationPromise =
  175. [self.controller getInstallationItem];
  176. // 5.1. Wait for the stored item to be read and saved.
  177. OCMVerifyAllWithDelay(self.mockInstallationsStore, 0.5);
  178. // 5.2. Wait for `registerInstallation` to be called.
  179. OCMVerifyAllWithDelay(self.mockAPIService, 0.5);
  180. // 5.3. Expect for the registered installation to be saved.
  181. FIRInstallationsItem *registeredInstallation = [FIRInstallationsItem
  182. createRegisteredInstallationItemWithAppID:createdInstallation.appID
  183. appName:createdInstallation.firebaseAppName];
  184. OCMExpect([self.mockInstallationsStore
  185. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  186. XCTAssertEqual(registeredInstallation, obj);
  187. return YES;
  188. }]])
  189. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  190. // 5.5. Resolve `registerPromise` to simulate finished registration.
  191. [registerPromise fulfill:registeredInstallation];
  192. // 5.4. Wait for the task to complete.
  193. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  194. XCTAssertNil(getInstallationPromise.error);
  195. // We expect the initially created installation to be returned - must not wait for registration to
  196. // complete here.
  197. XCTAssertEqual(getInstallationPromise.value, createdInstallation);
  198. // 5.5. Verify registered installation was saved.
  199. OCMVerifyAll(self.mockInstallationsStore);
  200. OCMVerifyAll(self.mockIIDStore);
  201. }
  202. - (void)testGetInstallationItem_WhenThereIsIIDAndNoFID_ThenFIDIsCreatedAndRegistered {
  203. // 1. Stub store get installation.
  204. [self expectInstallationsStoreGetInstallationNotFound];
  205. // 2. Expect IIDStore to be checked for existing IID.
  206. NSString *existingIID = @"existing-iid";
  207. OCMExpect([self.mockIIDStore existingIID]).andReturn([FBLPromise resolvedWith:existingIID]);
  208. // 3. Expect IID checkin store to be requested for checkin data.
  209. NSString *existingIIDDefaultToken = @"existing-iid-token";
  210. OCMExpect([self.mockIIDTokenStore existingIIDDefaultToken])
  211. .andReturn([FBLPromise resolvedWith:existingIIDDefaultToken]);
  212. // 3. Stub store save installation.
  213. __block FIRInstallationsItem *createdInstallation;
  214. OCMExpect([self.mockInstallationsStore
  215. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  216. [self assertValidCreatedInstallation:obj];
  217. XCTAssertEqualObjects(existingIID, obj.firebaseInstallationID);
  218. XCTAssertEqualObjects(obj.IIDDefaultToken, existingIIDDefaultToken);
  219. createdInstallation = obj;
  220. return YES;
  221. }]])
  222. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  223. // 4. Stub API register installation.
  224. // 4.1. Verify installation to be registered.
  225. id registerInstallationValidation = [OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  226. [self assertValidCreatedInstallation:obj];
  227. XCTAssertEqualObjects(existingIID, obj.firebaseInstallationID);
  228. return YES;
  229. }];
  230. // 4.2. Expect for `registerInstallation` to be called.
  231. FBLPromise<FIRInstallationsItem *> *registerPromise = [FBLPromise pendingPromise];
  232. OCMExpect([self.mockAPIService registerInstallation:registerInstallationValidation])
  233. .andReturn(registerPromise);
  234. // 5. Call get installation and check.
  235. FBLPromise<FIRInstallationsItem *> *getInstallationPromise =
  236. [self.controller getInstallationItem];
  237. // 5.1. Wait for the stored item to be read and saved.
  238. OCMVerifyAllWithDelay(self.mockInstallationsStore, 0.5);
  239. // 5.2. Wait for `registerInstallation` to be called.
  240. OCMVerifyAllWithDelay(self.mockAPIService, 0.5);
  241. // 5.3. Expect for the registered installation to be saved.
  242. FIRInstallationsItem *registeredInstallation = [FIRInstallationsItem
  243. createRegisteredInstallationItemWithAppID:createdInstallation.appID
  244. appName:createdInstallation.firebaseAppName];
  245. OCMExpect([self.mockInstallationsStore
  246. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  247. XCTAssertEqual(registeredInstallation, obj);
  248. return YES;
  249. }]])
  250. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  251. // 5.5. Resolve `registerPromise` to simulate finished registration.
  252. [registerPromise fulfill:registeredInstallation];
  253. // 5.4. Wait for the task to complete.
  254. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  255. XCTAssertNil(getInstallationPromise.error);
  256. // We expect the initially created installation to be returned - must not wait for registration to
  257. // complete here.
  258. XCTAssertEqual(getInstallationPromise.value, createdInstallation);
  259. // 5.5. Verify registered installation was saved.
  260. OCMVerifyAll(self.mockInstallationsStore);
  261. OCMVerifyAll(self.mockIIDStore);
  262. OCMVerifyAll(self.mockIIDTokenStore);
  263. }
  264. - (void)testGetInstallationItem_WhenCalledSeveralTimes_OnlyOneOperationIsPerformed {
  265. // 1. Expect the installation to be requested from the store only once.
  266. FIRInstallationsItem *storedInstallation1 =
  267. [FIRInstallationsItem createRegisteredInstallationItem];
  268. FBLPromise<FIRInstallationsItem *> *pendingStorePromise = [FBLPromise pendingPromise];
  269. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  270. .andReturn(pendingStorePromise);
  271. // 3. Request installation n times
  272. NSInteger requestCount = 10;
  273. NSMutableArray *installationPromises = [NSMutableArray arrayWithCapacity:requestCount];
  274. for (NSInteger i = 0; i < requestCount; i++) {
  275. [installationPromises addObject:[self.controller getInstallationItem]];
  276. }
  277. // 4. Resolve store promise.
  278. [pendingStorePromise fulfill:storedInstallation1];
  279. // 5. Wait for operation to be completed and check.
  280. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  281. for (FBLPromise<FIRInstallationsItem *> *installationPromise in installationPromises) {
  282. XCTAssertNil(installationPromise.error);
  283. XCTAssertEqual(installationPromise.value, storedInstallation1);
  284. }
  285. OCMVerifyAll(self.mockInstallationsStore);
  286. OCMVerifyAll(self.mockAPIService);
  287. // 6. Check that a new request is performed once previous finished.
  288. FIRInstallationsItem *storedInstallation2 =
  289. [FIRInstallationsItem createRegisteredInstallationItem];
  290. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  291. .andReturn([FBLPromise resolvedWith:storedInstallation2]);
  292. FBLPromise<FIRInstallationsItem *> *installationPromise = [self.controller getInstallationItem];
  293. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  294. XCTAssertNil(installationPromise.error);
  295. XCTAssertEqual(installationPromise.value, storedInstallation2);
  296. OCMVerifyAll(self.mockInstallationsStore);
  297. OCMVerifyAll(self.mockAPIService);
  298. }
  299. #pragma mark - Get Auth Token
  300. - (void)testGetAuthToken_WhenValidInstallationExists_ThenItIsReturned {
  301. // 1. Expect installation to be requested from the store.
  302. FIRInstallationsItem *storedInstallation =
  303. [FIRInstallationsItem createRegisteredInstallationItem];
  304. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  305. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  306. // 2. Request auth token.
  307. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getAuthTokenForcingRefresh:NO];
  308. // 3. Wait for the promise to resolve.
  309. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  310. // 4. Check.
  311. OCMVerifyAll(self.mockInstallationsStore);
  312. OCMVerifyAll(self.mockAPIService);
  313. XCTAssertNil(promise.error);
  314. XCTAssertNotNil(promise.value);
  315. XCTAssertEqualObjects(promise.value.authToken.token, storedInstallation.authToken.token);
  316. XCTAssertEqualObjects(promise.value.authToken.expirationDate,
  317. storedInstallation.authToken.expirationDate);
  318. }
  319. - (void)testGetAuthToken_WhenValidInstallationWithExpiredTokenExists_ThenTokenRequested {
  320. // 1.1. Expect installation to be requested from the store.
  321. FIRInstallationsItem *storedInstallation =
  322. [FIRInstallationsItem createRegisteredInstallationItem];
  323. storedInstallation.authToken.expirationDate = [NSDate dateWithTimeIntervalSinceNow:60 * 60 - 1];
  324. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  325. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  326. // 1.2. Auth Token refresh.
  327. FIRInstallationsItem *responseInstallation =
  328. [self expectAuthTokenRefreshForInstallation:storedInstallation];
  329. // 2. Request auth token.
  330. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getAuthTokenForcingRefresh:NO];
  331. // 3. Wait for the promise to resolve.
  332. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  333. // 4. Check.
  334. OCMVerifyAll(self.mockInstallationsStore);
  335. OCMVerifyAll(self.mockAPIService);
  336. XCTAssertNil(promise.error);
  337. XCTAssertNotNil(promise.value);
  338. XCTAssertEqualObjects(promise.value.authToken.token, responseInstallation.authToken.token);
  339. XCTAssertEqualObjects(promise.value.authToken.expirationDate,
  340. responseInstallation.authToken.expirationDate);
  341. }
  342. - (void)testGetAuthTokenForcingRefresh_WhenValidInstallationExists_ThenTokenRequested {
  343. // 1.1. Expect installation to be requested from the store.
  344. FIRInstallationsItem *storedInstallation =
  345. [FIRInstallationsItem createRegisteredInstallationItem];
  346. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  347. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  348. // 1.2. Auth Token refresh.
  349. FIRInstallationsItem *responseInstallation =
  350. [self expectAuthTokenRefreshForInstallation:storedInstallation];
  351. // 2. Request auth token.
  352. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getAuthTokenForcingRefresh:YES];
  353. // 3. Wait for the promise to resolve.
  354. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  355. // 4. Check.
  356. OCMVerifyAll(self.mockInstallationsStore);
  357. OCMVerifyAll(self.mockAPIService);
  358. XCTAssertNil(promise.error);
  359. XCTAssertNotNil(promise.value);
  360. XCTAssertEqualObjects(promise.value.authToken.token, responseInstallation.authToken.token);
  361. XCTAssertEqualObjects(promise.value.authToken.expirationDate,
  362. responseInstallation.authToken.expirationDate);
  363. }
  364. - (void)testGetAuthToken_WhenCalledSeveralTimes_OnlyOneOperationIsPerformed {
  365. // 1. Expect installation to be requested from the store.
  366. FIRInstallationsItem *storedInstallation =
  367. [FIRInstallationsItem createRegisteredInstallationItem];
  368. FBLPromise *storagePendingPromise = [FBLPromise pendingPromise];
  369. // Expect the installation to be requested only once.
  370. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  371. .andReturn(storagePendingPromise);
  372. // 2. Request auth token n times.
  373. NSInteger requestCount = 10;
  374. NSMutableArray *authTokenPromises = [NSMutableArray arrayWithCapacity:requestCount];
  375. for (NSInteger i = 0; i < requestCount; i++) {
  376. [authTokenPromises addObject:[self.controller getAuthTokenForcingRefresh:NO]];
  377. }
  378. // 3. Finish the storage request.
  379. [storagePendingPromise fulfill:storedInstallation];
  380. // 4. Wait for the promise to resolve.
  381. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  382. // 5. Check.
  383. OCMVerifyAll(self.mockInstallationsStore);
  384. for (FBLPromise<FIRInstallationsItem *> *authPromise in authTokenPromises) {
  385. XCTAssertNil(authPromise.error);
  386. XCTAssertNotNil(authPromise.value);
  387. XCTAssertEqualObjects(authPromise.value.authToken.token, storedInstallation.authToken.token);
  388. XCTAssertEqualObjects(authPromise.value.authToken.expirationDate,
  389. storedInstallation.authToken.expirationDate);
  390. }
  391. }
  392. - (void)testGetAuthTokenForceRefresh_WhenCalledSeveralTimes_OnlyOneOperationIsPerformed {
  393. // 1.1. Expect installation to be requested from the store.
  394. FIRInstallationsItem *storedInstallation =
  395. [FIRInstallationsItem createRegisteredInstallationItem];
  396. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  397. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  398. // 1.2. Expect API request.
  399. FIRInstallationsItem *responseInstallation =
  400. [FIRInstallationsItem createRegisteredInstallationItem];
  401. responseInstallation.authToken.token =
  402. [responseInstallation.authToken.token stringByAppendingString:@"_new"];
  403. FBLPromise *pendingAPIPromise = [FBLPromise pendingPromise];
  404. OCMExpect([self.mockAPIService refreshAuthTokenForInstallation:storedInstallation])
  405. .andReturn(pendingAPIPromise);
  406. // 1.3. Expect new token to be stored.
  407. OCMExpect([self.mockInstallationsStore saveInstallation:responseInstallation])
  408. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  409. // 2. Request auth token n times.
  410. NSInteger requestCount = 10;
  411. NSMutableArray *authTokenPromises = [NSMutableArray arrayWithCapacity:requestCount];
  412. for (NSInteger i = 0; i < requestCount; i++) {
  413. [authTokenPromises addObject:[self.controller getAuthTokenForcingRefresh:YES]];
  414. }
  415. // 3. Finish the API request.
  416. [pendingAPIPromise fulfill:responseInstallation];
  417. // 4. Wait for the promise to resolve.
  418. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  419. // 5. Check.
  420. OCMVerifyAll(self.mockInstallationsStore);
  421. for (FBLPromise<FIRInstallationsItem *> *authPromise in authTokenPromises) {
  422. XCTAssertNil(authPromise.error);
  423. XCTAssertNotNil(authPromise.value);
  424. XCTAssertEqualObjects(authPromise.value.authToken.token, responseInstallation.authToken.token);
  425. XCTAssertEqualObjects(authPromise.value.authToken.expirationDate,
  426. responseInstallation.authToken.expirationDate);
  427. }
  428. }
  429. - (void)testGetAuthToken_WhenAPIResponse401_ThenFISResetAndReregistered {
  430. NSTimeInterval timeout = 0.5;
  431. // 1.1. Expect installation to be requested from the store.
  432. FIRInstallationsItem *storedInstallation =
  433. [FIRInstallationsItem createRegisteredInstallationItem];
  434. [self expectInstallationStoreToBeRequestedAndReturnInstallation:storedInstallation];
  435. // 1.2. Expect API request.
  436. FBLPromise *rejectedAPIPromise = [FBLPromise pendingPromise];
  437. OCMExpect([self.mockAPIService refreshAuthTokenForInstallation:storedInstallation])
  438. .andReturn(rejectedAPIPromise);
  439. // 2. Request auth token.
  440. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getAuthTokenForcingRefresh:YES];
  441. // 3. Wait for refresh token request.
  442. OCMVerifyAllWithDelay(self.mockAPIService, timeout);
  443. // 4.1. Expect Installation to be requested before deletion.
  444. [self expectInstallationStoreToBeRequestedAndReturnInstallation:storedInstallation];
  445. // 4. Expect for FIS to be deleted locally.
  446. NSArray<XCTestExpectation *> *deleteExpectations =
  447. [self expectInstallationToBeDeletedLocally:storedInstallation];
  448. // 6. Expect a new installation to be created and registered.
  449. // 6.1. Expect to request FIS from storage.
  450. [self expectInstallationsStoreGetInstallationNotFound];
  451. // 6.2. Expect stored IID not found.
  452. [self expectStoredIIDNotFound];
  453. // 6.3. Expect new Installation to be stored.
  454. __block FIRInstallationsItem *createdInstallation;
  455. OCMExpect([self.mockInstallationsStore
  456. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  457. [self assertValidCreatedInstallation:obj];
  458. createdInstallation = obj;
  459. return YES;
  460. }]])
  461. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  462. // 6.4. Expect registration API request to be sent.
  463. FBLPromise<FIRInstallationsItem *> *registerPromise = [FBLPromise pendingPromise];
  464. OCMExpect([self.mockAPIService registerInstallation:[OCMArg any]]).andReturn(registerPromise);
  465. // 6.5. Reject API request promise with 401.
  466. NSError *error401 = [FIRInstallationsErrorUtil APIErrorWithHTTPCode:404];
  467. [rejectedAPIPromise reject:error401];
  468. // 6.6. Wait local FIS to be deleted.
  469. [self waitForExpectations:deleteExpectations timeout:timeout];
  470. // 6.7 Wait for the new Installation to be stored.
  471. OCMVerifyAllWithDelay(self.mockInstallationsStore, timeout);
  472. // 6.8. Wait for registration API request to be sent.
  473. OCMVerifyAllWithDelay(self.mockAPIService, timeout);
  474. // 6.9. Expect for the registered installation to be saved.
  475. FIRInstallationsItem *registeredInstallation = [FIRInstallationsItem
  476. createRegisteredInstallationItemWithAppID:createdInstallation.appID
  477. appName:createdInstallation.firebaseAppName];
  478. OCMExpect([self.mockInstallationsStore
  479. saveInstallation:[OCMArg checkWithBlock:^BOOL(FIRInstallationsItem *obj) {
  480. XCTAssertEqual(registeredInstallation, obj);
  481. return YES;
  482. }]])
  483. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  484. // 6.9. Fulfill the registration API request promise.
  485. [registerPromise fulfill:registeredInstallation];
  486. // 7. Wait for promises.
  487. XCTAssert(FBLWaitForPromisesWithTimeout(timeout));
  488. // 8. Check.
  489. OCMVerifyAll(self.mockInstallationsStore);
  490. OCMVerifyAll(self.mockAPIService);
  491. XCTAssertNil(promise.error);
  492. XCTAssertNotNil(promise.value);
  493. XCTAssertNotEqualObjects(promise.value.firebaseInstallationID,
  494. storedInstallation.firebaseInstallationID);
  495. XCTAssertEqualObjects(promise.value, registeredInstallation);
  496. }
  497. #pragma mark - FID Deletion
  498. - (void)testDeleteRegisteredInstallation {
  499. // 1. Expect installation to be requested from the store.
  500. FIRInstallationsItem *installation = [FIRInstallationsItem createRegisteredInstallationItem];
  501. OCMExpect([self.mockInstallationsStore installationForAppID:installation.appID
  502. appName:installation.firebaseAppName])
  503. .andReturn([FBLPromise resolvedWith:installation]);
  504. // 2. Expect API request to delete installation.
  505. OCMExpect([self.mockAPIService deleteInstallation:installation])
  506. .andReturn([FBLPromise resolvedWith:installation]);
  507. // 3.1. Expect the installation to be removed from the storage.
  508. OCMExpect([self.mockInstallationsStore removeInstallationForAppID:installation.appID
  509. appName:installation.firebaseAppName])
  510. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  511. // 3.2. Expect IID to be deleted, because it is default app.
  512. OCMExpect([self.mockIIDStore deleteExistingIID])
  513. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  514. // 4. Expect FIRInstallationIDDidChangeNotification to be sent.
  515. XCTestExpectation *notificationExpectation =
  516. [self installationIDDidChangeNotificationExpectation];
  517. // 5. Call delete installation.
  518. FBLPromise<NSNull *> *promise = [self.controller deleteInstallation];
  519. // 6. Wait for operations to complete and check.
  520. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  521. XCTAssertNil(promise.error);
  522. XCTAssertTrue(promise.isFulfilled);
  523. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  524. OCMVerifyAll(self.mockInstallationsStore);
  525. OCMVerifyAll(self.mockAPIService);
  526. OCMVerifyAll(self.mockIIDStore);
  527. }
  528. - (void)testDeleteUnregisteredInstallation {
  529. // 1. Expect installation to be requested from the store.
  530. FIRInstallationsItem *installation = [FIRInstallationsItem createUnregisteredInstallationItem];
  531. OCMExpect([self.mockInstallationsStore installationForAppID:installation.appID
  532. appName:installation.firebaseAppName])
  533. .andReturn([FBLPromise resolvedWith:installation]);
  534. // 2. Don't expect API request to delete installation.
  535. OCMReject([self.mockAPIService deleteInstallation:[OCMArg any]]);
  536. // 3.1. Expect the installation to be removed from the storage.
  537. OCMExpect([self.mockInstallationsStore removeInstallationForAppID:installation.appID
  538. appName:installation.firebaseAppName])
  539. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  540. // 3.2. Expect IID to be deleted, because it is default app.
  541. OCMExpect([self.mockIIDStore deleteExistingIID])
  542. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  543. // 4. Expect FIRInstallationIDDidChangeNotification to be sent.
  544. XCTestExpectation *notificationExpectation =
  545. [self installationIDDidChangeNotificationExpectation];
  546. // 5. Call delete installation.
  547. FBLPromise<NSNull *> *promise = [self.controller deleteInstallation];
  548. // 6. Wait for operations to complete and check.
  549. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  550. XCTAssertNil(promise.error);
  551. XCTAssertTrue(promise.isFulfilled);
  552. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  553. OCMVerifyAll(self.mockInstallationsStore);
  554. OCMVerifyAll(self.mockAPIService);
  555. OCMVerifyAll(self.mockIIDStore);
  556. }
  557. - (void)testDeleteRegisteredInstallation_WhenAPIRequestFails_ThenFailsAndInstallationIsNotRemoved {
  558. // 1. Expect installation to be requested from the store.
  559. FIRInstallationsItem *installation = [FIRInstallationsItem createRegisteredInstallationItem];
  560. OCMExpect([self.mockInstallationsStore installationForAppID:installation.appID
  561. appName:installation.firebaseAppName])
  562. .andReturn([FBLPromise resolvedWith:installation]);
  563. // 2. Expect API request to delete installation.
  564. FBLPromise *rejectedAPIPromise = [FBLPromise pendingPromise];
  565. NSError *error500 =
  566. [FIRInstallationsErrorUtil APIErrorWithHTTPCode:FIRInstallationsHTTPCodesServerInternalError];
  567. [rejectedAPIPromise reject:error500];
  568. OCMExpect([self.mockAPIService deleteInstallation:installation]).andReturn(rejectedAPIPromise);
  569. // 3.1. Don't expect the installation to be removed from the storage.
  570. OCMReject([self.mockInstallationsStore removeInstallationForAppID:[OCMArg any]
  571. appName:[OCMArg any]]);
  572. // 3.2. Don't expect IID to be deleted.
  573. OCMReject([self.mockIIDStore deleteExistingIID]);
  574. // 4. Don't expect FIRInstallationIDDidChangeNotification to be sent.
  575. XCTestExpectation *notificationExpectation =
  576. [self installationIDDidChangeNotificationExpectation];
  577. notificationExpectation.inverted = YES;
  578. // 5. Call delete installation.
  579. FBLPromise<NSNull *> *promise = [self.controller deleteInstallation];
  580. // 6. Wait for operations to complete and check.
  581. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  582. XCTAssertEqualObjects(promise.error, error500);
  583. XCTAssertTrue(promise.isRejected);
  584. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  585. OCMVerifyAll(self.mockInstallationsStore);
  586. OCMVerifyAll(self.mockAPIService);
  587. OCMVerifyAll(self.mockIIDStore);
  588. }
  589. - (void)testDeleteRegisteredInstallation_WhenAPIFailsWithNotFound_ThenInstallationIsRemoved {
  590. // 1. Expect installation to be requested from the store.
  591. FIRInstallationsItem *installation = [FIRInstallationsItem createRegisteredInstallationItem];
  592. OCMExpect([self.mockInstallationsStore installationForAppID:installation.appID
  593. appName:installation.firebaseAppName])
  594. .andReturn([FBLPromise resolvedWith:installation]);
  595. // 2. Expect API request to delete installation.
  596. FBLPromise *rejectedAPIPromise = [FBLPromise pendingPromise];
  597. [rejectedAPIPromise reject:[FIRInstallationsErrorUtil APIErrorWithHTTPCode:404]];
  598. OCMExpect([self.mockAPIService deleteInstallation:installation]).andReturn(rejectedAPIPromise);
  599. // 3. Expect the installation to be removed from the storage.
  600. OCMExpect([self.mockInstallationsStore removeInstallationForAppID:installation.appID
  601. appName:installation.firebaseAppName])
  602. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  603. // 3.2. Expect IID to be deleted, because it is default app.
  604. OCMExpect([self.mockIIDStore deleteExistingIID])
  605. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  606. // 4. Expect FIRInstallationIDDidChangeNotification to be sent.
  607. XCTestExpectation *notificationExpectation =
  608. [self installationIDDidChangeNotificationExpectation];
  609. // 5. Call delete installation.
  610. FBLPromise<NSNull *> *promise = [self.controller deleteInstallation];
  611. // 6. Wait for operations to complete and check.
  612. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  613. XCTAssertNil(promise.error);
  614. XCTAssertTrue(promise.isFulfilled);
  615. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  616. OCMVerifyAll(self.mockInstallationsStore);
  617. OCMVerifyAll(self.mockAPIService);
  618. OCMVerifyAll(self.mockIIDStore);
  619. }
  620. - (void)testDeleteInstallation_WhenThereIsOngoingAuthTokenRequest_ThenUsesItsResult {
  621. // 1. Stub mocks for auth token request.
  622. // 1.1. Expect installation to be requested from the store.
  623. FIRInstallationsItem *storedInstallation =
  624. [FIRInstallationsItem createRegisteredInstallationItem];
  625. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  626. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  627. // 1.2. Expect API request.
  628. FIRInstallationsItem *responseInstallation =
  629. [FIRInstallationsItem createRegisteredInstallationItem];
  630. responseInstallation.authToken.token =
  631. [responseInstallation.authToken.token stringByAppendingString:@"_new"];
  632. FBLPromise *pendingAuthTokenAPIPromise = [FBLPromise pendingPromise];
  633. OCMExpect([self.mockAPIService refreshAuthTokenForInstallation:storedInstallation])
  634. .andReturn(pendingAuthTokenAPIPromise);
  635. // 2. Send auth token request.
  636. [self.controller getAuthTokenForcingRefresh:YES];
  637. OCMVerifyAllWithDelay(self.mockInstallationsStore, 0.5);
  638. OCMVerifyAllWithDelay(self.mockAPIService, 0.5);
  639. // 3. Delete installation.
  640. // 3.1. Don't expect installation to be requested from the store.
  641. OCMReject([self.mockInstallationsStore installationForAppID:[OCMArg any] appName:[OCMArg any]]);
  642. // 3.2. Expect API request to delete the UPDATED installation.
  643. OCMExpect([self.mockAPIService deleteInstallation:responseInstallation])
  644. .andReturn([FBLPromise resolvedWith:responseInstallation]);
  645. // 3.3. Expect the UPDATED installation to be removed from the storage.
  646. OCMExpect([self.mockInstallationsStore
  647. removeInstallationForAppID:responseInstallation.appID
  648. appName:responseInstallation.firebaseAppName])
  649. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  650. // 3.4. Expect IID to be deleted, because it is default app.
  651. OCMExpect([self.mockIIDStore deleteExistingIID])
  652. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  653. // 3.4. Call delete installation.
  654. FBLPromise<NSNull *> *deletePromise = [self.controller deleteInstallation];
  655. // 4. Fulfill auth token promise to proceed.
  656. // 4.1. Expect new token to be stored on API response.
  657. OCMExpect([self.mockInstallationsStore saveInstallation:responseInstallation])
  658. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  659. [pendingAuthTokenAPIPromise fulfill:responseInstallation];
  660. // 5. Wait for operations to complete and check the result.
  661. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  662. XCTAssertNil(deletePromise.error);
  663. XCTAssertTrue(deletePromise.isFulfilled);
  664. OCMVerifyAll(self.mockInstallationsStore);
  665. OCMVerifyAll(self.mockAPIService);
  666. OCMVerifyAll(self.mockIIDStore);
  667. }
  668. - (void)testDeleteInstallation_WhenNotDefaultApp_ThenIIDIsNotDeleted {
  669. // 0. Configure controller for not default app.
  670. NSString *appName = @"appName";
  671. [self setUpWithAppName:appName];
  672. // 1. Expect installation to be requested from the store.
  673. FIRInstallationsItem *installation =
  674. [FIRInstallationsItem createRegisteredInstallationItemWithAppID:self.appID appName:appName];
  675. OCMExpect([self.mockInstallationsStore installationForAppID:installation.appID
  676. appName:installation.firebaseAppName])
  677. .andReturn([FBLPromise resolvedWith:installation]);
  678. // 2. Expect API request to delete installation.
  679. OCMExpect([self.mockAPIService deleteInstallation:installation])
  680. .andReturn([FBLPromise resolvedWith:installation]);
  681. // 3.1. Expect the installation to be removed from the storage.
  682. OCMExpect([self.mockInstallationsStore removeInstallationForAppID:installation.appID
  683. appName:installation.firebaseAppName])
  684. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  685. // 3.2. Don't expect IID to be deleted, because it is not a default app.
  686. OCMReject([self.mockIIDStore deleteExistingIID]);
  687. // 4. Expect FIRInstallationIDDidChangeNotification to be sent.
  688. XCTestExpectation *notificationExpectation =
  689. [self installationIDDidChangeNotificationExpectation];
  690. // 5. Call delete installation.
  691. FBLPromise<NSNull *> *promise = [self.controller deleteInstallation];
  692. // 6. Wait for operations to complete and check.
  693. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  694. XCTAssertNil(promise.error);
  695. XCTAssertTrue(promise.isFulfilled);
  696. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  697. OCMVerifyAll(self.mockInstallationsStore);
  698. OCMVerifyAll(self.mockAPIService);
  699. OCMVerifyAll(self.mockIIDStore);
  700. }
  701. - (NSArray<XCTestExpectation *> *)expectInstallationToBeDeletedLocally:
  702. (FIRInstallationsItem *)installation {
  703. // 3.1. Expect the installation to be removed from the storage.
  704. OCMExpect([self.mockInstallationsStore removeInstallationForAppID:installation.appID
  705. appName:installation.firebaseAppName])
  706. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  707. // 3.2. Expect IID to be deleted, because it is default app.
  708. OCMExpect([self.mockIIDStore deleteExistingIID])
  709. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  710. // 4. Expect FIRInstallationIDDidChangeNotification to be sent.
  711. XCTestExpectation *notificationExpectation =
  712. [self installationIDDidChangeNotificationExpectation];
  713. return @[ notificationExpectation ];
  714. }
  715. // TODO: Test a single delete installation request at a time.
  716. #pragma mark - Notifications
  717. - (void)testFIDDidChangeNotificationIsSentWhenFIDCreated {
  718. // 1. Stub - no installation.
  719. // 1.2. FID store.
  720. [self expectInstallationsStoreGetInstallationNotFound];
  721. OCMStub([self.mockInstallationsStore saveInstallation:[OCMArg any]])
  722. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  723. // 1.3. IID store.
  724. [self expectStoredIIDNotFound];
  725. // 1.4. API Service.
  726. OCMExpect([self.mockAPIService registerInstallation:[OCMArg any]])
  727. .andReturn([FBLPromise resolvedWith:[FIRInstallationsItem createRegisteredInstallationItem]]);
  728. // 2. Expect FIRInstallationIDDidChangeNotification to be sent.
  729. XCTestExpectation *notificationExpectation =
  730. [self installationIDDidChangeNotificationExpectation];
  731. // 3. Request FID.
  732. FBLPromise *promise = [self.controller getInstallationItem];
  733. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  734. // 4. Check.
  735. XCTAssertNil(promise.error);
  736. XCTAssertNotNil(promise.value);
  737. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  738. OCMVerifyAll(self.mockInstallationsStore);
  739. OCMVerifyAll(self.mockIIDStore);
  740. OCMVerifyAll(self.mockAPIService);
  741. }
  742. - (void)testRegisterInstallation_WhenServerRespondsWithDifferentFID_ThenFIDDidChangeNotification {
  743. // 1.1. Expect installation to be requested from the store.
  744. FIRInstallationsItem *storedInstallation =
  745. [FIRInstallationsItem createUnregisteredInstallationItem];
  746. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  747. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  748. // 1.2. Expect register FID to be called.
  749. FIRInstallationsItem *receivedInstallation =
  750. [FIRInstallationsItem createRegisteredInstallationItem];
  751. receivedInstallation.firebaseInstallationID =
  752. [storedInstallation.firebaseInstallationID stringByAppendingString:@"_new"];
  753. OCMExpect([self.mockAPIService registerInstallation:storedInstallation])
  754. .andReturn([FBLPromise resolvedWith:receivedInstallation]);
  755. // 1.3. Expect the received installation to be stored.
  756. OCMExpect([self.mockInstallationsStore saveInstallation:receivedInstallation])
  757. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  758. // 2. Expect FIRInstallationIDDidChangeNotification to be sent.
  759. XCTestExpectation *notificationExpectation =
  760. [self installationIDDidChangeNotificationExpectation];
  761. // 3. Request Auth Token.
  762. FBLPromise<FIRInstallationsItem *> *promise = [self.controller getAuthTokenForcingRefresh:NO];
  763. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  764. // 4. Check.
  765. XCTAssertNil(promise.error);
  766. XCTAssertNotNil(promise.value);
  767. XCTAssertEqualObjects(promise.value.firebaseInstallationID,
  768. receivedInstallation.firebaseInstallationID);
  769. [self waitForExpectations:@[ notificationExpectation ] timeout:0.5];
  770. OCMVerifyAll(self.mockInstallationsStore);
  771. OCMVerifyAll(self.mockAPIService);
  772. }
  773. #pragma mark - Helpers
  774. - (void)expectInstallationsStoreGetInstallationNotFound {
  775. NSError *notFoundError =
  776. [FIRInstallationsErrorUtil installationItemNotFoundForAppID:self.appID appName:self.appName];
  777. FBLPromise *installationNotFoundPromise = [FBLPromise pendingPromise];
  778. [installationNotFoundPromise reject:notFoundError];
  779. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  780. .andReturn(installationNotFoundPromise);
  781. }
  782. - (void)expectStoredIIDNotFound {
  783. FBLPromise *rejectedPromise = [FBLPromise pendingPromise];
  784. [rejectedPromise reject:[FIRInstallationsErrorUtil keychainErrorWithFunction:@"" status:-1]];
  785. OCMExpect([self.mockIIDStore existingIID]).andReturn(rejectedPromise);
  786. OCMExpect([self.mockIIDTokenStore existingIIDDefaultToken]).andReturn(rejectedPromise);
  787. }
  788. - (void)assertValidCreatedInstallation:(FIRInstallationsItem *)installation {
  789. XCTAssertEqualObjects([installation class], [FIRInstallationsItem class]);
  790. XCTAssertEqualObjects(installation.appID, self.appID);
  791. XCTAssertEqualObjects(installation.firebaseAppName, self.appName);
  792. XCTAssertEqual(installation.registrationStatus, FIRInstallationStatusUnregistered);
  793. XCTAssertNotNil(installation.firebaseInstallationID);
  794. }
  795. - (XCTestExpectation *)installationIDDidChangeNotificationExpectation {
  796. XCTestExpectation *notificationExpectation = [self
  797. expectationForNotification:FIRInstallationIDDidChangeNotification
  798. object:nil
  799. handler:^BOOL(NSNotification *_Nonnull notification) {
  800. XCTAssertEqualObjects(
  801. notification
  802. .userInfo[kFIRInstallationIDDidChangeNotificationAppNameKey],
  803. self.appName);
  804. return YES;
  805. }];
  806. return notificationExpectation;
  807. }
  808. - (void)expectInstallationStoreToBeRequestedAndReturnInstallation:
  809. (FIRInstallationsItem *)storedInstallation {
  810. OCMExpect([self.mockInstallationsStore installationForAppID:self.appID appName:self.appName])
  811. .andReturn([FBLPromise resolvedWith:storedInstallation]);
  812. }
  813. - (FIRInstallationsItem *)expectAuthTokenRefreshForInstallation:
  814. (FIRInstallationsItem *)installation {
  815. FIRInstallationsItem *responseInstallation =
  816. [FIRInstallationsItem createRegisteredInstallationItem];
  817. responseInstallation.authToken.token =
  818. [responseInstallation.authToken.token stringByAppendingString:@"_new"];
  819. OCMExpect([self.mockAPIService refreshAuthTokenForInstallation:installation])
  820. .andReturn([FBLPromise resolvedWith:responseInstallation]);
  821. // 1.3. Expect new token to be stored.
  822. OCMExpect([self.mockInstallationsStore saveInstallation:responseInstallation])
  823. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  824. return responseInstallation;
  825. }
  826. @end