GDTCORFlatFileStorageTest.m 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * Copyright 2018 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 "GDTCORTests/Unit/GDTCORTestCase.h"
  17. #import "GDTCORLibrary/Private/GDTCORFlatFileStorage.h"
  18. #import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
  19. #import "GDTCORLibrary/Public/GDTCOREvent.h"
  20. #import "GDTCORLibrary/Public/GDTCORPlatform.h"
  21. #import "GDTCORLibrary/Public/GDTCORRegistrar.h"
  22. #import "GDTCORTests/Unit/Helpers/GDTCORAssertHelper.h"
  23. #import "GDTCORTests/Unit/Helpers/GDTCORDataObjectTesterClasses.h"
  24. #import "GDTCORTests/Unit/Helpers/GDTCORTestPrioritizer.h"
  25. #import "GDTCORTests/Unit/Helpers/GDTCORTestUploader.h"
  26. #import "GDTCORTests/Common/Fakes/GDTCORUploadCoordinatorFake.h"
  27. #import "GDTCORTests/Common/Categories/GDTCORFlatFileStorage+Testing.h"
  28. #import "GDTCORTests/Common/Categories/GDTCORRegistrar+Testing.h"
  29. static NSInteger target = kGDTCORTargetCCT;
  30. @interface GDTCORFlatFileStorageTest : GDTCORTestCase
  31. /** The test backend implementation. */
  32. @property(nullable, nonatomic) GDTCORTestUploader *testBackend;
  33. /** The test prioritizer implementation. */
  34. @property(nullable, nonatomic) GDTCORTestPrioritizer *testPrioritizer;
  35. /** The uploader fake. */
  36. @property(nonatomic) GDTCORUploadCoordinatorFake *uploaderFake;
  37. @end
  38. @implementation GDTCORFlatFileStorageTest
  39. - (void)setUp {
  40. [super setUp];
  41. self.testBackend = [[GDTCORTestUploader alloc] init];
  42. self.testPrioritizer = [[GDTCORTestPrioritizer alloc] init];
  43. [[GDTCORRegistrar sharedInstance] registerUploader:_testBackend target:target];
  44. [[GDTCORRegistrar sharedInstance] registerPrioritizer:_testPrioritizer target:target];
  45. self.uploaderFake = [[GDTCORUploadCoordinatorFake alloc] init];
  46. [GDTCORFlatFileStorage sharedInstance].uploadCoordinator = self.uploaderFake;
  47. }
  48. - (void)tearDown {
  49. [super tearDown];
  50. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  51. });
  52. // Destroy these objects before the next test begins.
  53. self.testBackend = nil;
  54. self.testPrioritizer = nil;
  55. [[GDTCORRegistrar sharedInstance] reset];
  56. [[GDTCORFlatFileStorage sharedInstance] reset];
  57. [GDTCORFlatFileStorage sharedInstance].uploadCoordinator =
  58. [GDTCORUploadCoordinator sharedInstance];
  59. self.uploaderFake = nil;
  60. }
  61. /** Tests the singleton pattern. */
  62. - (void)testInit {
  63. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance], [GDTCORFlatFileStorage sharedInstance]);
  64. }
  65. /** Tests storing an event. */
  66. - (void)testStoreEvent {
  67. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  68. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  69. event.clockSnapshot = [GDTCORClock snapshot];
  70. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  71. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  72. storeEvent:event
  73. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  74. XCTAssertNotEqualObjects(event.eventID, @0);
  75. XCTAssertNil(error);
  76. [writtenExpectation fulfill];
  77. }]);
  78. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  79. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  80. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 1);
  81. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].targetToEventSet[@(target)].count, 1);
  82. NSURL *eventFile = event.fileURL;
  83. XCTAssertNotNil(eventFile);
  84. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  85. NSError *error;
  86. XCTAssertTrue([[NSFileManager defaultManager] removeItemAtPath:eventFile.path error:&error]);
  87. XCTAssertNil(error, @"There was an error deleting the eventFile: %@", error);
  88. });
  89. }
  90. /** Tests removing an event. */
  91. - (void)testRemoveEvent {
  92. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  93. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  94. event.clockSnapshot = [GDTCORClock snapshot];
  95. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  96. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  97. storeEvent:event
  98. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  99. XCTAssertNotEqualObjects(event.eventID, @0);
  100. XCTAssertNil(error);
  101. [writtenExpectation fulfill];
  102. }]);
  103. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  104. __block NSURL *eventFile;
  105. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  106. eventFile = event.fileURL;
  107. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  108. });
  109. NSSet *eventIDs =
  110. [NSSet setWithArray:[[GDTCORFlatFileStorage sharedInstance].storedEvents allKeys]];
  111. [[GDTCORFlatFileStorage sharedInstance] removeEvents:eventIDs];
  112. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  113. XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  114. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 0);
  115. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].targetToEventSet[@(target)].count, 0);
  116. });
  117. }
  118. /** Tests removing a set of events. */
  119. - (void)testRemoveEvents {
  120. GDTCORFlatFileStorage *storage = [GDTCORFlatFileStorage sharedInstance];
  121. GDTCOREvent *event1 = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  122. event1.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString1"];
  123. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  124. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  125. storeEvent:event1
  126. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  127. XCTAssertNotEqualObjects(event1.eventID, @0);
  128. XCTAssertNil(error);
  129. [writtenExpectation fulfill];
  130. }]);
  131. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  132. GDTCOREvent *event2 = [[GDTCOREvent alloc] initWithMappingID:@"100" target:target];
  133. event2.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString2"];
  134. writtenExpectation = [self expectationWithDescription:@"event written"];
  135. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  136. storeEvent:event2
  137. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  138. XCTAssertNotEqualObjects(event2.eventID, @0);
  139. XCTAssertNil(error);
  140. [writtenExpectation fulfill];
  141. }]);
  142. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  143. GDTCOREvent *event3 = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  144. event3.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString3"];
  145. writtenExpectation = [self expectationWithDescription:@"event written"];
  146. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  147. storeEvent:event3
  148. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  149. XCTAssertNotEqualObjects(event3.eventID, @0);
  150. XCTAssertNil(error);
  151. [writtenExpectation fulfill];
  152. }]);
  153. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  154. NSSet<NSNumber *> *eventIDSet =
  155. [NSSet setWithObjects:event1.eventID, event2.eventID, event3.eventID, nil];
  156. [storage removeEvents:eventIDSet];
  157. NSSet<GDTCOREvent *> *eventSet = [NSSet setWithObjects:event1, event2, event3, nil];
  158. dispatch_sync(storage.storageQueue, ^{
  159. XCTAssertNil(storage.storedEvents[event1.eventID]);
  160. XCTAssertNil(storage.storedEvents[event2.eventID]);
  161. XCTAssertNil(storage.storedEvents[event3.eventID]);
  162. XCTAssertEqual(storage.targetToEventSet[@(target)].count, 0);
  163. for (GDTCOREvent *event in eventSet) {
  164. XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:event.fileURL.path]);
  165. }
  166. });
  167. }
  168. /** Tests storing a few different events. */
  169. - (void)testStoreMultipleEvents {
  170. GDTCOREvent *event1 = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  171. event1.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString1"];
  172. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  173. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  174. storeEvent:event1
  175. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  176. XCTAssertNotEqualObjects(event1.eventID, @0);
  177. XCTAssertNil(error);
  178. [writtenExpectation fulfill];
  179. }]);
  180. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  181. XCTAssertNotNil(event1.fileURL);
  182. GDTCOREvent *event2 = [[GDTCOREvent alloc] initWithMappingID:@"100" target:target];
  183. event2.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString2"];
  184. writtenExpectation = [self expectationWithDescription:@"event written"];
  185. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  186. storeEvent:event2
  187. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  188. XCTAssertNotEqualObjects(event2.eventID, @0);
  189. XCTAssertNil(error);
  190. [writtenExpectation fulfill];
  191. }]);
  192. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  193. XCTAssertNotNil(event2.fileURL);
  194. GDTCOREvent *event3 = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  195. event3.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString3"];
  196. writtenExpectation = [self expectationWithDescription:@"event written"];
  197. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  198. storeEvent:event3
  199. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  200. XCTAssertNotEqualObjects(event3.eventID, @0);
  201. XCTAssertNil(error);
  202. [writtenExpectation fulfill];
  203. }]);
  204. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  205. XCTAssertNotNil(event3.fileURL);
  206. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  207. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 3);
  208. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].targetToEventSet[@(target)].count, 3);
  209. NSURL *event1File = event1.fileURL;
  210. XCTAssertNotNil(event1File);
  211. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:event1File.path]);
  212. NSError *error;
  213. XCTAssertTrue([[NSFileManager defaultManager] removeItemAtPath:event1File.path error:&error]);
  214. XCTAssertNil(error, @"There was an error deleting the eventFile: %@", error);
  215. NSURL *event2File = event2.fileURL;
  216. XCTAssertNotNil(event2File);
  217. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:event2File.path]);
  218. error = nil;
  219. XCTAssertTrue([[NSFileManager defaultManager] removeItemAtPath:event2File.path error:&error]);
  220. XCTAssertNil(error, @"There was an error deleting the eventFile: %@", error);
  221. NSURL *event3File = event3.fileURL;
  222. XCTAssertNotNil(event3File);
  223. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:event3File.path]);
  224. error = nil;
  225. XCTAssertTrue([[NSFileManager defaultManager] removeItemAtPath:event3File.path error:&error]);
  226. XCTAssertNil(error, @"There was an error deleting the eventFile: %@", error);
  227. });
  228. }
  229. /** Tests enforcing that a prioritizer does not retain the DataObjectTransportBytes of an event in
  230. * memory.
  231. */
  232. - (void)testEventDeallocationIsEnforced {
  233. __weak NSData *weakDataObjectTransportBytes;
  234. GDTCOREvent *event;
  235. @autoreleasepool {
  236. event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  237. weakDataObjectTransportBytes = [event.dataObject transportBytes];
  238. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  239. event.clockSnapshot = [GDTCORClock snapshot];
  240. // Store the event and wait for the expectation.
  241. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  242. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  243. storeEvent:event
  244. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  245. XCTAssertNotEqualObjects(event.eventID, @0);
  246. XCTAssertNil(error);
  247. [writtenExpectation fulfill];
  248. }]);
  249. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  250. }
  251. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  252. XCTAssertNil(weakDataObjectTransportBytes);
  253. XCTAssertNotNil(event);
  254. });
  255. NSURL *eventFile = event.fileURL;
  256. // This isn't strictly necessary because of the -waitForExpectations above.
  257. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  258. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  259. });
  260. // Ensure event was removed.
  261. NSSet *eventIDs =
  262. [NSSet setWithArray:[[GDTCORFlatFileStorage sharedInstance].storedEvents allKeys]];
  263. [[GDTCORFlatFileStorage sharedInstance] removeEvents:eventIDs];
  264. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  265. XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  266. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 0);
  267. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].targetToEventSet[@(target)].count, 0);
  268. });
  269. }
  270. /** Tests encoding and decoding the storage singleton correctly. */
  271. - (void)testNSSecureCoding {
  272. XCTAssertTrue([GDTCORFlatFileStorage supportsSecureCoding]);
  273. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  274. event.clockSnapshot = [GDTCORClock snapshot];
  275. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  276. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  277. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  278. storeEvent:event
  279. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  280. XCTAssertNotEqualObjects(event.eventID, @0);
  281. [writtenExpectation fulfill];
  282. }]);
  283. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  284. event = nil;
  285. __block NSData *storageData;
  286. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  287. NSError *error;
  288. storageData = GDTCOREncodeArchive([GDTCORFlatFileStorage sharedInstance], nil, &error);
  289. XCTAssertNil(error);
  290. XCTAssertNotNil(storageData);
  291. });
  292. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  293. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 1);
  294. });
  295. NSSet *eventIDs =
  296. [NSSet setWithArray:[[GDTCORFlatFileStorage sharedInstance].storedEvents allKeys]];
  297. [[GDTCORFlatFileStorage sharedInstance] removeEvents:eventIDs];
  298. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  299. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 0);
  300. });
  301. NSError *error;
  302. GDTCORFlatFileStorage *unarchivedStorage = (GDTCORFlatFileStorage *)GDTCORDecodeArchive(
  303. [GDTCORFlatFileStorage class], nil, storageData, &error);
  304. XCTAssertNil(error);
  305. XCTAssertNotNil(unarchivedStorage);
  306. XCTAssertGreaterThan([unarchivedStorage storedEvents].count, 0);
  307. }
  308. /** Tests encoding and decoding the storage singleton when calling -sharedInstance. */
  309. - (void)testNSSecureCodingWithSharedInstance {
  310. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  311. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  312. event.clockSnapshot = [GDTCORClock snapshot];
  313. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  314. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  315. storeEvent:event
  316. onComplete:^(BOOL wasWritten, NSError *_Nullable error) {
  317. XCTAssertNotEqualObjects(event.eventID, @0);
  318. [writtenExpectation fulfill];
  319. }]);
  320. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  321. event = nil;
  322. __block NSData *storageData;
  323. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  324. NSError *error;
  325. storageData = GDTCOREncodeArchive([GDTCORFlatFileStorage sharedInstance], nil, &error);
  326. XCTAssertNil(error);
  327. XCTAssertNotNil(storageData);
  328. });
  329. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  330. XCTAssertNotNil([GDTCORFlatFileStorage sharedInstance].storedEvents);
  331. XCTAssertGreaterThan([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 0);
  332. });
  333. NSSet *eventIDs =
  334. [NSSet setWithArray:[[GDTCORFlatFileStorage sharedInstance].storedEvents allKeys]];
  335. [[GDTCORFlatFileStorage sharedInstance] removeEvents:eventIDs];
  336. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  337. XCTAssertNotNil([GDTCORFlatFileStorage sharedInstance].storedEvents);
  338. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 0);
  339. });
  340. NSError *error;
  341. GDTCORFlatFileStorage *unarchivedStorage = (GDTCORFlatFileStorage *)GDTCORDecodeArchive(
  342. [GDTCORFlatFileStorage class], nil, storageData, &error);
  343. XCTAssertNil(error);
  344. XCTAssertNotNil(unarchivedStorage);
  345. XCTAssertNotNil([unarchivedStorage storedEvents]);
  346. XCTAssertGreaterThan([unarchivedStorage storedEvents].count, 0);
  347. }
  348. /** Tests sending a fast priority event causes an upload attempt. */
  349. - (void)testQoSTierFast {
  350. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  351. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:@"testString"];
  352. event.qosTier = GDTCOREventQoSFast;
  353. event.clockSnapshot = [GDTCORClock snapshot];
  354. XCTAssertFalse(self.uploaderFake.forceUploadCalled);
  355. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  356. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  357. storeEvent:event
  358. onComplete:^(BOOL wasWritten, NSError *error) {
  359. XCTAssertNotEqualObjects(event.eventID, @0);
  360. XCTAssertNil(error);
  361. [writtenExpectation fulfill];
  362. }]);
  363. [self waitForExpectations:@[ writtenExpectation ] timeout:10.0];
  364. dispatch_sync([GDTCORFlatFileStorage sharedInstance].storageQueue, ^{
  365. XCTAssertTrue(self.uploaderFake.forceUploadCalled);
  366. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].storedEvents.count, 1);
  367. XCTAssertEqual([GDTCORFlatFileStorage sharedInstance].targetToEventSet[@(target)].count, 1);
  368. NSURL *eventFile = event.fileURL;
  369. XCTAssertNotNil(eventFile);
  370. XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:eventFile.path]);
  371. NSError *error;
  372. XCTAssertTrue([[NSFileManager defaultManager] removeItemAtPath:eventFile.path error:&error]);
  373. XCTAssertNil(error, @"There was an error deleting the eventFile: %@", error);
  374. });
  375. }
  376. /** Fuzz tests the storing of events at the same time as a terminate lifecycle notification. This
  377. * test can fail if there's simultaneous access to ivars of GDTCORFlatFileStorage with one access
  378. * being off the storage's queue. The terminate lifecycle event should operate on and flush the
  379. * queue.
  380. */
  381. - (void)testStoringEventsDuringTerminate {
  382. int numberOfIterations = 1000;
  383. for (int i = 0; i < numberOfIterations; i++) {
  384. NSString *testString = [NSString stringWithFormat:@"testString %d", i];
  385. GDTCOREvent *event = [[GDTCOREvent alloc] initWithMappingID:@"404" target:target];
  386. event.dataObject = [[GDTCORDataObjectTesterSimple alloc] initWithString:testString];
  387. event.clockSnapshot = [GDTCORClock snapshot];
  388. XCTestExpectation *writtenExpectation = [self expectationWithDescription:@"event written"];
  389. XCTAssertNoThrow([[GDTCORFlatFileStorage sharedInstance]
  390. storeEvent:event
  391. onComplete:^(BOOL wasWritten, NSError *error) {
  392. XCTAssertNotEqualObjects(event.eventID, @0);
  393. [writtenExpectation fulfill];
  394. }]);
  395. [self waitForExpectationsWithTimeout:10 handler:nil];
  396. if (i % 5 == 0) {
  397. NSSet *eventIDs =
  398. [NSSet setWithArray:[[GDTCORFlatFileStorage sharedInstance].storedEvents allKeys]];
  399. [[GDTCORFlatFileStorage sharedInstance] removeEvents:eventIDs];
  400. }
  401. [NSNotificationCenter.defaultCenter
  402. postNotificationName:kGDTCORApplicationWillTerminateNotification
  403. object:nil];
  404. }
  405. }
  406. - (void)testSaveAndLoadLibraryData {
  407. __weak NSData *weakData;
  408. NSString *dataKey = NSStringFromSelector(_cmd);
  409. @autoreleasepool {
  410. NSData *data = [@"test data" dataUsingEncoding:NSUTF8StringEncoding];
  411. weakData = data;
  412. XCTestExpectation *expectation = [self expectationWithDescription:@"storage completion called"];
  413. [[GDTCORFlatFileStorage sharedInstance] storeLibraryData:data
  414. forKey:dataKey
  415. onComplete:^(NSError *_Nullable error) {
  416. XCTAssertNil(error);
  417. [expectation fulfill];
  418. }];
  419. [self waitForExpectations:@[ expectation ] timeout:10.0];
  420. }
  421. XCTAssertNil(weakData);
  422. XCTestExpectation *expectation = [self expectationWithDescription:@"retrieval completion called"];
  423. [[GDTCORFlatFileStorage sharedInstance]
  424. libraryDataForKey:dataKey
  425. onComplete:^(NSData *_Nullable data, NSError *_Nullable error) {
  426. [expectation fulfill];
  427. XCTAssertNil(error);
  428. XCTAssertEqualObjects(@"test data",
  429. [[NSString alloc] initWithData:data
  430. encoding:NSUTF8StringEncoding]);
  431. }];
  432. [self waitForExpectations:@[ expectation ] timeout:10.0];
  433. }
  434. - (void)testSavingNilLibraryData {
  435. XCTestExpectation *expectation = [self expectationWithDescription:@"storage completion called"];
  436. [[GDTCORFlatFileStorage sharedInstance] storeLibraryData:[NSData data]
  437. forKey:@"test data key"
  438. onComplete:^(NSError *_Nullable error) {
  439. XCTAssertNotNil(error);
  440. [expectation fulfill];
  441. }];
  442. [self waitForExpectations:@[ expectation ] timeout:10.0];
  443. }
  444. - (void)testSaveAndRemoveLibraryData {
  445. NSString *dataKey = NSStringFromSelector(_cmd);
  446. NSData *data = [@"test data" dataUsingEncoding:NSUTF8StringEncoding];
  447. XCTestExpectation *expectation = [self expectationWithDescription:@"storage completion called"];
  448. [[GDTCORFlatFileStorage sharedInstance] storeLibraryData:data
  449. forKey:dataKey
  450. onComplete:^(NSError *_Nullable error) {
  451. XCTAssertNil(error);
  452. [expectation fulfill];
  453. }];
  454. [self waitForExpectations:@[ expectation ] timeout:10.0];
  455. expectation = [self expectationWithDescription:@"retrieval completion called"];
  456. [[GDTCORFlatFileStorage sharedInstance]
  457. libraryDataForKey:dataKey
  458. onComplete:^(NSData *_Nullable data, NSError *_Nullable error) {
  459. [expectation fulfill];
  460. XCTAssertNil(error);
  461. XCTAssertEqualObjects(@"test data",
  462. [[NSString alloc] initWithData:data
  463. encoding:NSUTF8StringEncoding]);
  464. }];
  465. [self waitForExpectations:@[ expectation ] timeout:10.0];
  466. expectation = [self expectationWithDescription:@"removal completion called"];
  467. [[GDTCORFlatFileStorage sharedInstance] removeLibraryDataForKey:dataKey
  468. onComplete:^(NSError *error) {
  469. [expectation fulfill];
  470. XCTAssertNil(error);
  471. }];
  472. [self waitForExpectations:@[ expectation ] timeout:10.0];
  473. expectation = [self expectationWithDescription:@"retrieval completion called"];
  474. [[GDTCORFlatFileStorage sharedInstance]
  475. libraryDataForKey:dataKey
  476. onComplete:^(NSData *_Nullable data, NSError *_Nullable error) {
  477. [expectation fulfill];
  478. XCTAssertNotNil(error);
  479. XCTAssertNil(data);
  480. }];
  481. [self waitForExpectations:@[ expectation ] timeout:10.0];
  482. }
  483. /** Tests migration from v1 of the storage format to v2. */
  484. - (void)testMigrationFromOldVersion {
  485. static NSString *base64EncodedArchive =
  486. @"YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0cxIAAYagXxAPTlN"
  487. @"LZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxBxAAsADAAVADsASQBPAFUAVgBcAGAAYQBiAGMAbQBxAHUAfQCBAIUAhg"
  488. @"CKAJIAlgCaAJsAnwCnAKsArwCwALQAvADAAMQAxQDGAMoA0gDWANoA2wDfAOcA6wDvAPAA8QD1AP0BAQEFAQYBCgESA"
  489. @"RYBGgEbAR8BJwErAS8BMAE0ATwBQAFEAUUBSQFRAVUBWQFaAV4BZgFqAW4BbwFwAXQBfAGAAYQBhQGJAZEBlQGZAZoB"
  490. @"ngGmAaoBrgGvAbABtAG8AcABxAHFAckB0QHVAdkB2gHeAeMB7QH2AfsCCgIPAhECFVUkbnVsbNQADQAOAA8AEAARABI"
  491. @"AEwAUXxAhR0RUQ09SU3RvcmFnZVVwbG9hZENvb3JkaW5hdG9yS2V5XxAgR0RUQ09SU3RvcmFnZVRhcmdldFRvRXZlbn"
  492. @"RTZXRLZXlfEBxHRFRDT1JTdG9yYWdlU3RvcmVkRXZlbnRzS2V5ViRjbGFzc4BugGmAAoBw3xATABYAFwAYABkAGgAbA"
  493. @"BwAHQAeAB8AIAAQACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOltOUy5v"
  494. @"YmplY3QuNlxOUy5vYmplY3QuMTZbTlMub2JqZWN0LjdbTlMub2JqZWN0LjhcTlMub2JqZWN0LjE3W05TLm9iamVjdC4"
  495. @"5XE5TLm9iamVjdC4xMFxOUy5vYmplY3QuMTFbTlMub2JqZWN0LjBcTlMub2JqZWN0LjEyW05TLm9iamVjdC4xW05TLm"
  496. @"9iamVjdC4yXE5TLm9iamVjdC4xM1tOUy5vYmplY3QuM1xOUy5vYmplY3QuMTRbTlMub2JqZWN0LjRbTlMub2JqZWN0L"
  497. @"jVcTlMub2JqZWN0LjE1gCmAXoAvgDSAY4A5gD6AQ4ADgEiAD4BogBSAToAZgFOAHoAkgFjXABAAPAA9AD4APwBAAEEA"
  498. @"QgBDAEQARQBGAEcASF8QGkdEVENPUlN0b3JlZEV2ZW50VGFyZ2V0S2V5XxAeR0RUQ09SU3RvcmVkRXZlbnREYXRhRnV"
  499. @"0dXJlS2V5XxAbR0RUQ09SU3RvcmVkRXZlbnRRb3NUaWVyS2V5XxAlR0RUQ09SU3RvcmVkRXZlbnRjdXN0b21CeXRlc1"
  500. @"BhcmFtc0tleV8QIUdEVENPUlN0b3JlZEV2ZW50Q2xvY2tTbmFwc2hvdEtleV8QHUdEVENPUlN0b3JlZEV2ZW50TWFwc"
  501. @"GluZ0lES2V5gA6ACoAEgAuAAIAMgAnTABAASgBLAEwARgBOXxAXR0RUQ09SRGF0YUZ1dHVyZURhdGFLZXlfEBpHRFRD"
  502. @"T1JEYXRhRnV0dXJlRmlsZVVSTEtleYAIgACABdMAUAAQAFEARgBTAFRXTlMuYmFzZVtOUy5yZWxhdGl2ZYAAgAeABl8"
  503. @"Q5GZpbGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMD"
  504. @"BCMS05MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyM"
  505. @"DcyQjQtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9l"
  506. @"dmVudC0xODI5Nzg1NzIwNjcyMjc5OTkwONIAVwBYAFkAWlokY2xhc3NuYW1lWCRjbGFzc2VzVU5TVVJMogBZAFtYTlN"
  507. @"PYmplY3TSAFcAWABdAF5fEBBHRFRDT1JEYXRhRnV0dXJlogBfAFtfEBBHRFRDT1JEYXRhRnV0dXJlVDEwMTgRA+gQAd"
  508. @"UAEABkAGUAZgBnAGgAaQBqAGsAbF8QFUdEVENPUkNsb2NrVGltZU1pbGxpc18QEUdEVENPUkNsb2NrVXB0aW1lXxAgR"
  509. @"0RUQ09SQ2xvY2tUaW1lem9uZU9mZnNldFNlY29uZHNfEBlHRFRDT1JDbG9ja0tlcm5lbEJvb3RUaW1lgA0TAAABcEWS"
  510. @"uikTAAACb3DqLb8T////////j4ATAAWcIFQ9BZLSAFcAWABuAG9bR0RUQ09SQ2xvY2uiAHAAW1tHRFRDT1JDbG9ja9I"
  511. @"AVwBYAHIAc18QEUdEVENPUlN0b3JlZEV2ZW50ogB0AFtfEBFHRFRDT1JTdG9yZWRFdmVudNcAEAA8AD0APgA/AEAAQQ"
  512. @"BCAEMAeABFAEYAewBIgA6ACoAQgAuAAIATgAnTABAASgBLAEwARgCAgAiAAIAR0wBQABAAUQBGAFMAhIAAgAeAEl8Q5"
  513. @"GZpbGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBC"
  514. @"MS05MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDc"
  515. @"yQjQtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldm"
  516. @"VudC0xODI5NzcwODE2NDQwNDM0OTE4MdUAEABkAGUAZgBnAGgAiACJAGsAbIANEwAAAXBFkrrLEwAAAm9w7KYU1wAQA"
  517. @"DwAPQA+AD8AQABBAEIAQwCNAEUARgCQAEiADoAKgBWAC4AAgBiACdMAEABKAEsATABGAJWACIAAgBbTAFAAEABRAEYA"
  518. @"UwCZgACAB4AXXxDkZmlsZTovLy9Vc2Vycy9oYW5leW0vTGlicmFyeS9EZXZlbG9wZXIvQ29yZVNpbXVsYXRvci9EZXZ"
  519. @"pY2VzLzdDRkMwMEIxLTkwNzQtNDY0OC1BNEIwLUI3OTRGRjNFQzY5MS9kYXRhL0NvbnRhaW5lcnMvRGF0YS9BcHBsaW"
  520. @"NhdGlvbi84RTIwNzJCNC02NjNCLTQ1N0UtOUZBQy1GNUFBQjAwNkFGRkEvTGlicmFyeS9DYWNoZXMvZ29vZ2xlLXNka"
  521. @"3MtZXZlbnRzL2V2ZW50LTE4Mjk1OTM1ODIwNjI5NzUxODU41QAQAGQAZQBmAGcAaACdAJ4AawBsgA0TAAABcEWSu14T"
  522. @"AAACb3Du5R7XABAAPAA9AD4APwBAAEEAQgBDAKIARQBGAKUASIAOgAqAGoALgACAHYAJ0wAQAEoASwBMAEYAqoAIgAC"
  523. @"AG9MAUAAQAFEARgBTAK6AAIAHgBxfEORmaWxlOi8vL1VzZXJzL2hhbmV5bS9MaWJyYXJ5L0RldmVsb3Blci9Db3JlU2"
  524. @"ltdWxhdG9yL0RldmljZXMvN0NGQzAwQjEtOTA3NC00NjQ4LUE0QjAtQjc5NEZGM0VDNjkxL2RhdGEvQ29udGFpbmVyc"
  525. @"y9EYXRhL0FwcGxpY2F0aW9uLzhFMjA3MkI0LTY2M0ItNDU3RS05RkFDLUY1QUFCMDA2QUZGQS9MaWJyYXJ5L0NhY2hl"
  526. @"cy9nb29nbGUtc2Rrcy1ldmVudHMvZXZlbnQtMTgyOTY5NjUyNDM0ODIxNTA3NDPVABAAZABlAGYAZwBoALIAswBrAGy"
  527. @"ADRMAAAFwRZK8FhMAAAJvcPGzA9cAEAA8AD0APgA/AEAAQQBCAEMAtwC4AEYAugBIgA6ACoAfgCKAAIAjgAnTABAASg"
  528. @"BLAEwARgC/gAiAAIAg0wBQABAAUQBGAFMAw4AAgAeAIV8Q5GZpbGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2Z"
  529. @"WxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS05MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0"
  530. @"YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQjQtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0x"
  531. @"pYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVudC0xODI5OTgzMTA3OTY1MDA2NDQwMBAD1QAQAGQAZQ"
  532. @"BmAGcAaADIAMkAawBsgA0TAAABcEWSveMTAAACb3D4vMfXABAAPAA9AD4APwBAAEEAQgBDAM0AuABGANAASIAOgAqAJ"
  533. @"YAigACAKIAJ0wAQAEoASwBMAEYA1YAIgACAJtMAUAAQAFEARgBTANmAAIAHgCdfEORmaWxlOi8vL1VzZXJzL2hhbmV5"
  534. @"bS9MaWJyYXJ5L0RldmVsb3Blci9Db3JlU2ltdWxhdG9yL0RldmljZXMvN0NGQzAwQjEtOTA3NC00NjQ4LUE0QjAtQjc"
  535. @"5NEZGM0VDNjkxL2RhdGEvQ29udGFpbmVycy9EYXRhL0FwcGxpY2F0aW9uLzhFMjA3MkI0LTY2M0ItNDU3RS05RkFDLU"
  536. @"Y1QUFCMDA2QUZGQS9MaWJyYXJ5L0NhY2hlcy9nb29nbGUtc2Rrcy1ldmVudHMvZXZlbnQtMTgyOTg2ODA3Njk5NzU4M"
  537. @"DUxMjHVABAAZABlAGYAZwBoAN0A3gBrAGyADRMAAAFwRZK+lhMAAAJvcPt089cAEAA8AD0APgA/AEAAQQBCAOEA4gC4"
  538. @"AEYA5QBIgA6ALYAqgCKAAIAugAnTABAASgBLAEwARgDqgAiAAIAr0wBQABAAUQBGAFMA7oAAgAeALF8Q5GZpbGU6Ly8"
  539. @"vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS05MDc0LT"
  540. @"Q2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQjQtNjYzQ"
  541. @"i00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVudC0xODMw"
  542. @"MDUyNTEyMjAxMDQxNTY5NRED6dUAEABkAGUAZgBnAGgA8wD0AGsAbIANEwAAAXBFksI/EwAAAm9xCcJF1wAQADwAPQA"
  543. @"+AD8AQABBAEIA4QD4ALgARgD7AEiADoAtgDCAIoAAgDOACdMAEABKAEsATABGAQCACIAAgDHTAFAAEABRAEYAUwEEgA"
  544. @"CAB4AyXxDkZmlsZTovLy9Vc2Vycy9oYW5leW0vTGlicmFyeS9EZXZlbG9wZXIvQ29yZVNpbXVsYXRvci9EZXZpY2VzL"
  545. @"zdDRkMwMEIxLTkwNzQtNDY0OC1BNEIwLUI3OTRGRjNFQzY5MS9kYXRhL0NvbnRhaW5lcnMvRGF0YS9BcHBsaWNhdGlv"
  546. @"bi84RTIwNzJCNC02NjNCLTQ1N0UtOUZBQy1GNUFBQjAwNkFGRkEvTGlicmFyeS9DYWNoZXMvZ29vZ2xlLXNka3MtZXZ"
  547. @"lbnRzL2V2ZW50LTE4Mjg1ODc4MDYzMDU2ODM3MjUw1QAQAGQAZQBmAGcAaAEIAQkAawBsgA0TAAABcEWSw8MTAAACb3"
  548. @"EPrWTXABAAPAA9AD4APwBAAEEAQgDhAQ0AuABGARAASIAOgC2ANYAigACAOIAJ0wAQAEoASwBMAEYBFYAIgACANtMAU"
  549. @"AAQAFEARgBTARmAAIAHgDdfEORmaWxlOi8vL1VzZXJzL2hhbmV5bS9MaWJyYXJ5L0RldmVsb3Blci9Db3JlU2ltdWxh"
  550. @"dG9yL0RldmljZXMvN0NGQzAwQjEtOTA3NC00NjQ4LUE0QjAtQjc5NEZGM0VDNjkxL2RhdGEvQ29udGFpbmVycy9EYXR"
  551. @"hL0FwcGxpY2F0aW9uLzhFMjA3MkI0LTY2M0ItNDU3RS05RkFDLUY1QUFCMDA2QUZGQS9MaWJyYXJ5L0NhY2hlcy9nb2"
  552. @"9nbGUtc2Rrcy1ldmVudHMvZXZlbnQtMTgyODY0MTI4Njg1OTcwMzcwNzDVABAAZABlAGYAZwBoAR0BHgBrAGyADRMAA"
  553. @"AFwRZLElRMAAAJvcRLh3tcAEAA8AD0APgA/AEAAQQBCAOEBIgBFAEYBJQBIgA6ALYA6gAuAAIA9gAnTABAASgBLAEwA"
  554. @"RgEqgAiAAIA70wBQABAAUQBGAFMBLoAAgAeAPF8Q5GZpbGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGV"
  555. @"yL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS05MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db2"
  556. @"50YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQjQtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhc"
  557. @"nkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVudC0xODI4NTM5MTg3NjI3NTA4Mjk1MdUAEABkAGUAZgBnAGgB"
  558. @"MgEzAGsAbIANEwAAAXBFksZ7EwAAAm9xGktv1wAQADwAPQA+AD8AQABBAEIA4QE3AEUARgE6AEiADoAtgD+AC4AAgEK"
  559. @"ACdMAEABKAEsATABGAT+ACIAAgEDTAFAAEABRAEYAUwFDgACAB4BBXxDkZmlsZTovLy9Vc2Vycy9oYW5leW0vTGlicm"
  560. @"FyeS9EZXZlbG9wZXIvQ29yZVNpbXVsYXRvci9EZXZpY2VzLzdDRkMwMEIxLTkwNzQtNDY0OC1BNEIwLUI3OTRGRjNFQ"
  561. @"zY5MS9kYXRhL0NvbnRhaW5lcnMvRGF0YS9BcHBsaWNhdGlvbi84RTIwNzJCNC02NjNCLTQ1N0UtOUZBQy1GNUFBQjAw"
  562. @"NkFGRkEvTGlicmFyeS9DYWNoZXMvZ29vZ2xlLXNka3MtZXZlbnRzL2V2ZW50LTE4Mjg4MDcyODk3NDM3NDg0MDYy1QA"
  563. @"QAGQAZQBmAGcAaAFHAUgAawBsgA0TAAABcEWSxxwTAAACb3EcwoHXABAAPAA9AD4APwBAAEEAQgDhAUwARQBGAU8ASI"
  564. @"AOgC2ARIALgACAR4AJ0wAQAEoASwBMAEYBVIAIgACARdMAUAAQAFEARgBTAViAAIAHgEZfEORmaWxlOi8vL1VzZXJzL"
  565. @"2hhbmV5bS9MaWJyYXJ5L0RldmVsb3Blci9Db3JlU2ltdWxhdG9yL0RldmljZXMvN0NGQzAwQjEtOTA3NC00NjQ4LUE0"
  566. @"QjAtQjc5NEZGM0VDNjkxL2RhdGEvQ29udGFpbmVycy9EYXRhL0FwcGxpY2F0aW9uLzhFMjA3MkI0LTY2M0ItNDU3RS0"
  567. @"5RkFDLUY1QUFCMDA2QUZGQS9MaWJyYXJ5L0NhY2hlcy9nb29nbGUtc2Rrcy1ldmVudHMvZXZlbnQtMTgyODkwNDg0ND"
  568. @"AxMzk0MDIwNDbVABAAZABlAGYAZwBoAVwBXQBrAGyADRMAAAFwRZLHuBMAAAJvcR8jBdcAEAA8AD0APgA/AEAAQQBCA"
  569. @"OEBYQFiAEYBZABIgA6ALYBJgEyAAIBNgAnTABAASgBLAEwARgFpgAiAAIBK0wBQABAAUQBGAFMBbYAAgAeAS18Q5GZp"
  570. @"bGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS0"
  571. @"5MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQj"
  572. @"QtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVud"
  573. @"C0xODI5MDU2NDQ2MDYyMzE0NDA2NRAF1QAQAGQAZQBmAGcAaAFyAXMAawBsgA0TAAABcEWSydcTAAACb3EnbeLXABAA"
  574. @"PAA9AD4APwBAAEEAQgDhAXcBYgBGAXoASIAOgC2AT4BMgACAUoAJ0wAQAEoASwBMAEYBf4AIgACAUNMAUAAQAFEARgB"
  575. @"TAYOAAIAHgFFfEORmaWxlOi8vL1VzZXJzL2hhbmV5bS9MaWJyYXJ5L0RldmVsb3Blci9Db3JlU2ltdWxhdG9yL0Rldm"
  576. @"ljZXMvN0NGQzAwQjEtOTA3NC00NjQ4LUE0QjAtQjc5NEZGM0VDNjkxL2RhdGEvQ29udGFpbmVycy9EYXRhL0FwcGxpY"
  577. @"2F0aW9uLzhFMjA3MkI0LTY2M0ItNDU3RS05RkFDLUY1QUFCMDA2QUZGQS9MaWJyYXJ5L0NhY2hlcy9nb29nbGUtc2Rr"
  578. @"cy1ldmVudHMvZXZlbnQtMTgyOTAzMzI5MDkwMzM5NDQ3ODLVABAAZABlAGYAZwBoAYcBiABrAGyADRMAAAFwRZLKcRM"
  579. @"AAAJvcSnE+9cAEAA8AD0APgA/AEAAQQBCAOEBjAFiAEYBjwBIgA6ALYBUgEyAAIBXgAnTABAASgBLAEwARgGUgAiAAI"
  580. @"BV0wBQABAAUQBGAFMBmIAAgAeAVl8Q5GZpbGU6Ly8vVXNlcnMvaGFuZXltL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTa"
  581. @"W11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS05MDc0LTQ2NDgtQTRCMC1CNzk0RkYzRUM2OTEvZGF0YS9Db250YWluZXJz"
  582. @"L0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQjQtNjYzQi00NTdFLTlGQUMtRjVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGV"
  583. @"zL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVudC0xODI5MDg3MzY1MzgwODczNjM4NNUAEABkAGUAZgBnAGgBnAGdAGsAbI"
  584. @"ANEwAAAXBFkssiEwAAAm9xLHlG1wAQADwAPQA+AD8AQABBAEIA4QGhAaIARgGkAEiADoAtgFmAXIAAgF2ACdMAEABKA"
  585. @"EsATABGAamACIAAgFrTAFAAEABRAEYAUwGtgACAB4BbXxDkZmlsZTovLy9Vc2Vycy9oYW5leW0vTGlicmFyeS9EZXZl"
  586. @"bG9wZXIvQ29yZVNpbXVsYXRvci9EZXZpY2VzLzdDRkMwMEIxLTkwNzQtNDY0OC1BNEIwLUI3OTRGRjNFQzY5MS9kYXR"
  587. @"hL0NvbnRhaW5lcnMvRGF0YS9BcHBsaWNhdGlvbi84RTIwNzJCNC02NjNCLTQ1N0UtOUZBQy1GNUFBQjAwNkFGRkEvTG"
  588. @"licmFyeS9DYWNoZXMvZ29vZ2xlLXNka3MtZXZlbnRzL2V2ZW50LTE4MjkwMTg5OTgwODEwODcxNjk4EALVABAAZABlA"
  589. @"GYAZwBoAbIBswBrAGyADRMAAAFwRZLMtRMAAAJvcTKfNtcAEAA8AD0APgA/AEAAQQBCAOEBtwGiAEYBugBIgA6ALYBf"
  590. @"gFyAAIBigAnTABAASgBLAEwARgG/gAiAAIBg0wBQABAAUQBGAFMBw4AAgAeAYV8Q5GZpbGU6Ly8vVXNlcnMvaGFuZXl"
  591. @"tL0xpYnJhcnkvRGV2ZWxvcGVyL0NvcmVTaW11bGF0b3IvRGV2aWNlcy83Q0ZDMDBCMS05MDc0LTQ2NDgtQTRCMC1CNz"
  592. @"k0RkYzRUM2OTEvZGF0YS9Db250YWluZXJzL0RhdGEvQXBwbGljYXRpb24vOEUyMDcyQjQtNjYzQi00NTdFLTlGQUMtR"
  593. @"jVBQUIwMDZBRkZBL0xpYnJhcnkvQ2FjaGVzL2dvb2dsZS1zZGtzLWV2ZW50cy9ldmVudC0xODI5MzA1NjUzNjM1MjA0"
  594. @"NDYxOdUAEABkAGUAZgBnAGgBxwHIAGsAbIANEwAAAXBFks2BEwAAAm9xNbwL1wAQADwAPQA+AD8AQABBAEIA4QHMAaI"
  595. @"ARgHPAEiADoAtgGSAXIAAgGeACdMAEABKAEsATABGAdSACIAAgGXTAFAAEABRAEYAUwHYgACAB4BmXxDkZmlsZTovLy"
  596. @"9Vc2Vycy9oYW5leW0vTGlicmFyeS9EZXZlbG9wZXIvQ29yZVNpbXVsYXRvci9EZXZpY2VzLzdDRkMwMEIxLTkwNzQtN"
  597. @"DY0OC1BNEIwLUI3OTRGRjNFQzY5MS9kYXRhL0NvbnRhaW5lcnMvRGF0YS9BcHBsaWNhdGlvbi84RTIwNzJCNC02NjNC"
  598. @"LTQ1N0UtOUZBQy1GNUFBQjAwNkFGRkEvTGlicmFyeS9DYWNoZXMvZ29vZ2xlLXNka3MtZXZlbnRzL2V2ZW50LTE4Mjk"
  599. @"zNDI4OTExMjU2MzE1MjY21QAQAGQAZQBmAGcAaAHcAd0AawBsgA0TAAABcEWSziwTAAACb3E4V7/SAFcAWAHfAeBfEB"
  600. @"NOU011dGFibGVPcmRlcmVkU2V0owHhAeIAW18QE05TTXV0YWJsZU9yZGVyZWRTZXRcTlNPcmRlcmVkU2V00wHkAeUAE"
  601. @"AHmAekB7FdOUy5rZXlzWk5TLm9iamVjdHOiAEMA4YAKgC2iAeoB64BqgGyAbdIB5QAQAe4B9aYANAA4ADAAMgA2ADmA"
  602. @"FIAegAOAD4AZgCSAa9IAVwBYAfcB+FxOU011dGFibGVTZXSjAfkB+gBbXE5TTXV0YWJsZVNldFVOU1NldNIB5QAQAfw"
  603. @"B9awAOgApADUALgAvACwANwAoAC0AKwAqADGAWIBegE6APoBDgGOAU4ApgDmANIAvgEiAa9IAVwBYAgsCDF8QE05TTX"
  604. @"V0YWJsZURpY3Rpb25hcnmjAg0CDgBbXxATTlNNdXRhYmxlRGljdGlvbmFyeVxOU0RpY3Rpb25hcnnRABACEIBv0gBXA"
  605. @"FgCEgITXxAXR0RUQ09SVXBsb2FkQ29vcmRpbmF0b3KiAhQAW18QF0dEVENPUlVwbG9hZENvb3JkaW5hdG9y0gBXAFgC"
  606. @"FgIXXUdEVENPUlN0b3JhZ2WiAhgAW11HRFRDT1JTdG9yYWdlAAgAGQAiACwAMQA6AD8AUQBWAFsAXQFCAUgBWQF9AaA"
  607. @"BvwHGAcgBygHMAc4CHQIpAjYCQgJOAlsCZwJ0AoECjQKaAqYCsgK/AssC2ALkAvAC/QL/AwEDAwMFAwcDCQMLAw0DDw"
  608. @"MRAxMDFQMXAxkDGwMdAx8DIQMjA0ADXQN+A5wDxAPoBAgECgQMBA4EEAQSBBQEFgQjBD0EWgRcBF4EYARtBHUEgQSDB"
  609. @"IUEhwVuBXcFggWLBZEFlgWfBagFuwXABdMF2AXbBd0F8gYKBh4GQQZdBl8GaAZxBnoGgwaMBpgGnQapBrIGxgbLBt8G"
  610. @"/Ab+BwAHAgcEBwYHCAcKBxcHGQcbBx0HKgcsBy4HMAgXCCwILgg3CEAIXQhfCGEIYwhlCGcIaQhrCHgIegh8CH4Iiwi"
  611. @"NCI8IkQl4CY0JjwmYCaEJvgnACcIJxAnGCcgJygnMCdkJ2wndCd8J7AnuCfAJ8grZCu4K8Ar5CwILHwshCyMLJQsnCy"
  612. @"kLKwstCzoLPAs+C0ALTQtPC1ELUww6DDwMUQxTDFwMZQyCDIQMhgyIDIoMjAyODJAMnQyfDKEMowywDLIMtAy2DZ0Ns"
  613. @"g20Db0Nxg3jDeUN5w3pDesN7Q3vDfEN/g4ADgIOBA4RDhMOFQ4XDv4PAQ8WDxgPIQ8qD0cPSQ9LD00PTw9RD1MPVQ9i"
  614. @"D2QPZg9oD3UPdw95D3sQYhB3EHkQghCLEKgQqhCsEK4QsBCyELQQthDDEMUQxxDJENYQ2BDaENwRwxHYEdoR4xHsEgk"
  615. @"SCxINEg8SERITEhUSFxIkEiYSKBIqEjcSORI7Ej0TJBM5EzsTRBNNE2oTbBNuE3ATchN0E3YTeBOFE4cTiROLE5gTmh"
  616. @"OcE54UhRSaFJwUpRSuFMsUzRTPFNEU0xTVFNcU2RTmFOgU6hTsFPkU+xT9FP8V5hX7Ff0WBhYPFiwWLhYwFjIWNBY2F"
  617. @"jgWOhZHFkkWSxZNFloWXBZeFmAXRxdJF14XYBdpF3IXjxeRF5MXlReXF5kXmxedF6oXrBeuF7AXvRe/F8EXwxiqGL8Y"
  618. @"wRjKGNMY8BjyGPQY9hj4GPoY/Bj+GQsZDRkPGREZHhkgGSIZJBoLGiAaIhorGjQaURpTGlUaVxpZGlsaXRpfGmwabhp"
  619. @"wGnIafxqBGoMahRtsG24bgxuFG44blxu0G7YbuBu6G7wbvhvAG8IbzxvRG9Mb1RviG+Qb5hvoHM8c5BzmHO8c+B0VHR"
  620. @"cdGR0bHR0dHx0hHSMdMB0yHTQdNh1DHUUdRx1JHjAeRR5HHlAeWR5iHngefx6VHqIerx63HsIexx7JHsse0B7SHtQe1"
  621. @"h7fHuwe7h7wHvIe9B72Hvge+h8DHxAfFx8kHyofMx9MH04fUB9SH1QfVh9YH1ofXB9eH2AfYh9kH2Yfbx+FH4wfoh+v"
  622. @"H7Qfth+/H9kf3h/4IAEgDyAUAAAAAAAAAgIAAAAAAAACGQAAAAAAAAAAAAAAAAAAICI=";
  623. NSData *v1ArchiveData = [[NSData alloc] initWithBase64EncodedString:base64EncodedArchive
  624. options:0];
  625. XCTAssertNotNil(v1ArchiveData);
  626. NSError *error;
  627. GDTCORFlatFileStorage *archiveStorage = (GDTCORFlatFileStorage *)GDTCORDecodeArchive(
  628. [GDTCORFlatFileStorage class], nil, v1ArchiveData, &error);
  629. XCTAssertNil(error);
  630. XCTAssertNotNil(archiveStorage);
  631. XCTAssertEqual(archiveStorage.targetToEventSet[@(kGDTCORTargetCCT)].count, 6);
  632. XCTAssertEqual(archiveStorage.targetToEventSet[@(kGDTCORTargetFLL)].count, 12);
  633. XCTAssertEqual(archiveStorage.storedEvents.count, 18);
  634. XCTAssertNotNil(archiveStorage.uploadCoordinator);
  635. }
  636. @end