Skip to content

Add spec test support for target-scoped resume tokens #1498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ - (void)failStreamWithError:(NSError *)error {

#pragma mark - Helper methods.

- (void)writeWatchChange:(FSTWatchChange *)change snapshotVersion:(const SnapshotVersion &)snap {
- (void)writeWatchChange:(FSTWatchChange *)change snapshotVersion:(SnapshotVersion)snap {
if ([change isKindOfClass:[FSTWatchTargetChange class]]) {
FSTWatchTargetChange *targetChange = (FSTWatchTargetChange *)change;
if (targetChange.cause) {
Expand All @@ -152,6 +152,11 @@ - (void)writeWatchChange:(FSTWatchChange *)change snapshotVersion:(const Snapsho
[self.activeTargets removeObjectForKey:targetID];
}
}
if ([targetChange.targetIDs count] != 0) {
// If the list of target IDs is not empty, we reset the snapshot version to NONE as
// done in `FSTSerializerBeta.versionFromListenResponse:`.
snap = SnapshotVersion::None();
}
}
[self.delegate watchStreamDidChange:change snapshotVersion:snap];
}
Expand Down
63 changes: 36 additions & 27 deletions Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -194,25 +194,25 @@ - (void)doDelete:(NSString *)key {
[self.driver writeUserMutation:FSTTestDeleteMutation(key)];
}

- (void)doWatchAck:(NSArray<NSNumber *> *)ackedTargets snapshot:(NSNumber *)watchSnapshot {
- (void)doWatchAck:(NSArray<NSNumber *> *)ackedTargets {
FSTWatchTargetChange *change =
[FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded
targetIDs:ackedTargets
cause:nil];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
}

- (void)doWatchCurrent:(NSArray<id> *)currentSpec snapshot:(NSNumber *)watchSnapshot {
- (void)doWatchCurrent:(NSArray<id> *)currentSpec {
NSArray<NSNumber *> *currentTargets = currentSpec[0];
NSData *resumeToken = [currentSpec[1] dataUsingEncoding:NSUTF8StringEncoding];
FSTWatchTargetChange *change =
[FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent
targetIDs:currentTargets
resumeToken:resumeToken];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
}

- (void)doWatchRemove:(NSDictionary *)watchRemoveSpec snapshot:(NSNumber *)watchSnapshot {
- (void)doWatchRemove:(NSDictionary *)watchRemoveSpec {
NSError *error = nil;
NSDictionary *cause = watchRemoveSpec[@"cause"];
if (cause) {
Expand All @@ -226,19 +226,16 @@ - (void)doWatchRemove:(NSDictionary *)watchRemoveSpec snapshot:(NSNumber *)watch
[FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved
targetIDs:watchRemoveSpec[@"targetIds"]
cause:error];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
// Unlike web, the FSTMockDatastore detects a watch removal with cause and will remove active
// targets
}

- (void)doWatchEntity:(NSDictionary *)watchEntity snapshot:(NSNumber *_Nullable)watchSnapshot {
- (void)doWatchEntity:(NSDictionary *)watchEntity {
if (watchEntity[@"docs"]) {
HARD_ASSERT(!watchEntity[@"doc"], "Exactly one of |doc| or |docs| needs to be set.");
int count = 0;
NSArray *docs = watchEntity[@"docs"];
for (NSDictionary *doc in docs) {
count++;
bool isLast = (count == docs.count);
NSMutableDictionary *watchSpec = [NSMutableDictionary dictionary];
watchSpec[@"doc"] = doc;
if (watchEntity[@"targets"]) {
Expand All @@ -247,11 +244,7 @@ - (void)doWatchEntity:(NSDictionary *)watchEntity snapshot:(NSNumber *_Nullable)
if (watchEntity[@"removedTargets"]) {
watchSpec[@"removedTargets"] = watchEntity[@"removedTargets"];
}
NSNumber *_Nullable version = nil;
if (isLast) {
version = watchSnapshot;
}
[self doWatchEntity:watchSpec snapshot:version];
[self doWatchEntity:watchSpec];
}
} else if (watchEntity[@"doc"]) {
NSArray *docSpec = watchEntity[@"doc"];
Expand All @@ -270,21 +263,21 @@ - (void)doWatchEntity:(NSDictionary *)watchEntity snapshot:(NSNumber *_Nullable)
removedTargetIDs:watchEntity[@"removedTargets"]
documentKey:doc.key
document:doc];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
} else if (watchEntity[@"key"]) {
FSTDocumentKey *docKey = FSTTestDocKey(watchEntity[@"key"]);
FSTWatchChange *change =
[[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[]
removedTargetIDs:watchEntity[@"removedTargets"]
documentKey:docKey
document:nil];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
} else {
HARD_FAIL("Either key, doc or docs must be set.");
}
}

- (void)doWatchFilter:(NSArray *)watchFilter snapshot:(NSNumber *_Nullable)watchSnapshot {
- (void)doWatchFilter:(NSArray *)watchFilter {
NSArray<NSNumber *> *targets = watchFilter[0];
HARD_ASSERT(targets.count == 1, "ExistenceFilters currently support exactly one target only.");

Expand All @@ -294,15 +287,29 @@ - (void)doWatchFilter:(NSArray *)watchFilter snapshot:(NSNumber *_Nullable)watch
FSTExistenceFilter *filter = [FSTExistenceFilter filterWithCount:keyCount];
FSTExistenceFilterWatchChange *change =
[FSTExistenceFilterWatchChange changeWithFilter:filter targetID:targets[0].intValue];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
}

- (void)doWatchReset:(NSArray<NSNumber *> *)watchReset snapshot:(NSNumber *_Nullable)watchSnapshot {
- (void)doWatchReset:(NSArray<NSNumber *> *)watchReset {
FSTWatchTargetChange *change =
[FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset
targetIDs:watchReset
cause:nil];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
[self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()];
}

- (void)doWatchSnapshot:(NSDictionary *)watchSnapshot {
// The client will only respond to watchSnapshots if they are on a target change with an empty
// set of target IDs.
NSArray<NSNumber *> *targetIDs =
watchSnapshot[@"targetIds"] ? watchSnapshot[@"targetIds"] : [NSArray array];
NSData *resumeToken = [watchSnapshot[@"resumeToken"] dataUsingEncoding:NSUTF8StringEncoding];
FSTWatchTargetChange *change =
[FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange
targetIDs:targetIDs
resumeToken:resumeToken];
[self.driver receiveWatchChange:change
snapshotVersion:[self parseVersion:watchSnapshot[@"version"]]];
}

- (void)doWatchStreamClose:(NSDictionary *)closeSpec {
Expand Down Expand Up @@ -415,17 +422,19 @@ - (void)doStep:(NSDictionary *)step {
} else if (step[@"userDelete"]) {
[self doDelete:step[@"userDelete"]];
} else if (step[@"watchAck"]) {
[self doWatchAck:step[@"watchAck"] snapshot:step[@"watchSnapshot"]];
[self doWatchAck:step[@"watchAck"]];
} else if (step[@"watchCurrent"]) {
[self doWatchCurrent:step[@"watchCurrent"] snapshot:step[@"watchSnapshot"]];
[self doWatchCurrent:step[@"watchCurrent"]];
} else if (step[@"watchRemove"]) {
[self doWatchRemove:step[@"watchRemove"] snapshot:step[@"watchSnapshot"]];
[self doWatchRemove:step[@"watchRemove"]];
} else if (step[@"watchEntity"]) {
[self doWatchEntity:step[@"watchEntity"] snapshot:step[@"watchSnapshot"]];
[self doWatchEntity:step[@"watchEntity"]];
} else if (step[@"watchFilter"]) {
[self doWatchFilter:step[@"watchFilter"] snapshot:step[@"watchSnapshot"]];
[self doWatchFilter:step[@"watchFilter"]];
} else if (step[@"watchReset"]) {
[self doWatchReset:step[@"watchReset"] snapshot:step[@"watchSnapshot"]];
[self doWatchReset:step[@"watchReset"]];
} else if (step[@"watchSnapshot"]) {
[self doWatchSnapshot:step[@"watchSnapshot"]];
} else if (step[@"watchStreamClose"]) {
[self doWatchStreamClose:step[@"watchStreamClose"]];
} else if (step[@"watchProto"]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,12 @@
2
],
"resume-token-1001"
],
"watchSnapshot": 1001,
]
},
{
"watchSnapshot": {
"version": 1001
},
"expect": [
{
"query": {
Expand Down
Loading