FIRInstanceIDStoreTest.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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 kApplicationSupportSubDirectoryName = @"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 createApplicationSupportSubDirectory:kApplicationSupportSubDirectoryName];
  63. NSString *checkinPlistName = @"com.google.test.IIDStoreTestCheckin";
  64. self.checkinPlist = [[FIRInstanceIDBackupExcludedPlist alloc]
  65. initWithFileName:checkinPlistName
  66. applicationSupportSubDirectory:kApplicationSupportSubDirectoryName];
  67. // checkin store
  68. FIRInstanceIDFakeKeychain *fakeKeychain = [[FIRInstanceIDFakeKeychain alloc] init];
  69. _checkinStore = [[FIRInstanceIDCheckinStore alloc] initWithCheckinPlist:self.checkinPlist
  70. keychain:fakeKeychain];
  71. _mockCheckinStore = OCMPartialMock(_checkinStore);
  72. // token store
  73. FIRInstanceIDFakeKeychain *fakeTokenKeychain = [[FIRInstanceIDFakeKeychain alloc] init];
  74. _tokenStore = [[FIRInstanceIDTokenStore alloc] initWithKeychain:fakeTokenKeychain];
  75. _mockTokenStore = OCMPartialMock(_tokenStore);
  76. #pragma clang diagnostic push
  77. #pragma clang diagnostic ignored "-Wnonnull"
  78. _instanceIDStore = [[FIRInstanceIDStore alloc] initWithCheckinStore:_mockCheckinStore
  79. tokenStore:_mockTokenStore
  80. delegate:nil];
  81. #pragma clang diagnostic pop
  82. _mockInstanceIDStore = OCMPartialMock(_instanceIDStore);
  83. }
  84. - (void)tearDown {
  85. [self.instanceIDStore removeAllCachedTokensWithHandler:nil];
  86. [self.instanceIDStore removeCheckinPreferencesWithHandler:nil];
  87. [FIRInstanceIDStore removeApplicationSupportSubDirectory:kApplicationSupportSubDirectoryName
  88. error:nil];
  89. [_mockCheckinStore stopMocking];
  90. [_mockTokenStore stopMocking];
  91. [_mockInstanceIDStore stopMocking];
  92. [super tearDown];
  93. }
  94. /**
  95. * Tests that an InstanceID token can be stored in the FIRInstanceIDStore for
  96. * an authorizedEntity and scope.
  97. */
  98. - (void)testSaveToken {
  99. XCTestExpectation *tokenExpectation = [self expectationWithDescription:@"token is saved"];
  100. FIRInstanceIDTokenInfo *tokenInfo =
  101. [[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
  102. scope:kScope
  103. token:kToken
  104. appVersion:@"1.0"
  105. firebaseAppID:@"firebaseAppID"];
  106. [self.instanceIDStore saveTokenInfo:tokenInfo
  107. handler:^(NSError *error) {
  108. XCTAssertNil(error);
  109. FIRInstanceIDTokenInfo *retrievedTokenInfo = [self.instanceIDStore
  110. tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  111. scope:kScope];
  112. XCTAssertEqualObjects(retrievedTokenInfo.token, kToken);
  113. [tokenExpectation fulfill];
  114. }];
  115. [self waitForExpectationsWithTimeout:1 handler:nil];
  116. }
  117. /**
  118. * Tests that a token can be removed from from FIRInstanceIDStore's cache when specifying
  119. * its authorizedEntity and scope.
  120. */
  121. - (void)testRemoveCachedToken {
  122. XCTestExpectation *tokenExpectation = [self expectationWithDescription:@"token is removed"];
  123. FIRInstanceIDTokenInfo *tokenInfo =
  124. [[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
  125. scope:kScope
  126. token:kToken
  127. appVersion:@"1.0"
  128. firebaseAppID:@"firebaseAppID"];
  129. [self.instanceIDStore
  130. saveTokenInfo:tokenInfo
  131. handler:^(NSError *error) {
  132. XCTAssertNotNil([self.instanceIDStore tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  133. scope:kScope]);
  134. [self.instanceIDStore removeCachedTokenWithAuthorizedEntity:kAuthorizedEntity
  135. scope:kScope];
  136. XCTAssertNil([self.instanceIDStore tokenInfoWithAuthorizedEntity:kAuthorizedEntity
  137. scope:kScope]);
  138. [tokenExpectation fulfill];
  139. }];
  140. [self waitForExpectationsWithTimeout:1 handler:nil];
  141. }
  142. /**
  143. * Tests that a checkin authentication ID can be stored in the FIRInstanceIDStore.
  144. */
  145. - (void)testSaveCheckinAuthID {
  146. XCTestExpectation *checkinExpectation = [self expectationWithDescription:@"checkin is saved"];
  147. NSDictionary *plistContent = @{
  148. kFIRInstanceIDDigestStringKey : @"digest-xyz",
  149. kFIRInstanceIDLastCheckinTimeKey : @(FIRInstanceIDCurrentTimestampInMilliseconds())
  150. };
  151. FIRInstanceIDCheckinPreferences *preferences =
  152. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  153. [preferences updateWithCheckinPlistContents:plistContent];
  154. [self.instanceIDStore
  155. saveCheckinPreferences:preferences
  156. handler:^(NSError *_Nonnull error) {
  157. XCTAssertNil(error);
  158. FIRInstanceIDCheckinPreferences *cachedPreferences =
  159. [self.instanceIDStore cachedCheckinPreferences];
  160. XCTAssertEqualObjects(cachedPreferences.deviceID, kAuthID);
  161. XCTAssertEqualObjects(cachedPreferences.secretToken, kSecret);
  162. [checkinExpectation fulfill];
  163. }];
  164. [self waitForExpectationsWithTimeout:1 handler:nil];
  165. }
  166. /**
  167. * Tests that a checkin authentication ID can be removed from FIRInstanceIDStore's cache.
  168. */
  169. - (void)testRemoveCheckinPreferences {
  170. XCTestExpectation *checkinExpectation = [self expectationWithDescription:@"checkin is removed"];
  171. NSDictionary *plistContent = @{
  172. kFIRInstanceIDDigestStringKey : @"digest-xyz",
  173. kFIRInstanceIDLastCheckinTimeKey : @(FIRInstanceIDCurrentTimestampInMilliseconds())
  174. };
  175. FIRInstanceIDCheckinPreferences *preferences =
  176. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  177. [preferences updateWithCheckinPlistContents:plistContent];
  178. [self.instanceIDStore
  179. saveCheckinPreferences:preferences
  180. handler:^(NSError *error) {
  181. XCTAssertNil(error);
  182. [self.instanceIDStore
  183. removeCheckinPreferencesWithHandler:^(NSError *_Nullable error) {
  184. XCTAssertNil(error);
  185. FIRInstanceIDCheckinPreferences *cachedPreferences =
  186. [self.instanceIDStore cachedCheckinPreferences];
  187. XCTAssertNil(cachedPreferences.deviceID);
  188. XCTAssertNil(cachedPreferences.secretToken);
  189. [checkinExpectation fulfill];
  190. }];
  191. }];
  192. [self waitForExpectationsWithTimeout:1 handler:nil];
  193. }
  194. - (void)testResetCredentialsWithFreshInstall {
  195. FIRInstanceIDCheckinPreferences *checkinPreferences =
  196. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  197. // Expect checkin is removed if it's a fresh install.
  198. [[_mockCheckinStore expect]
  199. removeCheckinPreferencesWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], nil]];
  200. // Always setting up stub after expect.
  201. OCMStub([_mockCheckinStore cachedCheckinPreferences]).andReturn(checkinPreferences);
  202. // Plist file doesn't exist, meaning this is a fresh install.
  203. OCMStub([_mockCheckinStore hasCheckinPlist]).andReturn(NO);
  204. [_mockInstanceIDStore resetCredentialsIfNeeded];
  205. OCMVerifyAll(_mockCheckinStore);
  206. }
  207. - (void)testResetCredentialsWithoutFreshInstall {
  208. FIRInstanceIDCheckinPreferences *checkinPreferences =
  209. [[FIRInstanceIDCheckinPreferences alloc] initWithDeviceID:kAuthID secretToken:kSecret];
  210. // Expect migration happens if it's not a fresh install.
  211. [[_mockCheckinStore expect] migrateCheckinItemIfNeeded];
  212. // Always setting up stub after expect.
  213. OCMStub([_mockCheckinStore cachedCheckinPreferences]).andReturn(checkinPreferences);
  214. // Mock plist exists, meaning this is not a fresh install.
  215. OCMStub([_mockCheckinStore hasCheckinPlist]).andReturn(YES);
  216. [_mockInstanceIDStore resetCredentialsIfNeeded];
  217. OCMVerifyAll(_mockCheckinStore);
  218. }
  219. - (void)testResetCredentialsWithNoCachedCheckin {
  220. _mockCheckinStore = [OCMockObject niceMockForClass:[FIRInstanceIDCheckinStore class]];
  221. [[_mockCheckinStore reject]
  222. removeCheckinPreferencesWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], nil]];
  223. // Always setting up stub after expect.
  224. OCMStub([_checkinStore cachedCheckinPreferences]).andReturn(nil);
  225. [_instanceIDStore resetCredentialsIfNeeded];
  226. OCMVerifyAll(_mockCheckinStore);
  227. }
  228. @end