FIRInstallationsStoreTests.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 <GoogleUtilities/GULUserDefaults.h>
  19. #import "FBLPromise+Testing.h"
  20. #import "FIRInstallationsErrorUtil.h"
  21. #import "FIRInstallationsItem+Tests.h"
  22. #import "FIRInstallationsItem.h"
  23. #import "FIRInstallationsStore.h"
  24. #import "FIRInstallationsStoredItem.h"
  25. #import "FIRSecureStorage.h"
  26. @interface FIRInstallationsStoreTests : XCTestCase
  27. @property(nonatomic) NSString *accessGroup;
  28. @property(nonatomic) FIRInstallationsStore *store;
  29. @property(nonatomic) id mockSecureStorage;
  30. @property(nonatomic) GULUserDefaults *userDefaults;
  31. @end
  32. @implementation FIRInstallationsStoreTests
  33. - (void)setUp {
  34. self.accessGroup = @"accessGroup";
  35. self.mockSecureStorage = OCMClassMock([FIRSecureStorage class]);
  36. self.store = [[FIRInstallationsStore alloc] initWithSecureStorage:self.mockSecureStorage
  37. accessGroup:self.accessGroup];
  38. // TODO: Replace real user defaults by an injected mock or a test specific user defaults instance
  39. // with a specific suite name.
  40. self.userDefaults =
  41. [[GULUserDefaults alloc] initWithSuiteName:kFIRInstallationsStoreUserDefaultsID];
  42. }
  43. - (void)tearDown {
  44. self.userDefaults = nil;
  45. self.store = nil;
  46. self.mockSecureStorage = nil;
  47. [self.mockSecureStorage stopMocking];
  48. }
  49. - (void)testInstallationID_WhenNoUserDefaultsItem_ThenNotFound {
  50. NSString *appID = @"123";
  51. NSString *appName = @"name";
  52. NSString *itemID = [self itemIDWithAppID:appID appName:appName];
  53. [self.userDefaults removeObjectForKey:itemID];
  54. // Check with empty keychain.
  55. OCMReject([self.mockSecureStorage getObjectForKey:[OCMArg any]
  56. objectClass:[OCMArg any]
  57. accessGroup:[OCMArg any]]);
  58. [self assertInstallationIDNotFoundForAppID:appID appName:appName];
  59. OCMVerifyAll(self.mockSecureStorage);
  60. }
  61. - (void)testInstallationID_WhenThereIsUserDefaultsAndKeychain_ThenReturnsItem {
  62. NSString *appID = @"123";
  63. NSString *appName = @"name";
  64. NSString *itemID = [self itemIDWithAppID:appID appName:appName];
  65. [self.userDefaults setObject:@(YES) forKey:itemID];
  66. FIRInstallationsStoredItem *storedItem = [self createValidStoredItem];
  67. OCMExpect([self.mockSecureStorage getObjectForKey:itemID
  68. objectClass:[FIRInstallationsStoredItem class]
  69. accessGroup:self.accessGroup])
  70. .andReturn([FBLPromise resolvedWith:storedItem]);
  71. FBLPromise<FIRInstallationsItem *> *itemPromise = [self.store installationForAppID:appID
  72. appName:appName];
  73. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  74. XCTAssertTrue(itemPromise.isFulfilled);
  75. XCTAssertNil(itemPromise.error);
  76. XCTAssertNotNil(itemPromise.value);
  77. FIRInstallationsItem *item = itemPromise.value;
  78. XCTAssertEqualObjects(item.appID, appID);
  79. XCTAssertEqualObjects(item.firebaseAppName, appName);
  80. [self assertStoredItem:storedItem correspondsToItem:item];
  81. OCMVerifyAll(self.mockSecureStorage);
  82. }
  83. - (void)testInstallationID_WhenThereIsUserDefaultsAndNoKeychain_ThenNotFound {
  84. NSString *appID = @"123";
  85. NSString *appName = @"name";
  86. NSString *itemID = [self itemIDWithAppID:appID appName:appName];
  87. [self.userDefaults setObject:@(YES) forKey:itemID];
  88. OCMExpect([self.mockSecureStorage getObjectForKey:itemID
  89. objectClass:[FIRInstallationsStoredItem class]
  90. accessGroup:self.accessGroup])
  91. .andReturn([FBLPromise resolvedWith:nil]);
  92. FBLPromise<FIRInstallationsItem *> *itemPromise = [self.store installationForAppID:appID
  93. appName:appName];
  94. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  95. XCTAssertNotNil(itemPromise.error);
  96. XCTAssertEqualObjects(itemPromise.error,
  97. [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID
  98. appName:appName]);
  99. XCTAssertNil(itemPromise.value);
  100. OCMVerifyAll(self.mockSecureStorage);
  101. }
  102. - (void)testSaveInstallationWhenKeychainSucceds {
  103. FIRInstallationsItem *item = [FIRInstallationsItem createUnregisteredInstallationItem];
  104. NSString *itemID = [item identifier];
  105. // Reset user defaults key.
  106. [self.userDefaults removeObjectForKey:itemID];
  107. id storedItemArg = [OCMArg checkWithBlock:^BOOL(FIRInstallationsStoredItem *obj) {
  108. XCTAssertEqualObjects([obj class], [FIRInstallationsStoredItem class]);
  109. [self assertStoredItem:obj correspondsToItem:item];
  110. return YES;
  111. }];
  112. OCMExpect([self.mockSecureStorage setObject:storedItemArg
  113. forKey:itemID
  114. accessGroup:self.accessGroup])
  115. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  116. FBLPromise<NSNull *> *promise = [self.store saveInstallation:item];
  117. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  118. XCTAssertNil(promise.error);
  119. XCTAssertTrue(promise.isFulfilled);
  120. OCMVerifyAll(self.mockSecureStorage);
  121. // Check the user defaults key updated.
  122. XCTAssertNotNil([self.userDefaults objectForKey:itemID]);
  123. }
  124. - (void)testSaveInstallationWhenKeychainFails {
  125. FIRInstallationsItem *item = [FIRInstallationsItem createUnregisteredInstallationItem];
  126. NSString *itemID = [item identifier];
  127. // Reset user defaults key.
  128. [self.userDefaults removeObjectForKey:itemID];
  129. NSError *keychainError = [FIRInstallationsErrorUtil keychainErrorWithFunction:@"Get" status:-1];
  130. FBLPromise *rejectedPromise = [FBLPromise pendingPromise];
  131. [rejectedPromise reject:keychainError];
  132. id storedItemArg = [OCMArg checkWithBlock:^BOOL(FIRInstallationsStoredItem *obj) {
  133. XCTAssertEqualObjects([obj class], [FIRInstallationsStoredItem class]);
  134. [self assertStoredItem:obj correspondsToItem:item];
  135. return YES;
  136. }];
  137. OCMExpect([self.mockSecureStorage setObject:storedItemArg
  138. forKey:itemID
  139. accessGroup:self.accessGroup])
  140. .andReturn(rejectedPromise);
  141. FBLPromise<NSNull *> *promise = [self.store saveInstallation:item];
  142. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  143. XCTAssertTrue(promise.isRejected);
  144. XCTAssertEqualObjects(promise.error, keychainError);
  145. OCMVerifyAll(self.mockSecureStorage);
  146. // Check the user defaults key wasn't updated.
  147. XCTAssertNil([self.userDefaults objectForKey:itemID]);
  148. }
  149. - (void)testRemoveInstallation {
  150. NSString *appID = @"123";
  151. NSString *appName = @"name";
  152. NSString *itemID = [self itemIDWithAppID:appID appName:appName];
  153. [self.userDefaults setObject:@(YES) forKey:itemID];
  154. OCMExpect([self.mockSecureStorage removeObjectForKey:itemID accessGroup:self.accessGroup])
  155. .andReturn([FBLPromise resolvedWith:[NSNull null]]);
  156. FBLPromise<NSNull *> *promise = [self.store removeInstallationForAppID:appID appName:appName];
  157. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  158. XCTAssertTrue(promise.isFulfilled);
  159. XCTAssertNil(promise.error);
  160. OCMVerifyAll(self.mockSecureStorage);
  161. XCTAssertNil([self.userDefaults objectForKey:itemID]);
  162. }
  163. #pragma mark - Common
  164. - (void)assertInstallationIDNotFoundForAppID:(NSString *)appID appName:(NSString *)appName {
  165. FBLPromise<FIRInstallationsItem *> *itemPromise = [self.store installationForAppID:appID
  166. appName:appName];
  167. XCTAssert(FBLWaitForPromisesWithTimeout(0.5));
  168. XCTAssertTrue(itemPromise.isRejected, @"%@", self.name);
  169. XCTAssertEqualObjects(itemPromise.error,
  170. [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID
  171. appName:appName],
  172. @"%@", self.name);
  173. }
  174. #pragma mark - Helpers
  175. - (NSString *)itemIDWithAppID:(NSString *)appID appName:(NSString *)appName {
  176. return [FIRInstallationsItem identifierWithAppID:appID appName:appName];
  177. }
  178. - (FIRInstallationsStoredItem *)createValidStoredItem {
  179. FIRInstallationsStoredItem *storedItem = [[FIRInstallationsStoredItem alloc] init];
  180. storedItem.firebaseInstallationID = @"firebaseInstallationID";
  181. storedItem.refreshToken = @"refreshToken";
  182. return storedItem;
  183. }
  184. - (void)assertStoredItem:(FIRInstallationsStoredItem *)storedItem
  185. correspondsToItem:(FIRInstallationsItem *)item {
  186. XCTAssertEqualObjects(item.refreshToken, storedItem.refreshToken);
  187. XCTAssertEqualObjects(item.firebaseInstallationID, storedItem.firebaseInstallationID);
  188. XCTAssertEqual(item.registrationStatus, storedItem.registrationStatus);
  189. }
  190. @end