FIRInstanceIDStoreTest.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 "FIRInstanceIDFakeKeychain.h"
  19. #import "Firebase/InstanceID/FIRInstanceIDBackupExcludedPlist.h"
  20. #import "Firebase/InstanceID/FIRInstanceIDCheckinPreferences+Internal.h"
  21. #import "Firebase/InstanceID/FIRInstanceIDCheckinPreferences.h"
  22. #import "Firebase/InstanceID/FIRInstanceIDCheckinService.h"
  23. #import "Firebase/InstanceID/FIRInstanceIDCheckinStore.h"
  24. #import "Firebase/InstanceID/FIRInstanceIDStore.h"
  25. #import "Firebase/InstanceID/FIRInstanceIDTokenInfo.h"
  26. #import "Firebase/InstanceID/FIRInstanceIDTokenStore.h"
  27. #import "Firebase/InstanceID/FIRInstanceIDUtilities.h"
  28. static NSString *const kSubDirectoryName = @"FirebaseInstanceIDStoreTest";
  29. static NSString *const kAuthorizedEntity = @"test-audience";
  30. static NSString *const kScope = @"test-scope";
  31. static NSString *const kToken = @"test-token";
  32. static NSString *const kKey = @"test-key";
  33. static NSString *const kTimeSuffix = @"-time";
  34. static NSString *const kAuthID = @"test-auth-id";
  35. static NSString *const kSecret = @"test-secret";
  36. // This should stay in sync with the same constant name in FIRInstanceIDStore.
  37. // We don't want to make a new method in FIRInstanceIDStore to avoid adding
  38. // binary bloat.
  39. static NSString *const kFIRInstanceIDAPNSTokenKey = @"APNSTuple";
  40. @interface FIRInstanceIDStore ()
  41. - (NSString *)tokenWithKey:(NSString *)key;
  42. - (void)cacheToken:(NSString *)token withKey:(NSString *)key;
  43. // APNS
  44. + (NSString *)legacyAPNSTokenCacheKeyForServerType:(BOOL)isSandbox;
  45. + (NSData *)dataWithHexString:(NSString *)hex;
  46. - (void)resetCredentialsIfNeeded;
  47. - (BOOL)hasSavedLibraryVersion;
  48. - (BOOL)hasCheckinPlist;
  49. @end
  50. @interface FIRInstanceIDStoreTest : XCTestCase
  51. @property(nonatomic) FIRInstanceIDStore *instanceIDStore;
  52. @property(nonatomic) FIRInstanceIDBackupExcludedPlist *checkinPlist;
  53. @property(nonatomic) FIRInstanceIDCheckinStore *checkinStore;
  54. @property(nonatomic) FIRInstanceIDTokenStore *tokenStore;
  55. @property(nonatomic) id mockCheckinStore;
  56. @property(nonatomic) id mockTokenStore;
  57. @property(nonatomic) id mockInstanceIDStore;
  58. @end
  59. @implementation FIRInstanceIDStoreTest
  60. - (void)setUp {
  61. [super setUp];
  62. [FIRInstanceIDStore createSubDirectory:kSubDirectoryName];
  63. NSString *checkinPlistName = @"com.google.test.IIDStoreTestCheckin";
  64. self.checkinPlist = [[FIRInstanceIDBackupExcludedPlist alloc] initWithFileName:checkinPlistName
  65. subDirectory:kSubDirectoryName];
  66. // checkin store
  67. FIRInstanceIDFakeKeychain *fakeKeychain = [[FIRInstanceIDFakeKeychain alloc] init];
  68. _checkinStore = [[FIRInstanceIDCheckinStore alloc] initWithCheckinPlist:self.checkinPlist
  69. keychain:fakeKeychain];
  70. _mockCheckinStore = OCMPartialMock(_checkinStore);
  71. // token store
  72. FIRInstanceIDFakeKeychain *fakeTokenKeychain = [[FIRInstanceIDFakeKeychain alloc] init];
  73. _tokenStore = [[FIRInstanceIDTokenStore alloc] initWithKeychain:fakeTokenKeychain];
  74. _mockTokenStore = OCMPartialMock(_tokenStore);
  75. #pragma clang diagnostic push
  76. #pragma clang diagnostic ignored "-Wnonnull"
  77. _instanceIDStore = [[FIRInstanceIDStore alloc] initWithCheckinStore:_mockCheckinStore
  78. tokenStore:_mockTokenStore
  79. delegate:nil];
  80. #pragma clang diagnostic pop
  81. _mockInstanceIDStore = OCMPartialMock(_instanceIDStore);
  82. }
  83. - (void)tearDown {
  84. [self.instanceIDStore removeAllCachedTokensWithHandler:nil];
  85. [self.instanceIDStore removeCheckinPreferencesWithHandler:nil];
  86. [FIRInstanceIDStore removeSubDirectory:kSubDirectoryName error:nil];
  87. [_mockCheckinStore stopMocking];
  88. [_mockTokenStore stopMocking];
  89. [_mockInstanceIDStore stopMocking];
  90. [super tearDown];
  91. }
  92. /**
  93. * Tests that an InstanceID token can be stored in the FIRInstanceIDStore for
  94. * an authorizedEntity and scope.
  95. */
  96. - (void)testSaveToken {
  97. XCTestExpectation *tokenExpectation = [self expectationWithDescription:@"token is saved"];
  98. FIRInstanceIDTokenInfo *tokenInfo =
  99. [[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
  100. scope:kScope
  101. token:kToken
  102. appVersion:@"1.0"
  103. firebaseAppID:@"firebaseAppID"];
  104. [self.instanceIDStore saveTokenInfo:tokenInfo
  105. handler:^(NSError *error) {
  106. XCTAssertNil(error);
  107. FIRInstanceIDTokenInfo *retrievedTokenInfo = [self.instanceIDStore
  108. tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  109. scope:kScope];
  110. XCTAssertEqualObjects(retrievedTokenInfo.token, kToken);
  111. [tokenExpectation fulfill];
  112. }];
  113. [self waitForExpectationsWithTimeout:1 handler:nil];
  114. }
  115. /**
  116. * Tests that a token can be removed from from FIRInstanceIDStore's cache when specifying
  117. * its authorizedEntity and scope.
  118. */
  119. - (void)testRemoveCachedToken {
  120. XCTestExpectation *tokenExpectation = [self expectationWithDescription:@"token is removed"];
  121. FIRInstanceIDTokenInfo *tokenInfo =
  122. [[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
  123. scope:kScope
  124. token:kToken
  125. appVersion:@"1.0"
  126. firebaseAppID:@"firebaseAppID"];
  127. [self.instanceIDStore
  128. saveTokenInfo:tokenInfo
  129. handler:^(NSError *error) {
  130. XCTAssertNotNil([self.instanceIDStore tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  131. scope:kScope]);
  132. [self.instanceIDStore removeCachedTokenWithAuthorizedEntity:kAuthorizedEntity
  133. scope:kScope];
  134. XCTAssertNil([self.instanceIDStore tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  135. scope:kScope]);
  136. [tokenExpectation fulfill];
  137. }];
  138. [self waitForExpectationsWithTimeout:1 handler:nil];
  139. }
  140. /**
  141. * Tests that a checkin authentication ID can be stored in the FIRInstanceIDStore.
  142. */
  143. - (void)testSaveCheckinAuthID {
  144. XCTestExpectation *checkinExpectation = [self expectationWithDescription:@"checkin is saved"];
  145. NSDictionary *plistContent = @{
  146. kFIRInstanceIDDigestStringKey : @"digest-xyz",
  147. kFIRInstanceIDLastCheckinTimeKey : @(FIRInstanceIDCurrentTimestampInMilliseconds())
  148. };
  149. FIRInstanceIDCheckinPreferences *preferences =
  150. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  151. [preferences updateWithCheckinPlistContents:plistContent];
  152. [self.instanceIDStore
  153. saveCheckinPreferences:preferences
  154. handler:^(NSError *_Nonnull error) {
  155. XCTAssertNil(error);
  156. FIRInstanceIDCheckinPreferences *cachedPreferences =
  157. [self.instanceIDStore cachedCheckinPreferences];
  158. XCTAssertEqualObjects(cachedPreferences.deviceID, kAuthID);
  159. XCTAssertEqualObjects(cachedPreferences.secretToken, kSecret);
  160. [checkinExpectation fulfill];
  161. }];
  162. [self waitForExpectationsWithTimeout:1 handler:nil];
  163. }
  164. /**
  165. * Tests that a checkin authentication ID can be removed from FIRInstanceIDStore's cache.
  166. */
  167. - (void)testRemoveCheckinPreferences {
  168. XCTestExpectation *checkinExpectation = [self expectationWithDescription:@"checkin is removed"];
  169. NSDictionary *plistContent = @{
  170. kFIRInstanceIDDigestStringKey : @"digest-xyz",
  171. kFIRInstanceIDLastCheckinTimeKey : @(FIRInstanceIDCurrentTimestampInMilliseconds())
  172. };
  173. FIRInstanceIDCheckinPreferences *preferences =
  174. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  175. [preferences updateWithCheckinPlistContents:plistContent];
  176. [self.instanceIDStore
  177. saveCheckinPreferences:preferences
  178. handler:^(NSError *error) {
  179. XCTAssertNil(error);
  180. [self.instanceIDStore
  181. removeCheckinPreferencesWithHandler:^(NSError *_Nullable error) {
  182. XCTAssertNil(error);
  183. FIRInstanceIDCheckinPreferences *cachedPreferences =
  184. [self.instanceIDStore cachedCheckinPreferences];
  185. XCTAssertNil(cachedPreferences.deviceID);
  186. XCTAssertNil(cachedPreferences.secretToken);
  187. [checkinExpectation fulfill];
  188. }];
  189. }];
  190. [self waitForExpectationsWithTimeout:1 handler:nil];
  191. }
  192. - (void)testResetCredentialsWithFreshInstall {
  193. FIRInstanceIDCheckinPreferences *checkinPreferences =
  194. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  195. // Expect checkin is removed if it's a fresh install.
  196. [[_mockCheckinStore expect]
  197. removeCheckinPreferencesWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], nil]];
  198. // Always setting up stub after expect.
  199. OCMStub([_mockCheckinStore cachedCheckinPreferences]).andReturn(checkinPreferences);
  200. // Plist file doesn't exist, meaning this is a fresh install.
  201. OCMStub([_mockCheckinStore hasCheckinPlist]).andReturn(NO);
  202. [_mockInstanceIDStore resetCredentialsIfNeeded];
  203. OCMVerifyAll(_mockCheckinStore);
  204. }
  205. - (void)testResetCredentialsWithoutFreshInstall {
  206. FIRInstanceIDCheckinPreferences *checkinPreferences =
  207. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  208. // Expect migration happens if it's not a fresh install.
  209. [[_mockCheckinStore expect] migrateCheckinItemIfNeeded];
  210. // Always setting up stub after expect.
  211. OCMStub([_mockCheckinStore cachedCheckinPreferences]).andReturn(checkinPreferences);
  212. // Mock plist exists, meaning this is not a fresh install.
  213. OCMStub([_mockCheckinStore hasCheckinPlist]).andReturn(YES);
  214. [_mockInstanceIDStore resetCredentialsIfNeeded];
  215. OCMVerifyAll(_mockCheckinStore);
  216. }
  217. - (void)testResetCredentialsWithNoCachedCheckin {
  218. _mockCheckinStore = [OCMockObject niceMockForClass:[FIRInstanceIDCheckinStore class]];
  219. [[_mockCheckinStore reject]
  220. removeCheckinPreferencesWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], nil]];
  221. // Always setting up stub after expect.
  222. OCMStub([_checkinStore cachedCheckinPreferences]).andReturn(nil);
  223. [_instanceIDStore resetCredentialsIfNeeded];
  224. OCMVerifyAll(_mockCheckinStore);
  225. }
  226. @end