diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 9eba0f3f07b..e51a89906c7 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -32,21 +32,19 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
throw new NullPointerException("Bitmap cannot be null.");
}
if (padding < 0 || padding >= 8) {
- throw new IllegalArgumentException("Invalid padding: " + padding);
+ throw new BloomFilterException("Invalid padding: " + padding);
}
if (hashCount < 0) {
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ throw new BloomFilterException("Invalid hash count: " + hashCount);
}
if (bitmap.length > 0 && hashCount == 0) {
// Only empty bloom filter can have 0 hash count.
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ throw new BloomFilterException("Invalid hash count: " + hashCount);
}
- if (bitmap.length == 0) {
+ if (bitmap.length == 0 && padding != 0) {
// Empty bloom filter should have 0 padding.
- if (padding != 0) {
- throw new IllegalArgumentException(
- "Expected padding of 0 when bitmap length is 0, but got " + padding);
- }
+ throw new BloomFilterException(
+ "Expected padding of 0 when bitmap length is 0, but got " + padding);
}
this.bitmap = bitmap;
@@ -133,8 +131,8 @@ private int getBitIndex(long hash1, long hash2, int hashIndex) {
/**
* Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
*
- *
The implementation is taken from Guava,
+ *
The implementation is taken from Guava,
* simplified to our needs.
*
*
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
new file mode 100644
index 00000000000..429b501ed47
--- /dev/null
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
@@ -0,0 +1,23 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.firestore.remote;
+
+import androidx.annotation.NonNull;
+
+public class BloomFilterException extends RuntimeException {
+ public BloomFilterException(@NonNull String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
index 7be1ca4744a..06d2d5f924e 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
@@ -14,20 +14,34 @@
package com.google.firebase.firestore.remote;
+import androidx.annotation.Nullable;
+import com.google.firestore.v1.BloomFilter;
+
/** Simplest form of existence filter */
public final class ExistenceFilter {
private final int count;
+ private BloomFilter unchangedNames;
public ExistenceFilter(int count) {
this.count = count;
}
+ public ExistenceFilter(int count, @Nullable BloomFilter unchangedNames) {
+ this.count = count;
+ this.unchangedNames = unchangedNames;
+ }
+
public int getCount() {
return count;
}
+ @Nullable
+ public BloomFilter getUnchangedNames() {
+ return unchangedNames;
+ }
+
@Override
public String toString() {
- return "ExistenceFilter{count=" + count + '}';
+ return "ExistenceFilter{count=" + count + ", unchangedNames=" + unchangedNames + '}';
}
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
index 7f1f7781045..655842a73af 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
@@ -945,8 +945,8 @@ public WatchChange decodeWatchChange(ListenResponse protoChange) {
break;
case FILTER:
com.google.firestore.v1.ExistenceFilter protoFilter = protoChange.getFilter();
- // TODO: implement existence filter parsing (see b/33076578)
- ExistenceFilter filter = new ExistenceFilter(protoFilter.getCount());
+ ExistenceFilter filter =
+ new ExistenceFilter(protoFilter.getCount(), protoFilter.getUnchangedNames());
int targetId = protoFilter.getTargetId();
watchChange = new ExistenceFilterWatchChange(targetId, filter);
break;
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
index 965ceee35da..1f5ad514b46 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
@@ -28,6 +28,7 @@
import com.google.firebase.firestore.local.LocalStore;
import com.google.firebase.firestore.local.QueryPurpose;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.SnapshotVersion;
import com.google.firebase.firestore.model.mutation.MutationBatch;
@@ -758,6 +759,11 @@ public TargetData getTargetDataForTarget(int targetId) {
return this.listenTargets.get(targetId);
}
+ @Override
+ public DatabaseId getDatabaseId() {
+ return this.datastore.getDatabaseInfo().getDatabaseId();
+ }
+
public Task runCountQuery(Query query) {
if (canUseNetwork()) {
return datastore.runCountQuery(query);
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index 1086af504db..435cbca9e24 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -23,12 +23,14 @@
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.local.QueryPurpose;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.MutableDocument;
import com.google.firebase.firestore.model.SnapshotVersion;
import com.google.firebase.firestore.remote.WatchChange.DocumentChange;
import com.google.firebase.firestore.remote.WatchChange.ExistenceFilterWatchChange;
import com.google.firebase.firestore.remote.WatchChange.WatchTargetChange;
+import com.google.firebase.firestore.util.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -56,6 +58,9 @@ public interface TargetMetadataProvider {
*/
@Nullable
TargetData getTargetDataForTarget(int targetId);
+
+ /** Returns the database ID of the Firestore instance. */
+ DatabaseId getDatabaseId();
}
private final TargetMetadataProvider targetMetadataProvider;
@@ -75,6 +80,9 @@ public interface TargetMetadataProvider {
*/
private Set pendingTargetResets = new HashSet<>();
+ /** The log tag to use for this class. */
+ private static final String LOG_TAG = "WatchChangeAggregator";
+
public WatchChangeAggregator(TargetMetadataProvider targetMetadataProvider) {
this.targetMetadataProvider = targetMetadataProvider;
}
@@ -196,17 +204,78 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) {
expectedCount == 1, "Single document existence filter with count: %d", expectedCount);
}
} else {
- long currentSize = getCurrentDocumentCountForTarget(targetId);
+ int currentSize = getCurrentDocumentCountForTarget(targetId);
if (currentSize != expectedCount) {
- // Existence filter mismatch: We reset the mapping and raise a new snapshot with
- // `isFromCache:true`.
- resetTarget(targetId);
- pendingTargetResets.add(targetId);
+
+ // Apply bloom filter to identify and mark removed documents.
+ boolean bloomFilterApplied = this.applyBloomFilter(watchChange, currentSize);
+
+ if (!bloomFilterApplied) {
+ // If bloom filter application fails, we reset the mapping and
+ // trigger re-run of the query.
+ resetTarget(targetId);
+ pendingTargetResets.add(targetId);
+ }
}
}
}
}
+ /** Returns whether a bloom filter removed the deleted documents successfully. */
+ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int currentCount) {
+ int expectedCount = watchChange.getExistenceFilter().getCount();
+ com.google.firestore.v1.BloomFilter unchangedNames =
+ watchChange.getExistenceFilter().getUnchangedNames();
+
+ if (unchangedNames == null || !unchangedNames.hasBits()) {
+ return false;
+ }
+
+ byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray();
+ BloomFilter bloomFilter;
+
+ try {
+ bloomFilter =
+ new BloomFilter(
+ bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount());
+ } catch (BloomFilterException e) {
+ Logger.warn(
+ LOG_TAG,
+ "Decoding the base64 bloom filter in existence filter failed ("
+ + e.getMessage()
+ + "); ignoring the bloom filter and falling back to full re-query.");
+ return false;
+ }
+
+ int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, watchChange.getTargetId());
+
+ return expectedCount == (currentCount - removedDocumentCount);
+ }
+
+ /**
+ * Filter out removed documents based on bloom filter membership result and return number of
+ * documents removed.
+ */
+ private int filterRemovedDocuments(BloomFilter bloomFilter, int targetId) {
+ ImmutableSortedSet existingKeys =
+ targetMetadataProvider.getRemoteKeysForTarget(targetId);
+ int removalCount = 0;
+ for (DocumentKey key : existingKeys) {
+ DatabaseId databaseId = targetMetadataProvider.getDatabaseId();
+ String documentPath =
+ "projects/"
+ + databaseId.getProjectId()
+ + "/databases/"
+ + databaseId.getDatabaseId()
+ + "/documents/"
+ + key.getPath().canonicalString();
+ if (!bloomFilter.mightContain(documentPath)) {
+ this.removeDocumentFromTarget(targetId, key, /*updatedDocument=*/ null);
+ removalCount++;
+ }
+ }
+ return removalCount;
+ }
/**
* Converts the currently accumulated state into a remote event at the provided snapshot version.
* Resets the accumulated changes before returning.
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 0e851a0fc4f..c2ba39c4d7f 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -73,55 +73,53 @@ public void constructorShouldThrowNPEOnNullBitmap() {
}
@Test
- public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() {
- IllegalArgumentException exception =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
+ public void constructorShouldThrowBFEOnEmptyBloomFilterWithNonZeroPadding() {
+ BloomFilterException exception =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 1, 0));
assertThat(exception)
.hasMessageThat()
.contains("Expected padding of 0 when bitmap length is 0, but got 1");
}
@Test
- public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() {
- IllegalArgumentException zeroHashCountException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, 0));
+ public void constructorShouldThrowBFEOnNonEmptyBloomFilterWithZeroHashCount() {
+ BloomFilterException zeroHashCountException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, 0));
assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0");
}
@Test
- public void constructorShouldThrowIAEOnNegativePadding() {
+ public void constructorShouldThrowBFEOnNegativePadding() {
{
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0));
+ BloomFilterException emptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], -1, 0));
assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
}
{
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(
- IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
+ BloomFilterException nonEmptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
}
}
@Test
- public void constructorShouldThrowIAEOnNegativeHashCount() {
+ public void constructorShouldThrowBFEOnNegativeHashCount() {
{
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
+ BloomFilterException emptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 0, -1));
assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
}
{
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(
- IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
+ BloomFilterException nonEmptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
}
}
@Test
- public void constructorShouldThrowIAEIfPaddingIsTooLarge() {
- IllegalArgumentException exception =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
+ public void constructorShouldThrowBFEIfPaddingIsTooLarge() {
+ BloomFilterException exception =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
assertThat(exception).hasMessageThat().contains("Invalid padding: 8");
}
@@ -179,7 +177,7 @@ public void bloomFilterToString() {
private static void runGoldenTest(String testFile) throws Exception {
String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result");
if (resultFile.equals(testFile)) {
- throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile);
+ throw new BloomFilterException("Cannot find corresponding result file for " + testFile);
}
JSONObject testJson = readJsonFile(testFile);
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 7be9479da3b..42f570711b1 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.util.Base64;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.gms.tasks.Task;
@@ -81,6 +82,8 @@
import com.google.firebase.firestore.util.Assert;
import com.google.firebase.firestore.util.AsyncQueue;
import com.google.firebase.firestore.util.AsyncQueue.TimerId;
+import com.google.firestore.v1.BitSequence;
+import com.google.firestore.v1.BloomFilter;
import com.google.protobuf.ByteString;
import io.grpc.Status;
import java.io.BufferedReader;
@@ -468,6 +471,24 @@ private List parseIntList(@Nullable JSONArray arr) throws JSONException
return result;
}
+ /** Deeply parses a JSONObject into a bloom filter proto type. */
+ private BloomFilter parseBloomFilter(JSONObject obj) throws JSONException {
+ BitSequence.Builder bitSequence = BitSequence.newBuilder();
+ JSONObject bits = obj.getJSONObject("bits");
+ if (bits.has("padding")) {
+ bitSequence.setPadding(bits.getInt("padding"));
+ }
+ bitSequence.setBitmap(
+ ByteString.copyFrom(Base64.decode(bits.getString("bitmap"), Base64.DEFAULT)));
+
+ BloomFilter.Builder bloomFilter = BloomFilter.newBuilder();
+ bloomFilter.setBits(bitSequence);
+ if (obj.has("hashCount")) {
+ bloomFilter.setHashCount(obj.getInt("hashCount"));
+ }
+ return bloomFilter.build();
+ }
+
//
// Methods for doing the steps of the spec test.
//
@@ -654,15 +675,19 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception {
}
}
- private void doWatchFilter(JSONArray watchFilter) throws Exception {
- List targets = parseIntList(watchFilter.getJSONArray(0));
+ private void doWatchFilter(JSONObject watchFilter) throws Exception {
+ List targets = parseIntList(watchFilter.getJSONArray("targetIds"));
+
Assert.hardAssert(
targets.size() == 1, "ExistenceFilters currently support exactly one target only.");
- int keyCount = watchFilter.length() == 0 ? 0 : watchFilter.length() - 1;
+ int keyCount = watchFilter.getJSONArray("keys").length();
+ BloomFilter bloomFilterProto =
+ watchFilter.has("bloomFilter")
+ ? parseBloomFilter(watchFilter.getJSONObject("bloomFilter"))
+ : null;
- // TODO: extend this with different existence filters over time.
- ExistenceFilter filter = new ExistenceFilter(keyCount);
+ ExistenceFilter filter = new ExistenceFilter(keyCount, bloomFilterProto);
ExistenceFilterWatchChange change = new ExistenceFilterWatchChange(targets.get(0), filter);
writeWatchChange(change, SnapshotVersion.NONE);
}
@@ -713,7 +738,7 @@ private void doWriteAck(JSONObject writeAckSpec) throws Exception {
validateNextWriteSent(write.first);
MutationResult mutationResult =
- new MutationResult(version(version), /*transformResults=*/ Collections.emptyList());
+ new MutationResult(version(version), /* transformResults= */ Collections.emptyList());
queue.runSync(() -> datastore.ackWrite(version(version), singletonList(mutationResult)));
}
@@ -830,7 +855,7 @@ private void doStep(JSONObject step) throws Exception {
} else if (step.has("watchEntity")) {
doWatchEntity(step.getJSONObject("watchEntity"));
} else if (step.has("watchFilter")) {
- doWatchFilter(step.getJSONArray("watchFilter"));
+ doWatchFilter(step.getJSONObject("watchFilter"));
} else if (step.has("watchReset")) {
doWatchReset(step.getJSONArray("watchReset"));
} else if (step.has("watchSnapshot")) {
@@ -899,7 +924,17 @@ private void assertEventMatches(JSONObject expected, QueryEvent actual) throws J
for (int i = 0; metadata != null && i < metadata.length(); ++i) {
expectedChanges.add(parseChange(metadata.getJSONObject(i), Type.METADATA));
}
- assertEquals(expectedChanges, actual.view.getChanges());
+
+ List sortedActualChanges =
+ actual.view.getChanges().stream()
+ .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()))
+ .collect(Collectors.toList());
+ List sortedExpectedChanges =
+ expectedChanges.stream()
+ .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()))
+ .collect(Collectors.toList());
+
+ assertEquals(sortedExpectedChanges, sortedActualChanges);
boolean expectedHasPendingWrites = expected.optBoolean("hasPendingWrites", false);
boolean expectedFromCache = expected.optBoolean("fromCache", false);
diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
index 3083b762224..a66a08bce17 100644
--- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
@@ -1,9 +1,8 @@
{
- "Existence filter clears resume token": {
+ "Bloom filter can process special characters in document name": {
"describeName": "Existence Filters:",
- "itName": "Existence filter clears resume token",
+ "itName": "Bloom filter can process special characters in document name",
"tags": [
- "durable-persistence"
],
"config": {
"numClients": 1,
@@ -47,7 +46,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/ÀÒ∑",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -58,13 +57,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/À∑Ò",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -92,7 +91,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/ÀÒ∑",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -103,13 +102,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/À∑Ò",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -128,12 +127,21 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "IIAAIIAIIAAIIAIIAA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/ÀÒ∑"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -154,19 +162,51 @@
"path": "collection"
}
}
- ]
- },
- {
- "restart": true,
+ ],
"expectedState": {
"activeLimboDocs": [
+ "collection/À∑Ò"
],
"activeTargets": {
- },
- "enqueuedLimboDocs": [
- ]
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/À∑Ò"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
- },
+ }
+ ]
+ },
+ "Bloom filter fills in default values for undefined padding and hashCount": {
+ "describeName": "Existence Filters:",
+ "itName": "Bloom filter fills in default values for undefined padding and hashCount",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
"userListen": {
"query": {
@@ -178,11 +218,78 @@
},
"targetId": 2
},
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -193,7 +300,7 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -204,6 +311,42 @@
"version": 1000
}
],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA=="
+ }
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
"errorCode": 0,
"fromCache": true,
"hasPendingWrites": false,
@@ -235,9 +378,9 @@
}
]
},
- "Existence filter handled at global snapshot": {
+ "Bloom filter is handled at global snapshot": {
"describeName": "Existence Filters:",
- "itName": "Existence filter handled at global snapshot",
+ "itName": "Bloom filter is handled at global snapshot",
"tags": [
],
"config": {
@@ -282,7 +425,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -291,6 +434,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
}
],
"targets": [
@@ -316,7 +470,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -325,6 +479,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
}
],
"errorCode": 0,
@@ -341,19 +506,27 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
],
- "collection/1",
- "collection/2"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchEntity": {
"docs": [
{
- "key": "collection/3",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -379,7 +552,7 @@
{
"added": [
{
- "key": "collection/3",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -403,7 +576,22 @@
}
],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
@@ -418,12 +606,45 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Bloom filter limbo resolution is denied": {
+ "describeName": "Existence Filters:",
+ "itName": "Bloom filter limbo resolution is denied",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -435,7 +656,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -446,26 +667,15 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
- },
- {
- "key": "collection/3",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 3
- },
- "version": 3000
+ "version": 1000
}
],
"targets": [
@@ -478,135 +688,39 @@
[
2
],
- "resume-token-3000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 3000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/2",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
- }
- ],
- "errorCode": 0,
- "fromCache": false,
- "hasPendingWrites": false,
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- }
- ]
- }
- ]
- },
- "Existence filter ignored with pending target": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter ignored with pending target",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": false
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
- },
- "expectedState": {
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
- }
- }
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchEntity": {
- "docs": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
+ "version": 1000
},
- "version": 2000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-1000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 1000
- },
- "expectedSnapshotEvents": [
- {
- "added": [
{
- "key": "collection/1",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
}
],
"errorCode": 0,
@@ -623,47 +737,30 @@
]
},
{
- "userUnlisten": [
- 2,
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "expectedState": {
- "activeTargets": {
- }
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
}
},
{
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
- "added": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 2000
- }
- ],
"errorCode": 0,
"fromCache": true,
"hasPendingWrites": false,
@@ -677,7 +774,22 @@
}
],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
@@ -688,43 +800,19 @@
"path": "collection"
}
],
- "resumeToken": "resume-token-1000"
+ "resumeToken": ""
}
}
}
},
- {
- "watchFilter": [
- [
- 2
- ]
- ]
- },
{
"watchRemove": {
+ "cause": {
+ "code": 7
+ },
"targetIds": [
- 2
+ 1
]
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
},
"expectedSnapshotEvents": [
{
@@ -737,15 +825,46 @@
"orderBys": [
],
"path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
}
}
- ]
+ }
}
]
},
- "Existence filter limbo resolution is denied": {
+ "Bloom filter with large size works as expected": {
"describeName": "Existence Filters:",
- "itName": "Existence filter limbo resolution is denied",
+ "itName": "Bloom filter with large size works as expected",
"tags": [
],
"config": {
@@ -790,7 +909,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/doc0",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -801,27 +920,4388 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/doc1",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
+ },
+ {
+ "key": "collection/doc2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc4",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc5",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc6",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc7",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc8",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc9",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc10",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc11",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc12",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc13",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc14",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc15",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc16",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc17",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc18",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc19",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc20",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc21",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc22",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc23",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc24",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc25",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc26",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc27",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc28",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc29",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc30",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc31",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc32",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc33",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc34",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc35",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc36",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc37",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc38",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc39",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc40",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc41",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc42",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc43",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc44",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc45",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc46",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc47",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc48",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc49",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc50",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc51",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc52",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc53",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc54",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc55",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc56",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc57",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc58",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc59",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc60",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc61",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc62",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc63",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc64",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc65",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc66",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc67",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc68",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc69",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc70",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc71",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc72",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc73",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc74",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc75",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc76",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc77",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc78",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc79",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc80",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc81",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc82",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc83",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc84",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc85",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc86",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc87",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc88",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc89",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc90",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc91",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc92",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc93",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc94",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc95",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc96",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc97",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc98",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc99",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/doc0",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc4",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc5",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc6",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc7",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc8",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc9",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc10",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc11",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc12",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc13",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc14",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc15",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc16",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc17",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc18",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc19",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc20",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc21",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc22",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc23",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc24",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc25",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc26",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc27",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc28",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc29",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc30",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc31",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc32",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc33",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc34",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc35",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc36",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc37",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc38",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc39",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc40",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc41",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc42",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc43",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc44",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc45",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc46",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc47",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc48",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc49",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc50",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc51",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc52",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc53",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc54",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc55",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc56",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc57",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc58",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc59",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc60",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc61",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc62",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc63",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc64",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc65",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc66",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc67",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc68",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc69",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc70",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc71",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc72",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc73",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc74",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc75",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc76",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc77",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc78",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc79",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc80",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc81",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc82",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc83",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc84",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc85",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc86",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc87",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc88",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc89",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc90",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc91",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc92",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc93",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc94",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc95",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc96",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc97",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc98",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc99",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "+9oMQXUptl274DOaET8sfebQ4aCu0Roiddbja3z8TfadKuyPV/9XWV5Ksv+vywRXTfZSNIn8z+xk/oq1+cbOPepeNvbXVOF6H92fCOAz/KiS3Mcw338R9tXE3Y7QB1L2kbvbvVHW3Kn/k3Vx8k9Oa19eWX6RYE97Q+oCcVU=",
+ "padding": 0
+ },
+ "hashCount": 16
+ },
+ "keys": [
+ "collection/doc0",
+ "collection/doc1",
+ "collection/doc2",
+ "collection/doc3",
+ "collection/doc4",
+ "collection/doc5",
+ "collection/doc6",
+ "collection/doc7",
+ "collection/doc8",
+ "collection/doc9",
+ "collection/doc10",
+ "collection/doc11",
+ "collection/doc12",
+ "collection/doc13",
+ "collection/doc14",
+ "collection/doc15",
+ "collection/doc16",
+ "collection/doc17",
+ "collection/doc18",
+ "collection/doc19",
+ "collection/doc20",
+ "collection/doc21",
+ "collection/doc22",
+ "collection/doc23",
+ "collection/doc24",
+ "collection/doc25",
+ "collection/doc26",
+ "collection/doc27",
+ "collection/doc28",
+ "collection/doc29",
+ "collection/doc30",
+ "collection/doc31",
+ "collection/doc32",
+ "collection/doc33",
+ "collection/doc34",
+ "collection/doc35",
+ "collection/doc36",
+ "collection/doc37",
+ "collection/doc38",
+ "collection/doc39",
+ "collection/doc40",
+ "collection/doc41",
+ "collection/doc42",
+ "collection/doc43",
+ "collection/doc44",
+ "collection/doc45",
+ "collection/doc46",
+ "collection/doc47",
+ "collection/doc48",
+ "collection/doc49"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/doc50",
+ "collection/doc51",
+ "collection/doc52",
+ "collection/doc53",
+ "collection/doc54",
+ "collection/doc55",
+ "collection/doc56",
+ "collection/doc57",
+ "collection/doc58",
+ "collection/doc59",
+ "collection/doc60",
+ "collection/doc61",
+ "collection/doc62",
+ "collection/doc63",
+ "collection/doc64",
+ "collection/doc65",
+ "collection/doc66",
+ "collection/doc67",
+ "collection/doc68",
+ "collection/doc69",
+ "collection/doc70",
+ "collection/doc71",
+ "collection/doc72",
+ "collection/doc73",
+ "collection/doc74",
+ "collection/doc75",
+ "collection/doc76",
+ "collection/doc77",
+ "collection/doc78",
+ "collection/doc79",
+ "collection/doc80",
+ "collection/doc81",
+ "collection/doc82",
+ "collection/doc83",
+ "collection/doc84",
+ "collection/doc85",
+ "collection/doc86",
+ "collection/doc87",
+ "collection/doc88",
+ "collection/doc89",
+ "collection/doc90",
+ "collection/doc91",
+ "collection/doc92",
+ "collection/doc93",
+ "collection/doc94",
+ "collection/doc95",
+ "collection/doc96",
+ "collection/doc97",
+ "collection/doc98",
+ "collection/doc99"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc50"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "11": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc55"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "13": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc56"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "15": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc57"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "17": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc58"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "19": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc59"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "21": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc60"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "23": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc61"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "25": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc62"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "27": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc63"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "29": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc64"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc51"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "31": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc65"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "33": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc66"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "35": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc67"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "37": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc68"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "39": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc69"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "41": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc70"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "43": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc71"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "45": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc72"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "47": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc73"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "49": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc74"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "5": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc52"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "51": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc75"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "53": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc76"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "55": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc77"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "57": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc78"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "59": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc79"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "61": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc80"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "63": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc81"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "65": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc82"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "67": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc83"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "69": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc84"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "7": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc53"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "71": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc85"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "73": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc86"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "75": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc87"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "77": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc88"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "79": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc89"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "81": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc90"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "83": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc91"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "85": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc92"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "87": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc93"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "89": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc94"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "9": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc54"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "91": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc95"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "93": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc96"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "95": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc97"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "97": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc98"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "99": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc99"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter clears resume token": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter clears resume token",
+ "tags": [
+ "durable-persistence"
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "restart": true,
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ },
+ "enqueuedLimboDocs": [
+ ]
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter handled at global snapshot": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter handled at global snapshot",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1",
+ "collection/2"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ },
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-3000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 3000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter ignored with pending target": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter ignored with pending target",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": false
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "userUnlisten": [
+ 2,
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ }
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ }
+ }
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter limbo resolution is denied": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter limbo resolution is denied",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "cause": {
+ "code": 7
+ },
+ "targetIds": [
+ 1
+ ]
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter match": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter match",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ }
+ }
+ ]
+ },
+ "Existence filter match after pending update": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter match after pending update",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter mismatch triggers re-run of query": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter mismatch triggers re-run of query",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
"resume-token-1000"
]
},
@@ -829,30 +5309,676 @@
"watchSnapshot": {
"targetIds": [
],
- "version": 1000
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter mismatch will drop resume token": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter mismatch will drop resume token",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "existence-filter-resume-token"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ },
+ "runBackoffTimer": true
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "existence-filter-resume-token"
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
- "added": [
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
{
- "key": "collection/1",
+ "key": "collection/2",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 2
},
"version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter synthesizes deletes": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter synthesizes deletes",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
},
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
{
- "key": "collection/2",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -865,18 +5991,19 @@
],
"orderBys": [
],
- "path": "collection"
+ "path": "collection/a"
}
}
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "keys": [
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -887,17 +6014,54 @@
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": true,
+ "fromCache": false,
"hasPendingWrites": false,
"query": {
"filters": [
],
"orderBys": [
],
- "path": "collection"
- }
+ "path": "collection/a"
+ },
+ "removed": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ]
}
- ],
+ ]
+ }
+ ]
+ },
+ "Existence filter with empty target": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter with empty target",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
"expectedState": {
"activeTargets": {
"2": {
@@ -915,44 +6079,17 @@
}
}
},
- {
- "watchRemove": {
- "targetIds": [
- 2
- ]
- }
- },
{
"watchAck": [
2
]
},
- {
- "watchEntity": {
- "docs": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 1
- },
- "version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
{
"watchCurrent": [
[
2
],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
@@ -961,51 +6098,41 @@
],
"version": 2000
},
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
],
- "resumeToken": ""
- },
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
+ "orderBys": [
],
- "resumeToken": ""
+ "path": "collection"
}
}
- }
+ ]
},
{
- "watchRemove": {
- "cause": {
- "code": 7
- },
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
"targetIds": [
- 1
+ 2
]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
@@ -1013,46 +6140,15 @@
"orderBys": [
],
"path": "collection"
- },
- "removed": [
- {
- "key": "collection/2",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 1000
- }
- ]
- }
- ],
- "expectedState": {
- "activeLimboDocs": [
- ],
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
}
}
- }
+ ]
}
]
},
- "Existence filter match": {
+ "Full re-query is skipped when bloom filter can identify documents deleted": {
"describeName": "Existence Filters:",
- "itName": "Existence filter match",
+ "itName": "Full re-query is skipped when bloom filter can identify documents deleted",
"tags": [
],
"config": {
@@ -1097,7 +6193,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1106,6 +6202,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"targets": [
@@ -1131,7 +6238,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1140,6 +6247,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"errorCode": 0,
@@ -1156,11 +6274,85 @@
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
],
- "collection/1"
+ "resume-token-2000"
]
},
{
@@ -1168,14 +6360,61 @@
"targetIds": [
],
"version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
}
]
},
- "Existence filter match after pending update": {
+ "Full re-query is triggered when bloom filter bitmap is invalid": {
"describeName": "Existence Filters:",
- "itName": "Existence filter match after pending update",
+ "itName": "Full re-query is triggered when bloom filter bitmap is invalid",
"tags": [
+ "no-ios",
+ "no-android"
],
"config": {
"numClients": 1,
@@ -1215,48 +6454,30 @@
2
]
},
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-1000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedSnapshotEvents": [
- {
- "errorCode": 0,
- "fromCache": false,
- "hasPendingWrites": false,
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- }
- ]
- },
{
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
],
"targets": [
@@ -1265,32 +6486,43 @@
}
},
{
- "watchFilter": [
+ "watchCurrent": [
[
2
],
- "collection/1"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
],
"errorCode": 0,
@@ -1305,12 +6537,66 @@
}
}
]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "INVALID_BASE_64",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
}
]
},
- "Existence filter mismatch triggers re-run of query": {
+ "Full re-query is triggered when bloom filter can not identify documents deleted": {
"describeName": "Existence Filters:",
- "itName": "Existence filter mismatch triggers re-run of query",
+ "itName": "Full re-query is triggered when bloom filter can not identify documents deleted",
"tags": [
],
"config": {
@@ -1355,7 +6641,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1366,7 +6652,18 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1400,7 +6697,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1411,7 +6708,18 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1436,12 +6744,21 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AxBIApBIAIAWBoCQBA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -1462,7 +6779,14 @@
"path": "collection"
}
}
- ],
+ ]
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ },
"expectedState": {
"activeTargets": {
"2": {
@@ -1479,12 +6803,45 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Full re-query is triggered when bloom filter hashCount is invalid": {
+ "describeName": "Existence Filters:",
+ "itName": "Full re-query is triggered when bloom filter hashCount is invalid",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -1496,7 +6853,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1505,80 +6862,64 @@
"v": 1
},
"version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
- ],
- "resumeToken": ""
},
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
- }
+ ],
+ "targets": [
+ 2
+ ]
}
},
- {
- "watchAck": [
- 1
- ]
- },
{
"watchCurrent": [
[
- 1
+ 2
],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
+ "added": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
"errorCode": 0,
"fromCache": false,
"hasPendingWrites": false,
@@ -1588,25 +6929,48 @@
"orderBys": [
],
"path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
},
- "removed": [
- {
- "key": "collection/2",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 1000
- }
- ]
+ "hashCount": -1
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
}
],
"expectedState": {
- "activeLimboDocs": [
- ],
"activeTargets": {
"2": {
"queries": [
@@ -1625,9 +6989,9 @@
}
]
},
- "Existence filter mismatch will drop resume token": {
+ "Full re-query is triggered when bloom filter is empty": {
"describeName": "Existence Filters:",
- "itName": "Existence filter mismatch will drop resume token",
+ "itName": "Full re-query is triggered when bloom filter is empty",
"tags": [
],
"config": {
@@ -1672,7 +7036,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1683,13 +7047,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -1704,7 +7068,7 @@
[
2
],
- "existence-filter-resume-token"
+ "resume-token-1000"
]
},
{
@@ -1717,7 +7081,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1728,13 +7092,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -1753,42 +7117,21 @@
]
},
{
- "watchStreamClose": {
- "error": {
- "code": 14,
- "message": "Simulated Backend Error"
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "",
+ "padding": 0
+ },
+ "hashCount": 0
},
- "runBackoffTimer": true
- },
- "expectedState": {
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": "existence-filter-resume-token"
- }
- }
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchFilter": [
- [
- 2
+ "keys": [
+ "collection/a"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -1826,12 +7169,55 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Same documents can have different bloom filters": {
+ "describeName": "Existence Filters:",
+ "itName": "Same documents can have different bloom filters",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -1843,7 +7229,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1852,6 +7238,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"targets": [
@@ -1864,81 +7261,80 @@
[
2
],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
- ],
- "resumeToken": ""
- },
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
- }
- }
- }
- },
- {
- "watchAck": [
- 1
- ]
- },
- {
- "watchCurrent": [
- [
- 1
- ],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
+ "added": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
"errorCode": 0,
"fromCache": false,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
"path": "collection"
- },
- "removed": [
+ }
+ }
+ ]
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 4
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1948,17 +7344,35 @@
},
"version": 1000
}
- ]
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
}
],
"expectedState": {
- "activeLimboDocs": [
- ],
"activeTargets": {
"2": {
"queries": [
{
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
@@ -1966,43 +7380,20 @@
}
],
"resumeToken": ""
- }
- }
- }
- }
- ]
- },
- "Existence filter synthesizes deletes": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter synthesizes deletes",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": true
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/a"
- },
- "targetId": 2
- },
- "expectedState": {
- "activeTargets": {
- "2": {
+ },
+ "4": {
"queries": [
{
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
+ "path": "collection"
}
],
"resumeToken": ""
@@ -2012,54 +7403,65 @@
},
{
"watchAck": [
- 2
+ 4
]
},
{
"watchEntity": {
"docs": [
{
- "key": "collection/a",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
},
"version": 1000
}
],
"targets": [
- 2
+ 4
]
}
},
{
"watchCurrent": [
[
- 2
+ 4
],
- "resume-token-1000"
+ "resume-token-1001"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 1000
+ "version": 1001
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/a",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 3
},
"version": 1000
}
@@ -2069,20 +7471,35 @@
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
+ "path": "collection"
}
}
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "CQ==",
+ "padding": 3
+ },
+ "hashCount": 2
+ },
+ "keys": [
+ "collection/b"
+ ],
+ "targetIds": [
2
]
- ]
+ }
},
{
"watchSnapshot": {
@@ -2093,60 +7510,65 @@
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
- },
- "removed": [
- {
- "key": "collection/a",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 1
- },
- "version": 1000
- }
- ]
+ "path": "collection"
+ }
}
- ]
- }
- ]
- },
- "Existence filter with empty target": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter with empty target",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": true
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
- },
+ ],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/a"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "4": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
@@ -2159,67 +7581,113 @@
}
},
{
- "watchAck": [
- 2
- ]
- },
- {
- "watchCurrent": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "CA==",
+ "padding": 4
+ },
+ "hashCount": 1
+ },
+ "keys": [
+ "collection/b"
],
- "resume-token-1000"
- ]
+ "targetIds": [
+ 4
+ ]
+ }
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 3000
},
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
"path": "collection"
}
}
- ]
- },
- {
- "watchFilter": [
- [
- 2
- ],
- "collection/1"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/a",
+ "collection/c"
],
- "version": 2000
- },
- "expectedSnapshotEvents": [
- {
- "errorCode": 0,
- "fromCache": true,
- "hasPendingWrites": false,
- "query": {
- "filters": [
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
],
- "orderBys": [
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
],
- "path": "collection"
+ "resumeToken": ""
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/c"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "4": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
}
}
- ]
+ }
}
]
}
diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json
index 0b6abe08a2b..7babd7364f5 100644
--- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json
@@ -3386,11 +3386,13 @@
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "keys": [
+ ],
+ "targetIds": [
1
]
- ]
+ }
},
{
"watchCurrent": [
@@ -7794,9 +7796,9 @@
}
]
},
- "Limbo resolution throttling with existence filter mismatch": {
+ "Limbo resolution throttling with bloom filter application": {
"describeName": "Limbo Documents:",
- "itName": "Limbo resolution throttling with existence filter mismatch",
+ "itName": "Limbo resolution throttling with bloom filter application",
"tags": [
],
"config": {
@@ -8036,15 +8038,397 @@
}
},
{
- "watchFilter": [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "yABCEAeZURNRGAkgAQ==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/b1",
+ "collection/b2",
+ "collection/b3"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1001
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/b1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b3"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1002"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1002
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/a1",
+ "collection/a2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a1"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a2"
+ }
+ ],
+ "resumeToken": ""
+ }
+ },
+ "enqueuedLimboDocs": [
+ "collection/a3"
+ ]
+ }
+ }
+ ]
+ },
+ "Limbo resolution throttling with existence filter mismatch": {
+ "describeName": "Limbo Documents:",
+ "itName": "Limbo resolution throttling with existence filter mismatch",
+ "tags": [
+ ],
+ "config": {
+ "maxConcurrentLimboResolutions": 2,
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a3"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
[
2
],
- "collection/b1",
- "collection/b2",
- "collection/b3"
+ "resume-token-1000"
]
},
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/a1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a3"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "enableNetwork": false,
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ },
+ "enqueuedLimboDocs": [
+ ]
+ }
+ },
+ {
+ "enableNetwork": true,
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/b1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b3"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/b1",
+ "collection/b2",
+ "collection/b3"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
{
"watchSnapshot": {
"targetIds": [
diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json
index 40e48205956..856e0505d91 100644
--- a/firebase-firestore/src/test/resources/json/limit_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json
@@ -5455,12 +5455,14 @@
}
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "keys": [
+ "collection/b"
],
- "collection/b"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
index 71cb84b9de8..21394a90269 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
@@ -16,6 +16,7 @@
import com.google.firebase.database.collection.ImmutableSortedSet;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.remote.WatchChangeAggregator;
import java.util.HashMap;
@@ -41,6 +42,11 @@ public TargetData getTargetDataForTarget(int targetId) {
return queryData.get(targetId);
}
+ @Override
+ public DatabaseId getDatabaseId() {
+ return DatabaseId.forProject("test-project");
+ }
+
/** Sets or replaces the local state for the provided query data. */
public void setSyncedKeys(TargetData targetData, ImmutableSortedSet keys) {
this.queryData.put(targetData.getTargetId(), targetData);
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
index 55f846f9270..daf64c9b3e3 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
@@ -108,6 +108,8 @@ public class TestUtil {
public static final long ARBITRARY_SEQUENCE_NUMBER = 2;
+ private static final DatabaseId TEST_PROJECT = DatabaseId.forProject("project");
+
@SuppressWarnings("unchecked")
public static Map map(Object... entries) {
Map res = new LinkedHashMap<>();
@@ -140,8 +142,7 @@ public static FieldMask fieldMask(String... fields) {
public static final Map EMPTY_MAP = new HashMap<>();
public static Value wrap(Object value) {
- DatabaseId databaseId = DatabaseId.forProject("project");
- UserDataReader dataReader = new UserDataReader(databaseId);
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
// HACK: We use parseQueryValue() since it accepts scalars as well as arrays / objects, and
// our tests currently use wrap() pretty generically so we don't know the intent.
return dataReader.parseQueryValue(value);
@@ -488,6 +489,11 @@ public TargetData getTargetDataForTarget(int targetId) {
ResourcePath collectionPath = docs.get(0).getKey().getCollectionPath();
return targetData(targetId, QueryPurpose.LISTEN, collectionPath.toString());
}
+
+ @Override
+ public DatabaseId getDatabaseId() {
+ return TEST_PROJECT;
+ }
});
SnapshotVersion version = SnapshotVersion.NONE;
@@ -535,13 +541,18 @@ public TargetData getTargetDataForTarget(int targetId) {
? targetData(targetId, QueryPurpose.LISTEN, doc.getKey().toString())
: null;
}
+
+ @Override
+ public DatabaseId getDatabaseId() {
+ return TEST_PROJECT;
+ }
});
aggregator.handleDocumentChange(change);
return aggregator.createRemoteEvent(doc.getVersion());
}
public static SetMutation setMutation(String path, Map values) {
- UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project"));
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
ParsedSetData parsed = dataReader.parseSetData(values);
// The order of the transforms doesn't matter, but we sort them so tests can assume a particular
@@ -574,7 +585,7 @@ private static PatchMutation patchMutationHelper(
}
}
- UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project"));
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
ParsedUpdateData parsed = dataReader.parseUpdateData(values);
// `mergeMutation()` provides an update mask for the merged fields, whereas `patchMutation()`