FSTRemoteEventTests.m 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. * Copyright 2017 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 "Firestore/Source/Remote/FSTRemoteEvent.h"
  17. #import <XCTest/XCTest.h>
  18. #import "Firestore/Source/Local/FSTQueryData.h"
  19. #import "Firestore/Source/Model/FSTDocument.h"
  20. #import "Firestore/Source/Model/FSTDocumentKey.h"
  21. #import "Firestore/Source/Remote/FSTExistenceFilter.h"
  22. #import "Firestore/Source/Remote/FSTWatchChange.h"
  23. #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h"
  24. #import "Firestore/Example/Tests/Util/FSTHelpers.h"
  25. NS_ASSUME_NONNULL_BEGIN
  26. @interface FSTRemoteEventTests : XCTestCase
  27. @end
  28. @implementation FSTRemoteEventTests {
  29. NSData *_resumeToken1;
  30. NSMutableDictionary<NSNumber *, NSNumber *> *_noPendingResponses;
  31. }
  32. - (void)setUp {
  33. _resumeToken1 = [@"resume1" dataUsingEncoding:NSUTF8StringEncoding];
  34. _noPendingResponses = [NSMutableDictionary dictionary];
  35. }
  36. - (FSTWatchChangeAggregator *)aggregatorWithTargets:(NSArray<NSNumber *> *)targets
  37. outstanding:
  38. (NSDictionary<NSNumber *, NSNumber *> *)outstanding
  39. changes:(NSArray<FSTWatchChange *> *)watchChanges {
  40. NSMutableDictionary<NSNumber *, FSTQueryData *> *listens = [NSMutableDictionary dictionary];
  41. FSTQueryData *dummyQueryData = [FSTQueryData alloc];
  42. for (NSNumber *targetID in targets) {
  43. listens[targetID] = dummyQueryData;
  44. }
  45. FSTWatchChangeAggregator *aggregator =
  46. [[FSTWatchChangeAggregator alloc] initWithSnapshotVersion:FSTTestVersion(3)
  47. listenTargets:listens
  48. pendingTargetResponses:outstanding];
  49. [aggregator addWatchChanges:watchChanges];
  50. return aggregator;
  51. }
  52. - (void)testWillAccumulateDocumentAddedAndRemovedEvents {
  53. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  54. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  55. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @2, @3 ]
  56. removedTargetIDs:@[ @4, @5, @6 ]
  57. documentKey:doc1.key
  58. document:doc1];
  59. FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @4 ]
  60. removedTargetIDs:@[ @2, @6 ]
  61. documentKey:doc2.key
  62. document:doc2];
  63. FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargets:@[ @1, @2, @3, @4, @5, @6 ]
  64. outstanding:_noPendingResponses
  65. changes:@[ change1, change2 ]];
  66. FSTRemoteEvent *event = [aggregator remoteEvent];
  67. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  68. XCTAssertEqual(event.documentUpdates.count, 2);
  69. XCTAssertEqualObjects(event.documentUpdates[doc1.key], doc1);
  70. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  71. XCTAssertEqual(event.targetChanges.count, 6);
  72. FSTUpdateMapping *mapping1 =
  73. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1, doc2 ] removedDocuments:@[]];
  74. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  75. FSTUpdateMapping *mapping2 =
  76. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1 ] removedDocuments:@[ doc2 ]];
  77. XCTAssertEqualObjects(event.targetChanges[@2].mapping, mapping2);
  78. FSTUpdateMapping *mapping3 =
  79. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1 ] removedDocuments:@[]];
  80. XCTAssertEqualObjects(event.targetChanges[@3].mapping, mapping3);
  81. FSTUpdateMapping *mapping4 =
  82. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc2 ] removedDocuments:@[ doc1 ]];
  83. XCTAssertEqualObjects(event.targetChanges[@4].mapping, mapping4);
  84. FSTUpdateMapping *mapping5 =
  85. [FSTUpdateMapping mappingWithAddedDocuments:@[] removedDocuments:@[ doc1 ]];
  86. XCTAssertEqualObjects(event.targetChanges[@5].mapping, mapping5);
  87. FSTUpdateMapping *mapping6 =
  88. [FSTUpdateMapping mappingWithAddedDocuments:@[] removedDocuments:@[ doc1, doc2 ]];
  89. XCTAssertEqualObjects(event.targetChanges[@6].mapping, mapping6);
  90. }
  91. - (void)testWillIgnoreEventsForPendingTargets {
  92. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  93. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  94. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  95. removedTargetIDs:@[]
  96. documentKey:doc1.key
  97. document:doc1];
  98. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved
  99. targetIDs:@[ @1 ]
  100. cause:nil];
  101. FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded
  102. targetIDs:@[ @1 ]
  103. cause:nil];
  104. FSTWatchChange *change4 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  105. removedTargetIDs:@[]
  106. documentKey:doc2.key
  107. document:doc2];
  108. // We're waiting for the unwatch and watch ack
  109. NSDictionary<NSNumber *, NSNumber *> *pendingResponses = @{ @1 : @2 };
  110. FSTWatchChangeAggregator *aggregator =
  111. [self aggregatorWithTargets:@[ @1 ]
  112. outstanding:pendingResponses
  113. changes:@[ change1, change2, change3, change4 ]];
  114. FSTRemoteEvent *event = [aggregator remoteEvent];
  115. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  116. // doc1 is ignored because it was part of an inactive target, but doc2 is in the changes
  117. // because it become active.
  118. XCTAssertEqual(event.documentUpdates.count, 1);
  119. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  120. XCTAssertEqual(event.targetChanges.count, 1);
  121. }
  122. - (void)testWillIgnoreEventsForRemovedTargets {
  123. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  124. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  125. removedTargetIDs:@[]
  126. documentKey:doc1.key
  127. document:doc1];
  128. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved
  129. targetIDs:@[ @1 ]
  130. cause:nil];
  131. // We're waiting for the unwatch ack
  132. NSDictionary<NSNumber *, NSNumber *> *pendingResponses = @{ @1 : @1 };
  133. FSTWatchChangeAggregator *aggregator =
  134. [self aggregatorWithTargets:@[] outstanding:pendingResponses changes:@[ change1, change2 ]];
  135. FSTRemoteEvent *event = [aggregator remoteEvent];
  136. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  137. // doc1 is ignored because it was part of an inactive target
  138. XCTAssertEqual(event.documentUpdates.count, 0);
  139. // Target 1 is ignored because it was removed
  140. XCTAssertEqual(event.targetChanges.count, 0);
  141. }
  142. - (void)testWillKeepResetMappingEvenWithUpdates {
  143. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  144. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  145. FSTDocument *doc3 = FSTTestDoc(@"docs/3", 3, @{ @"value" : @3 }, NO);
  146. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  147. removedTargetIDs:@[]
  148. documentKey:doc1.key
  149. document:doc1];
  150. // Reset stream, ignoring doc1
  151. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset
  152. targetIDs:@[ @1 ]
  153. cause:nil];
  154. // Add doc2, doc3
  155. FSTWatchChange *change3 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  156. removedTargetIDs:@[]
  157. documentKey:doc2.key
  158. document:doc2];
  159. FSTWatchChange *change4 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  160. removedTargetIDs:@[]
  161. documentKey:doc3.key
  162. document:doc3];
  163. // Remove doc2 again, should not show up in reset mapping
  164. FSTWatchChange *change5 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[]
  165. removedTargetIDs:@[ @1 ]
  166. documentKey:doc2.key
  167. document:doc2];
  168. FSTWatchChangeAggregator *aggregator =
  169. [self aggregatorWithTargets:@[ @1 ]
  170. outstanding:_noPendingResponses
  171. changes:@[ change1, change2, change3, change4, change5 ]];
  172. FSTRemoteEvent *event = [aggregator remoteEvent];
  173. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  174. XCTAssertEqual(event.documentUpdates.count, 3);
  175. XCTAssertEqualObjects(event.documentUpdates[doc1.key], doc1);
  176. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  177. XCTAssertEqualObjects(event.documentUpdates[doc3.key], doc3);
  178. XCTAssertEqual(event.targetChanges.count, 1);
  179. // Only doc3 is part of the new mapping
  180. FSTResetMapping *expectedMapping = [FSTResetMapping mappingWithDocuments:@[ doc3 ]];
  181. XCTAssertEqualObjects(event.targetChanges[@1].mapping, expectedMapping);
  182. }
  183. - (void)testWillHandleSingleReset {
  184. // Reset target
  185. FSTWatchChange *change = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset
  186. targetIDs:@[ @1 ]
  187. cause:nil];
  188. FSTWatchChangeAggregator *aggregator =
  189. [self aggregatorWithTargets:@[ @1 ] outstanding:_noPendingResponses changes:@[ change ]];
  190. FSTRemoteEvent *event = [aggregator remoteEvent];
  191. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  192. XCTAssertEqual(event.documentUpdates.count, 0);
  193. XCTAssertEqual(event.targetChanges.count, 1);
  194. // Reset mapping is empty
  195. FSTResetMapping *expectedMapping = [FSTResetMapping mappingWithDocuments:@[]];
  196. XCTAssertEqualObjects(event.targetChanges[@1].mapping, expectedMapping);
  197. }
  198. - (void)testWillHandleTargetAddAndRemovalInSameBatch {
  199. FSTDocument *doc1a = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  200. FSTDocument *doc1b = FSTTestDoc(@"docs/1", 1, @{ @"value" : @2 }, NO);
  201. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  202. removedTargetIDs:@[ @2 ]
  203. documentKey:doc1a.key
  204. document:doc1a];
  205. FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @2 ]
  206. removedTargetIDs:@[ @1 ]
  207. documentKey:doc1b.key
  208. document:doc1b];
  209. FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargets:@[ @1, @2 ]
  210. outstanding:_noPendingResponses
  211. changes:@[ change1, change2 ]];
  212. FSTRemoteEvent *event = [aggregator remoteEvent];
  213. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  214. XCTAssertEqual(event.documentUpdates.count, 1);
  215. XCTAssertEqualObjects(event.documentUpdates[doc1b.key], doc1b);
  216. XCTAssertEqual(event.targetChanges.count, 2);
  217. FSTUpdateMapping *mapping1 =
  218. [FSTUpdateMapping mappingWithAddedDocuments:@[] removedDocuments:@[ doc1b ]];
  219. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  220. FSTUpdateMapping *mapping2 =
  221. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1b ] removedDocuments:@[]];
  222. XCTAssertEqualObjects(event.targetChanges[@2].mapping, mapping2);
  223. }
  224. - (void)testTargetCurrentChangeWillMarkTheTargetCurrent {
  225. FSTWatchChange *change = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  226. targetIDs:@[ @1 ]
  227. resumeToken:_resumeToken1];
  228. FSTWatchChangeAggregator *aggregator =
  229. [self aggregatorWithTargets:@[ @1 ] outstanding:_noPendingResponses changes:@[ change ]];
  230. FSTRemoteEvent *event = [aggregator remoteEvent];
  231. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  232. XCTAssertEqual(event.documentUpdates.count, 0);
  233. XCTAssertEqual(event.targetChanges.count, 1);
  234. FSTTargetChange *targetChange = event.targetChanges[@1];
  235. XCTAssertEqualObjects(targetChange.mapping, [[FSTUpdateMapping alloc] init]);
  236. XCTAssertEqual(targetChange.currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  237. XCTAssertEqualObjects(targetChange.resumeToken, _resumeToken1);
  238. }
  239. - (void)testTargetAddedChangeWillResetPreviousState {
  240. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  241. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  242. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @3 ]
  243. removedTargetIDs:@[ @2 ]
  244. documentKey:doc1.key
  245. document:doc1];
  246. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  247. targetIDs:@[ @1, @2, @3 ]
  248. resumeToken:_resumeToken1];
  249. FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved
  250. targetIDs:@[ @1 ]
  251. cause:nil];
  252. FSTWatchChange *change4 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved
  253. targetIDs:@[ @2 ]
  254. cause:nil];
  255. FSTWatchChange *change5 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded
  256. targetIDs:@[ @1 ]
  257. cause:nil];
  258. FSTWatchChange *change6 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  259. removedTargetIDs:@[ @3 ]
  260. documentKey:doc2.key
  261. document:doc2];
  262. NSDictionary<NSNumber *, NSNumber *> *pendingResponses = @{ @1 : @2, @2 : @1 };
  263. FSTWatchChangeAggregator *aggregator =
  264. [self aggregatorWithTargets:@[ @1, @3 ]
  265. outstanding:pendingResponses
  266. changes:@[ change1, change2, change3, change4, change5, change6 ]];
  267. FSTRemoteEvent *event = [aggregator remoteEvent];
  268. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  269. XCTAssertEqual(event.documentUpdates.count, 2);
  270. XCTAssertEqualObjects(event.documentUpdates[doc1.key], doc1);
  271. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  272. // target 1 and 3 are affected (1 because of re-add), target 2 is not because of remove
  273. XCTAssertEqual(event.targetChanges.count, 2);
  274. // doc1 was before the remove, so it does not show up in the mapping
  275. FSTUpdateMapping *mapping1 =
  276. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc2 ] removedDocuments:@[]];
  277. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  278. // Current was before the remove
  279. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateNone);
  280. // Doc1 was before the remove
  281. FSTUpdateMapping *mapping3 =
  282. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1 ] removedDocuments:@[ doc2 ]];
  283. XCTAssertEqualObjects(event.targetChanges[@3].mapping, mapping3);
  284. // Current was before the remove
  285. XCTAssertEqual(event.targetChanges[@3].currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  286. XCTAssertEqualObjects(event.targetChanges[@3].resumeToken, _resumeToken1);
  287. }
  288. - (void)testNoChangeWillStillMarkTheAffectedTargets {
  289. FSTWatchChange *change = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange
  290. targetIDs:@[ @1 ]
  291. resumeToken:_resumeToken1];
  292. FSTWatchChangeAggregator *aggregator =
  293. [self aggregatorWithTargets:@[ @1 ] outstanding:_noPendingResponses changes:@[ change ]];
  294. FSTRemoteEvent *event = [aggregator remoteEvent];
  295. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  296. XCTAssertEqual(event.documentUpdates.count, 0);
  297. XCTAssertEqual(event.targetChanges.count, 1);
  298. XCTAssertEqualObjects(event.targetChanges[@1].mapping, [[FSTUpdateMapping alloc] init]);
  299. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateNone);
  300. XCTAssertEqualObjects(event.targetChanges[@1].resumeToken, _resumeToken1);
  301. }
  302. - (void)testExistenceFiltersWillReplacePreviousExistenceFilters {
  303. FSTExistenceFilter *filter1 = [FSTExistenceFilter filterWithCount:1];
  304. FSTExistenceFilter *filter2 = [FSTExistenceFilter filterWithCount:2];
  305. FSTWatchChange *change1 = [FSTExistenceFilterWatchChange changeWithFilter:filter1 targetID:1];
  306. FSTWatchChange *change2 = [FSTExistenceFilterWatchChange changeWithFilter:filter1 targetID:2];
  307. // replace filter1 for target 2
  308. FSTWatchChange *change3 = [FSTExistenceFilterWatchChange changeWithFilter:filter2 targetID:2];
  309. FSTWatchChangeAggregator *aggregator =
  310. [self aggregatorWithTargets:@[ @1, @2 ]
  311. outstanding:_noPendingResponses
  312. changes:@[ change1, change2, change3 ]];
  313. FSTRemoteEvent *event = [aggregator remoteEvent];
  314. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  315. XCTAssertEqual(event.documentUpdates.count, 0);
  316. XCTAssertEqual(event.targetChanges.count, 0);
  317. XCTAssertEqual(aggregator.existenceFilters.count, 2);
  318. XCTAssertEqual(aggregator.existenceFilters[@1], filter1);
  319. XCTAssertEqual(aggregator.existenceFilters[@2], filter2);
  320. }
  321. - (void)testExistenceFilterMismatchResetsTarget {
  322. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  323. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  324. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  325. removedTargetIDs:@[]
  326. documentKey:doc1.key
  327. document:doc1];
  328. FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  329. removedTargetIDs:@[]
  330. documentKey:doc2.key
  331. document:doc2];
  332. FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  333. targetIDs:@[ @1 ]
  334. resumeToken:_resumeToken1];
  335. FSTWatchChangeAggregator *aggregator =
  336. [self aggregatorWithTargets:@[ @1 ]
  337. outstanding:_noPendingResponses
  338. changes:@[ change1, change2, change3 ]];
  339. FSTRemoteEvent *event = [aggregator remoteEvent];
  340. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  341. XCTAssertEqual(event.documentUpdates.count, 2);
  342. XCTAssertEqualObjects(event.documentUpdates[doc1.key], doc1);
  343. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  344. XCTAssertEqual(event.targetChanges.count, 1);
  345. FSTUpdateMapping *mapping1 =
  346. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1, doc2 ] removedDocuments:@[]];
  347. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  348. XCTAssertEqualObjects(event.targetChanges[@1].snapshotVersion, FSTTestVersion(3));
  349. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  350. XCTAssertEqualObjects(event.targetChanges[@1].resumeToken, _resumeToken1);
  351. [event handleExistenceFilterMismatchForTargetID:@1];
  352. // Mapping is reset
  353. XCTAssertEqualObjects(event.targetChanges[@1].mapping, [[FSTResetMapping alloc] init]);
  354. // Reset the resume snapshot
  355. XCTAssertEqualObjects(event.targetChanges[@1].snapshotVersion, FSTTestVersion(0));
  356. // Target needs to be set to not current
  357. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateMarkNotCurrent);
  358. XCTAssertEqual(event.targetChanges[@1].resumeToken.length, 0);
  359. }
  360. - (void)testDocumentUpdate {
  361. FSTDocument *doc1 = FSTTestDoc(@"docs/1", 1, @{ @"value" : @1 }, NO);
  362. FSTDeletedDocument *deletedDoc1 =
  363. [FSTDeletedDocument documentWithKey:doc1.key version:FSTTestVersion(3)];
  364. FSTDocument *doc2 = FSTTestDoc(@"docs/2", 2, @{ @"value" : @2 }, NO);
  365. FSTDocument *doc3 = FSTTestDoc(@"docs/3", 3, @{ @"value" : @3 }, NO);
  366. FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  367. removedTargetIDs:@[]
  368. documentKey:doc1.key
  369. document:doc1];
  370. FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ]
  371. removedTargetIDs:@[]
  372. documentKey:doc2.key
  373. document:doc2];
  374. FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargets:@[ @1 ]
  375. outstanding:_noPendingResponses
  376. changes:@[ change1, change2 ]];
  377. FSTRemoteEvent *event = [aggregator remoteEvent];
  378. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  379. XCTAssertEqual(event.documentUpdates.count, 2);
  380. XCTAssertEqualObjects(event.documentUpdates[doc1.key], doc1);
  381. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  382. // Update doc1
  383. [event addDocumentUpdate:deletedDoc1];
  384. [event addDocumentUpdate:doc3];
  385. XCTAssertEqualObjects(event.snapshotVersion, FSTTestVersion(3));
  386. XCTAssertEqual(event.documentUpdates.count, 3);
  387. // doc1 is replaced
  388. XCTAssertEqualObjects(event.documentUpdates[doc1.key], deletedDoc1);
  389. // doc2 is untouched
  390. XCTAssertEqualObjects(event.documentUpdates[doc2.key], doc2);
  391. // doc3 is new
  392. XCTAssertEqualObjects(event.documentUpdates[doc3.key], doc3);
  393. // Target is unchanged
  394. XCTAssertEqual(event.targetChanges.count, 1);
  395. FSTUpdateMapping *mapping1 =
  396. [FSTUpdateMapping mappingWithAddedDocuments:@[ doc1, doc2 ] removedDocuments:@[]];
  397. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  398. }
  399. - (void)testResumeTokensHandledPerTarget {
  400. NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding];
  401. FSTWatchChange *change1 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  402. targetIDs:@[ @1 ]
  403. resumeToken:_resumeToken1];
  404. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  405. targetIDs:@[ @2 ]
  406. resumeToken:resumeToken2];
  407. FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargets:@[ @1, @2 ]
  408. outstanding:_noPendingResponses
  409. changes:@[ change1, change2 ]];
  410. FSTRemoteEvent *event = [aggregator remoteEvent];
  411. XCTAssertEqual(event.targetChanges.count, 2);
  412. FSTUpdateMapping *mapping1 =
  413. [FSTUpdateMapping mappingWithAddedDocuments:@[] removedDocuments:@[]];
  414. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  415. XCTAssertEqualObjects(event.targetChanges[@1].snapshotVersion, FSTTestVersion(3));
  416. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  417. XCTAssertEqualObjects(event.targetChanges[@1].resumeToken, _resumeToken1);
  418. XCTAssertEqualObjects(event.targetChanges[@2].mapping, mapping1);
  419. XCTAssertEqualObjects(event.targetChanges[@2].snapshotVersion, FSTTestVersion(3));
  420. XCTAssertEqual(event.targetChanges[@2].currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  421. XCTAssertEqualObjects(event.targetChanges[@2].resumeToken, resumeToken2);
  422. }
  423. - (void)testLastResumeTokenWins {
  424. NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding];
  425. NSData *resumeToken3 = [@"resume3" dataUsingEncoding:NSUTF8StringEncoding];
  426. FSTWatchChange *change1 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
  427. targetIDs:@[ @1 ]
  428. resumeToken:_resumeToken1];
  429. FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset
  430. targetIDs:@[ @1 ]
  431. resumeToken:resumeToken2];
  432. FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset
  433. targetIDs:@[ @2 ]
  434. resumeToken:resumeToken3];
  435. FSTWatchChangeAggregator *aggregator =
  436. [self aggregatorWithTargets:@[ @1, @2 ]
  437. outstanding:_noPendingResponses
  438. changes:@[ change1, change2, change3 ]];
  439. FSTRemoteEvent *event = [aggregator remoteEvent];
  440. XCTAssertEqual(event.targetChanges.count, 2);
  441. FSTResetMapping *mapping1 = [FSTResetMapping mappingWithDocuments:@[]];
  442. XCTAssertEqualObjects(event.targetChanges[@1].mapping, mapping1);
  443. XCTAssertEqualObjects(event.targetChanges[@1].snapshotVersion, FSTTestVersion(3));
  444. XCTAssertEqual(event.targetChanges[@1].currentStatusUpdate, FSTCurrentStatusUpdateMarkCurrent);
  445. XCTAssertEqualObjects(event.targetChanges[@1].resumeToken, resumeToken2);
  446. XCTAssertEqualObjects(event.targetChanges[@2].mapping, mapping1);
  447. XCTAssertEqualObjects(event.targetChanges[@2].snapshotVersion, FSTTestVersion(3));
  448. XCTAssertEqual(event.targetChanges[@2].currentStatusUpdate, FSTCurrentStatusUpdateNone);
  449. XCTAssertEqualObjects(event.targetChanges[@2].resumeToken, resumeToken3);
  450. }
  451. @end
  452. NS_ASSUME_NONNULL_END