Skip to content

Commit 9d230de

Browse files
author
Brian Chen
authored
Adding onSnapshotsInSync (not public) (#3850)
1 parent bf9cb5e commit 9d230de

20 files changed

+1242
-27
lines changed

Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,42 @@ - (void)testAddingToACollectionYieldsTheCorrectDocumentReference {
531531
[self awaitExpectations];
532532
}
533533

534+
- (void)testSnapshotsInSyncListenerFiresAfterListenersInSync {
535+
FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"];
536+
FIRDocumentReference *ref = [coll addDocumentWithData:@{@"foo" : @1}];
537+
NSMutableArray<NSString *> *events = [NSMutableArray array];
538+
539+
XCTestExpectation *gotInitialSnapshot = [self expectationWithDescription:@"gotInitialSnapshot"];
540+
__block bool setupComplete = false;
541+
[ref addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
542+
XCTAssertNil(error);
543+
[events addObject:@"doc"];
544+
// Wait for the initial event from the backend so that we know we'll get exactly one snapshot
545+
// event for our local write below.
546+
if (!setupComplete) {
547+
setupComplete = true;
548+
[gotInitialSnapshot fulfill];
549+
}
550+
}];
551+
552+
[self awaitExpectations];
553+
[events removeAllObjects];
554+
555+
XCTestExpectation *done = [self expectationWithDescription:@"SnapshotsInSyncListenerDone"];
556+
[ref.firestore addSnapshotsInSyncListener:^() {
557+
[events addObject:@"snapshots-in-sync"];
558+
if ([events count] == 3) {
559+
// We should have an initial snapshots-in-sync event, then a snapshot event
560+
// for set(), then another event to indicate we're in sync again.
561+
NSArray<NSString *> *expected = @[ @"snapshots-in-sync", @"doc", @"snapshots-in-sync" ];
562+
XCTAssertEqualObjects(events, expected);
563+
[done fulfill];
564+
}
565+
}];
566+
567+
[self writeDocumentRef:ref data:@{@"foo" : @3}];
568+
}
569+
534570
- (void)testListenCanBeCalledMultipleTimes {
535571
FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"];
536572
FIRDocumentReference *doc = [coll documentWithAutoID];

Firestore/Example/Tests/SpecTests/FSTSpecTests.mm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ - (void)doDelete:(NSString *)key {
278278
[self.driver writeUserMutation:FSTTestDeleteMutation(key)];
279279
}
280280

281+
- (void)doAddSnapshotsInSyncListener {
282+
[self.driver addSnapshotsInSyncListener];
283+
}
284+
285+
- (void)doRemoveSnapshotsInSyncListener {
286+
[self.driver removeSnapshotsInSyncListener];
287+
}
288+
281289
- (void)doWatchAck:(NSArray<NSNumber *> *)ackedTargets {
282290
WatchTargetChange change{WatchTargetChangeState::Added, ConvertTargetsArray(ackedTargets)};
283291
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
@@ -479,6 +487,10 @@ - (void)doStep:(NSDictionary *)step {
479487
[self doPatch:step[@"userPatch"]];
480488
} else if (step[@"userDelete"]) {
481489
[self doDelete:step[@"userDelete"]];
490+
} else if (step[@"addSnapshotsInSyncListener"]) {
491+
[self doAddSnapshotsInSyncListener];
492+
} else if (step[@"removeSnapshotsInSyncListener"]) {
493+
[self doRemoveSnapshotsInSyncListener];
482494
} else if (step[@"drainQueue"]) {
483495
[self doDrainQueue];
484496
} else if (step[@"watchAck"]) {
@@ -651,6 +663,11 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected {
651663
[self validateActiveTargets];
652664
}
653665

666+
- (void)validateSnapshotsInSyncEvents:(int)expectedSnapshotInSyncEvents {
667+
XCTAssertEqual(expectedSnapshotInSyncEvents, [self.driver snapshotsInSyncEvents]);
668+
[self.driver resetSnapshotsInSyncEvents];
669+
}
670+
654671
- (void)validateUserCallbacks:(nullable NSDictionary *)expected {
655672
NSDictionary *expectedCallbacks = expected[@"userCallbacks"];
656673
NSArray<NSString *> *actualAcknowledgedDocs =
@@ -728,6 +745,8 @@ - (void)runSpecTestSteps:(NSArray *)steps config:(NSDictionary *)config {
728745
[self doStep:step];
729746
[self validateStepExpectations:step[@"expect"]];
730747
[self validateStateExpectations:step[@"stateExpect"]];
748+
int expectedSnapshotsInSyncEvents = [step[@"expectedSnapshotsInSyncEvents"] intValue];
749+
[self validateSnapshotsInSyncEvents:expectedSnapshotsInSyncEvents];
731750
}
732751
[self.driver validateUsage];
733752
} @finally {

Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <vector>
2323

2424
#include "Firestore/core/src/firebase/firestore/auth/user.h"
25+
#include "Firestore/core/src/firebase/firestore/core/event_listener.h"
2526
#include "Firestore/core/src/firebase/firestore/core/query.h"
2627
#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h"
2728
#include "Firestore/core/src/firebase/firestore/local/query_data.h"
@@ -32,6 +33,7 @@
3233
#include "Firestore/core/src/firebase/firestore/model/types.h"
3334
#include "Firestore/core/src/firebase/firestore/remote/watch_change.h"
3435
#include "Firestore/core/src/firebase/firestore/util/async_queue.h"
36+
#include "Firestore/core/src/firebase/firestore/util/empty.h"
3537

3638
namespace firebase {
3739
namespace firestore {
@@ -311,6 +313,26 @@ typedef std::unordered_map<firebase::firestore::auth::User,
311313
/** The current user for the FSTSyncEngine; determines which mutation queue is active. */
312314
@property(nonatomic, assign, readonly) const firebase::firestore::auth::User &currentUser;
313315

316+
/**
317+
* The number of snapshots-in-sync events that have been received.
318+
*/
319+
@property(nonatomic, readonly) int snapshotsInSyncEvents;
320+
321+
- (void)incrementSnapshotsInSyncEvents;
322+
323+
- (void)resetSnapshotsInSyncEvents;
324+
325+
/**
326+
* Adds a snpahots-in-sync listener to the event manager and keeps track of it so that it
327+
* can be easily removed later.
328+
*/
329+
- (void)addSnapshotsInSyncListener;
330+
331+
/**
332+
* Removes the snapshots-in-sync listener from the event manager.
333+
*/
334+
- (void)removeSnapshotsInSyncListener;
335+
314336
/** The set of active targets as observed on the watch stream. */
315337
- (const std::unordered_map<firebase::firestore::model::TargetId, local::QueryData> &)activeTargets;
316338

Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
using firebase::firestore::auth::HashUser;
5757
using firebase::firestore::auth::User;
5858
using firebase::firestore::core::DatabaseInfo;
59+
using firebase::firestore::core::EventListener;
5960
using firebase::firestore::core::EventManager;
6061
using firebase::firestore::core::ListenOptions;
6162
using firebase::firestore::core::Query;
@@ -78,6 +79,7 @@
7879
using firebase::firestore::remote::WatchChange;
7980
using firebase::firestore::util::AsyncQueue;
8081
using firebase::firestore::util::DelayedConstructor;
82+
using firebase::firestore::util::Empty;
8183
using firebase::firestore::util::ExecutorLibdispatch;
8284
using firebase::firestore::util::MakeNSError;
8385
using firebase::firestore::util::MakeNSString;
@@ -170,7 +172,10 @@ @implementation FSTSyncEngineTestDriver {
170172
DatabaseInfo _databaseInfo;
171173
User _currentUser;
172174

175+
std::vector<std::shared_ptr<EventListener<Empty>>> _snapshotsInSyncListeners;
173176
std::shared_ptr<MockDatastore> _datastore;
177+
178+
int _snapshotsInSyncEvents;
174179
}
175180

176181
- (instancetype)initWithPersistence:(std::unique_ptr<Persistence>)persistence {
@@ -246,6 +251,34 @@ - (void)drainQueue {
246251
return _currentUser;
247252
}
248253

254+
- (void)incrementSnapshotsInSyncEvents {
255+
_snapshotsInSyncEvents += 1;
256+
}
257+
258+
- (void)resetSnapshotsInSyncEvents {
259+
_snapshotsInSyncEvents = 0;
260+
}
261+
262+
- (void)addSnapshotsInSyncListener {
263+
std::shared_ptr<EventListener<Empty>> eventListener = EventListener<Empty>::Create(
264+
[self](const StatusOr<Empty> &) { [self incrementSnapshotsInSyncEvents]; });
265+
_snapshotsInSyncListeners.push_back(eventListener);
266+
_eventManager->AddSnapshotsInSyncListener(eventListener);
267+
}
268+
269+
- (void)removeSnapshotsInSyncListener {
270+
if (_snapshotsInSyncListeners.empty()) {
271+
HARD_FAIL("There must be a listener to unlisten to");
272+
} else {
273+
_eventManager->RemoveSnapshotsInSyncListener(_snapshotsInSyncListeners.back());
274+
_snapshotsInSyncListeners.pop_back();
275+
}
276+
}
277+
278+
- (int)snapshotsInSyncEvents {
279+
return _snapshotsInSyncEvents;
280+
}
281+
249282
- (void)start {
250283
_workerQueue->EnqueueBlocking([&] {
251284
_localStore->Start();

0 commit comments

Comments
 (0)