FIRCLSSettingsTests.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright 2019 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
  15. #import <Foundation/Foundation.h>
  16. #import <XCTest/XCTest.h>
  17. #if __has_include(<FBLPromises/FBLPromises.h>)
  18. #import <FBLPromises/FBLPromises.h>
  19. #else
  20. #import "FBLPromises.h"
  21. #endif
  22. #import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
  23. #import "Crashlytics/UnitTests/Mocks/FABMockApplicationIdentifierModel.h"
  24. #import "Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.h"
  25. const NSString *FIRCLSTestSettingsActivated =
  26. @"{\"settings_version\":3,\"cache_duration\":60,\"features\":{\"collect_logged_exceptions\":"
  27. @"true,\"collect_reports\":true, \"collect_metric_kit\":true},"
  28. @"\"fabric\":{\"org_id\":\"010101000000111111111111\",\"bundle_id\":\"com.lets.test."
  29. @"crashlytics\"}}";
  30. const NSString *FIRCLSTestSettingsInverse =
  31. @"{\"settings_version\":3,\"cache_duration\":12345,\"features\":{\"collect_logged_exceptions\":"
  32. @"false,\"collect_reports\":false, \"collect_metric_kit\":false},"
  33. @"\"fabric\":{\"org_id\":\"01e101a0000011b113115111\",\"bundle_id\":\"im.from.the.server\"},"
  34. @"\"session\":{\"log_buffer_size\":128000,\"max_chained_exception_depth\":32,\"max_complete_"
  35. @"sessions_count\":4,\"max_custom_exception_events\":1000,\"max_custom_key_value_pairs\":2000,"
  36. @"\"identifier_mask\":255}, \"on_demand_upload_rate_per_minute\":15.0, "
  37. @"\"on_demand_backoff_base\":3.0, \"on_demand_backoff_step_duration_seconds\":9}";
  38. const NSString *FIRCLSTestSettingsCorrupted = @"{{{{ non_key: non\"value {}";
  39. NSString *FIRCLSDefaultMockBuildInstanceID = @"12345abcdef";
  40. NSString *FIRCLSDifferentMockBuildInstanceID = @"98765zyxwv";
  41. NSString *FIRCLSDefaultMockAppDisplayVersion = @"1.2.3-beta.2";
  42. NSString *FIRCLSDifferentMockAppDisplayVersion = @"1.2.3-beta.3";
  43. NSString *FIRCLSDefaultMockAppBuildVersion = @"1024";
  44. NSString *FIRCLSDifferentMockAppBuildVersion = @"2048";
  45. NSString *const TestGoogleAppID = @"1:test:google:app:id";
  46. NSString *const TestChangedGoogleAppID = @"2:changed:google:app:id";
  47. @interface FIRCLSSettings (Testing)
  48. @property(nonatomic, strong) NSDictionary<NSString *, id> *settingsDictionary;
  49. @end
  50. @interface FIRCLSSettingsTests : XCTestCase
  51. @property(nonatomic, retain) FIRCLSMockFileManager *fileManager;
  52. @property(nonatomic, retain) FABMockApplicationIdentifierModel *appIDModel;
  53. @property(nonatomic, retain) FIRCLSSettings *settings;
  54. @end
  55. @implementation FIRCLSSettingsTests
  56. - (void)setUp {
  57. [super setUp];
  58. _fileManager = [[FIRCLSMockFileManager alloc] init];
  59. _appIDModel = [[FABMockApplicationIdentifierModel alloc] init];
  60. _appIDModel.buildInstanceID = FIRCLSDefaultMockBuildInstanceID;
  61. _appIDModel.displayVersion = FIRCLSDefaultMockAppDisplayVersion;
  62. _appIDModel.buildVersion = FIRCLSDefaultMockAppBuildVersion;
  63. _settings = [[FIRCLSSettings alloc] initWithFileManager:_fileManager appIDModel:_appIDModel];
  64. }
  65. - (void)testDefaultSettings {
  66. XCTAssertEqual(self.settings.isCacheExpired, YES);
  67. // Default to an hour
  68. XCTAssertEqual(self.settings.cacheDurationSeconds, 60 * 60);
  69. XCTAssertTrue(self.settings.collectReportsEnabled);
  70. XCTAssertTrue(self.settings.errorReportingEnabled);
  71. XCTAssertTrue(self.settings.customExceptionsEnabled);
  72. XCTAssertFalse(self.settings.metricKitCollectionEnabled);
  73. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  74. XCTAssertEqual(self.settings.logBufferSize, 64 * 1000);
  75. XCTAssertEqual(self.settings.maxCustomExceptions, 8);
  76. XCTAssertEqual(self.settings.maxCustomKeys, 64);
  77. XCTAssertEqual(self.settings.onDemandUploadRate, 10);
  78. XCTAssertEqual(self.settings.onDemandBackoffBase, 1.5);
  79. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 6);
  80. }
  81. - (BOOL)writeSettings:(const NSString *)settings error:(NSError **)error {
  82. return [self writeSettings:settings error:error isCacheKey:NO];
  83. }
  84. - (BOOL)writeSettings:(const NSString *)settings
  85. error:(NSError **)error
  86. isCacheKey:(BOOL)isCacheKey {
  87. NSString *path = _fileManager.settingsFilePath;
  88. if (isCacheKey) {
  89. path = _fileManager.settingsCacheKeyPath;
  90. }
  91. return [self.fileManager createFileAtPath:path
  92. contents:[settings dataUsingEncoding:NSUTF8StringEncoding]
  93. attributes:nil];
  94. }
  95. - (void)cacheSettingsWithGoogleAppID:(NSString *)googleAppID
  96. currentTimestamp:(NSTimeInterval)currentTimestamp
  97. expectedRemoveCount:(NSInteger)expectedRemoveCount {
  98. self.fileManager.removeExpectation = [[XCTestExpectation alloc]
  99. initWithDescription:@"FIRCLSMockFileManager.removeExpectation.cache"];
  100. self.fileManager.removeCount = 0;
  101. self.fileManager.expectedRemoveCount = expectedRemoveCount;
  102. [self.settings cacheSettingsWithGoogleAppID:googleAppID currentTimestamp:currentTimestamp];
  103. [self waitForExpectations:@[ self.fileManager.removeExpectation ] timeout:1];
  104. }
  105. - (void)reloadFromCacheWithGoogleAppID:(NSString *)googleAppID
  106. currentTimestamp:(NSTimeInterval)currentTimestamp
  107. expectedRemoveCount:(NSInteger)expectedRemoveCount {
  108. self.fileManager.removeExpectation = [[XCTestExpectation alloc]
  109. initWithDescription:@"FIRCLSMockFileManager.removeExpectation.reload"];
  110. self.fileManager.removeCount = 0;
  111. self.fileManager.expectedRemoveCount = expectedRemoveCount;
  112. [self.settings reloadFromCacheWithGoogleAppID:googleAppID currentTimestamp:currentTimestamp];
  113. [self waitForExpectations:@[ self.fileManager.removeExpectation ] timeout:1];
  114. }
  115. - (void)testActivatedSettingsCached {
  116. NSError *error = nil;
  117. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  118. XCTAssertNil(error, "%@", error);
  119. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  120. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  121. XCTAssertEqual(self.settings.isCacheExpired, NO);
  122. XCTAssertEqual(self.settings.cacheDurationSeconds, 60);
  123. XCTAssertTrue(self.settings.collectReportsEnabled);
  124. XCTAssertTrue(self.settings.errorReportingEnabled);
  125. XCTAssertTrue(self.settings.customExceptionsEnabled);
  126. XCTAssertTrue(self.settings.metricKitCollectionEnabled);
  127. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  128. XCTAssertEqual(self.settings.logBufferSize, 64 * 1000);
  129. XCTAssertEqual(self.settings.maxCustomExceptions, 8);
  130. XCTAssertEqual(self.settings.maxCustomKeys, 64);
  131. XCTAssertEqual(self.settings.onDemandUploadRate, 10);
  132. XCTAssertEqual(self.settings.onDemandBackoffBase, 1.5);
  133. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 6);
  134. }
  135. - (void)testInverseDefaultSettingsCached {
  136. NSError *error = nil;
  137. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  138. XCTAssertNil(error, "%@", error);
  139. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  140. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  141. XCTAssertEqual(self.settings.isCacheExpired, NO);
  142. XCTAssertEqual(self.settings.cacheDurationSeconds, 12345);
  143. XCTAssertFalse(self.settings.collectReportsEnabled);
  144. XCTAssertFalse(self.settings.errorReportingEnabled);
  145. XCTAssertFalse(self.settings.customExceptionsEnabled);
  146. XCTAssertFalse(self.settings.metricKitCollectionEnabled);
  147. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  148. XCTAssertEqual(self.settings.logBufferSize, 128000);
  149. XCTAssertEqual(self.settings.maxCustomExceptions, 1000);
  150. XCTAssertEqual(self.settings.maxCustomKeys, 2000);
  151. XCTAssertEqual(self.settings.onDemandUploadRate, 15);
  152. XCTAssertEqual(self.settings.onDemandBackoffBase, 3);
  153. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 9);
  154. }
  155. - (void)testCacheExpiredFromTTL {
  156. NSError *error = nil;
  157. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  158. XCTAssertNil(error, "%@", error);
  159. // 1 delete for clearing the cache key, plus 2 for the deletes from reloading and clearing the
  160. // cache and cache key
  161. self.fileManager.expectedRemoveCount = 3;
  162. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  163. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  164. // Go forward in time by 2x the cache duration
  165. NSTimeInterval futureTimestamp = currentTimestamp + (2 * self.settings.cacheDurationSeconds);
  166. [self.settings reloadFromCacheWithGoogleAppID:TestGoogleAppID currentTimestamp:futureTimestamp];
  167. XCTAssertEqual(self.settings.isCacheExpired, YES);
  168. // Since the TTL just expired, do not clear settings
  169. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  170. // Pretend we fetched settings again, but they had different values
  171. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  172. XCTAssertNil(error, "%@", error);
  173. // Cache the settings
  174. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  175. // We should have the updated values that were fetched, and should not be expired
  176. XCTAssertEqual(self.settings.isCacheExpired, NO);
  177. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  178. }
  179. - (void)testCacheExpiredFromBuildInstanceID {
  180. NSError *error = nil;
  181. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  182. XCTAssertNil(error, "%@", error);
  183. // 1 delete for clearing the cache key, plus 2 for the deletes from reloading and clearing the
  184. // cache and cache key
  185. self.fileManager.expectedRemoveCount = 3;
  186. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  187. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  188. // Change the Build Instance ID
  189. self.appIDModel.buildInstanceID = FIRCLSDifferentMockBuildInstanceID;
  190. [self.settings reloadFromCacheWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  191. XCTAssertEqual(self.settings.isCacheExpired, YES);
  192. // Since the TTL just expired, do not clear settings
  193. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  194. // Pretend we fetched settings again, but they had different values
  195. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  196. XCTAssertNil(error, "%@", error);
  197. // Cache the settings
  198. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  199. // We should have the updated values that were fetched, and should not be expired
  200. XCTAssertEqual(self.settings.isCacheExpired, NO);
  201. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  202. }
  203. - (void)testCacheExpiredFromAppVersion {
  204. NSError *error = nil;
  205. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  206. XCTAssertNil(error, "%@", error);
  207. // 1 delete for clearing the cache key, plus 2 for the deletes from reloading and clearing the
  208. // cache and cache key
  209. self.fileManager.expectedRemoveCount = 3;
  210. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  211. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  212. // Change the App Version
  213. self.appIDModel.displayVersion = FIRCLSDifferentMockAppDisplayVersion;
  214. self.appIDModel.buildVersion = FIRCLSDifferentMockAppBuildVersion;
  215. [self.settings reloadFromCacheWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  216. XCTAssertEqual(self.settings.isCacheExpired, YES);
  217. // Since the TTL just expired, do not clear settings
  218. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  219. // Pretend we fetched settings again, but they had different values
  220. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  221. XCTAssertNil(error, "%@", error);
  222. // Cache the settings
  223. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  224. // We should have the updated values that were fetched, and should not be expired
  225. XCTAssertEqual(self.settings.isCacheExpired, NO);
  226. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  227. }
  228. - (void)testGoogleAppIDChanged {
  229. NSError *error = nil;
  230. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  231. XCTAssertNil(error, "%@", error);
  232. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  233. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  234. // Different Google App ID
  235. [self reloadFromCacheWithGoogleAppID:TestChangedGoogleAppID
  236. currentTimestamp:currentTimestamp
  237. expectedRemoveCount:2];
  238. XCTAssertEqual(self.settings.isCacheExpired, YES);
  239. // Clear the settings because they were for a different Google App ID
  240. // Pretend we fetched settings again, but they had different values
  241. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  242. XCTAssertNil(error, "%@", error);
  243. // Cache the settings with the new Google App ID
  244. [self.settings cacheSettingsWithGoogleAppID:TestChangedGoogleAppID
  245. currentTimestamp:currentTimestamp];
  246. // Should have new values and not expired
  247. XCTAssertEqual(self.settings.isCacheExpired, NO);
  248. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  249. }
  250. // This is a weird case where we got settings, but never created a cache key for it. We are
  251. // treating this as if the cache was invalid and re-fetching in this case.
  252. - (void)testActivatedSettingsMissingCacheKey {
  253. NSError *error = nil;
  254. [self writeSettings:FIRCLSTestSettingsActivated error:&error];
  255. XCTAssertNil(error, "%@", error);
  256. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  257. // We only expect 1 removal because the cache key doesn't exist,
  258. // and deleteCachedSettings deletes the cache and the cache key
  259. [self reloadFromCacheWithGoogleAppID:TestGoogleAppID
  260. currentTimestamp:currentTimestamp
  261. expectedRemoveCount:1];
  262. XCTAssertEqual(self.settings.isCacheExpired, YES);
  263. XCTAssertEqual(self.settings.cacheDurationSeconds, 3600);
  264. XCTAssertTrue(self.settings.collectReportsEnabled);
  265. XCTAssertTrue(self.settings.errorReportingEnabled);
  266. XCTAssertTrue(self.settings.customExceptionsEnabled);
  267. XCTAssertFalse(self.settings.metricKitCollectionEnabled);
  268. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  269. XCTAssertEqual(self.settings.logBufferSize, 64 * 1000);
  270. XCTAssertEqual(self.settings.maxCustomExceptions, 8);
  271. XCTAssertEqual(self.settings.maxCustomKeys, 64);
  272. XCTAssertEqual(self.settings.onDemandUploadRate, 10);
  273. XCTAssertEqual(self.settings.onDemandBackoffBase, 1.5);
  274. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 6);
  275. }
  276. // These tests are partially to make sure the SDK doesn't crash when it
  277. // has corrupted settings.
  278. - (void)testCorruptCache {
  279. // First write and load a good settings file
  280. NSError *error = nil;
  281. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  282. XCTAssertNil(error, "%@", error);
  283. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  284. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  285. // Should have "Inverse" values
  286. XCTAssertEqual(self.settings.isCacheExpired, NO);
  287. XCTAssertEqual(self.settings.cacheDurationSeconds, 12345);
  288. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  289. // Then write a corrupted one and cache + reload it
  290. [self writeSettings:FIRCLSTestSettingsCorrupted error:&error];
  291. XCTAssertNil(error, "%@", error);
  292. // Cache them, and reload. Since it's corrupted we should delete it all
  293. [self cacheSettingsWithGoogleAppID:TestGoogleAppID
  294. currentTimestamp:currentTimestamp
  295. expectedRemoveCount:2];
  296. // Should have default values because we deleted the cache and settingsDictionary
  297. XCTAssertEqual(self.settings.isCacheExpired, YES);
  298. XCTAssertEqual(self.settings.cacheDurationSeconds, 3600);
  299. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  300. }
  301. - (void)testCorruptCacheKey {
  302. // First write and load a good settings file
  303. NSError *error = nil;
  304. [self writeSettings:FIRCLSTestSettingsInverse error:&error];
  305. XCTAssertNil(error, "%@", error);
  306. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  307. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  308. // Should have "Inverse" values
  309. XCTAssertEqual(self.settings.isCacheExpired, NO);
  310. XCTAssertEqual(self.settings.cacheDurationSeconds, 12345);
  311. XCTAssertEqual(self.settings.errorLogBufferSize, 128000);
  312. XCTAssertEqual(self.settings.onDemandUploadRate, 15);
  313. XCTAssertEqual(self.settings.onDemandBackoffBase, 3);
  314. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 9);
  315. // Then pretend we wrote a corrupted cache key and just reload it
  316. [self writeSettings:FIRCLSTestSettingsCorrupted error:&error isCacheKey:YES];
  317. XCTAssertNil(error, "%@", error);
  318. // Since settings themselves are corrupted, delete it all
  319. [self reloadFromCacheWithGoogleAppID:TestGoogleAppID
  320. currentTimestamp:currentTimestamp
  321. expectedRemoveCount:2];
  322. // Should have default values because we deleted the cache and settingsDictionary
  323. XCTAssertEqual(self.settings.isCacheExpired, YES);
  324. XCTAssertEqual(self.settings.cacheDurationSeconds, 3600);
  325. XCTAssertEqual(self.settings.errorLogBufferSize, 64 * 1000);
  326. XCTAssertEqual(self.settings.onDemandUploadRate, 10);
  327. XCTAssertEqual(self.settings.onDemandBackoffBase, 1.5);
  328. XCTAssertEqual(self.settings.onDemandBackoffStepDuration, 6);
  329. }
  330. - (void)testNewReportEndpointSettings {
  331. NSString *settingsJSON =
  332. @"{\"settings_version\":3,\"cache_duration\":60,\"app\":{\"report_upload_variant\":2}}";
  333. NSError *error = nil;
  334. [self writeSettings:settingsJSON error:&error];
  335. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  336. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  337. XCTAssertNil(error, "%@", error);
  338. XCTAssertNotNil(self.settings.settingsDictionary);
  339. NSLog(@"[Debug Log] %@", self.settings.settingsDictionary);
  340. }
  341. - (void)testLegacyReportEndpointSettings {
  342. NSString *settingsJSON =
  343. @"{\"settings_version\":3,\"cache_duration\":60,\"app\":{\"report_upload_variant\":1}}";
  344. NSError *error = nil;
  345. [self writeSettings:settingsJSON error:&error];
  346. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  347. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  348. XCTAssertNil(error, "%@", error);
  349. }
  350. - (void)testLegacyReportEndpointSettingsWithNonExistentKey {
  351. NSString *settingsJSON = @"{\"settings_version\":3,\"cache_duration\":60}";
  352. NSError *error = nil;
  353. [self writeSettings:settingsJSON error:&error];
  354. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  355. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  356. XCTAssertNil(error, "%@", error);
  357. }
  358. - (void)testLegacyReportEndpointSettingsWithUnknownValue {
  359. NSString *newEndpointJSON =
  360. @"{\"settings_version\":3,\"cache_duration\":60,\"app\":{\"report_upload_variant\":xyz}}";
  361. NSError *error = nil;
  362. [self writeSettings:newEndpointJSON error:&error];
  363. NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
  364. [self.settings cacheSettingsWithGoogleAppID:TestGoogleAppID currentTimestamp:currentTimestamp];
  365. XCTAssertNil(error, "%@", error);
  366. }
  367. @end