use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.
the class SpecTestCase method validateExpectedState.
private void validateExpectedState(@Nullable JSONObject expectedState) throws JSONException {
if (expectedState != null) {
if (expectedState.has("numOutstandingWrites")) {
assertEquals(expectedState.getInt("numOutstandingWrites"), writesSent());
}
if (expectedState.has("writeStreamRequestCount")) {
assertEquals(expectedState.getInt("writeStreamRequestCount"), datastore.getWriteStreamRequestCount());
}
if (expectedState.has("watchStreamRequestCount")) {
assertEquals(expectedState.getInt("watchStreamRequestCount"), datastore.getWatchStreamRequestCount());
}
if (expectedState.has("activeLimboDocs")) {
expectedActiveLimboDocs = new HashSet<>();
JSONArray limboDocs = expectedState.getJSONArray("activeLimboDocs");
for (int i = 0; i < limboDocs.length(); i++) {
expectedActiveLimboDocs.add(key((String) limboDocs.get(i)));
}
}
if (expectedState.has("enqueuedLimboDocs")) {
expectedEnqueuedLimboDocs = new HashSet<>();
JSONArray limboDocs = expectedState.getJSONArray("enqueuedLimboDocs");
for (int i = 0; i < limboDocs.length(); i++) {
expectedEnqueuedLimboDocs.add(key((String) limboDocs.get(i)));
}
}
if (expectedState.has("activeTargets")) {
expectedActiveTargets = new HashMap<>();
JSONObject activeTargets = expectedState.getJSONObject("activeTargets");
Iterator<String> keys = activeTargets.keys();
while (keys.hasNext()) {
String targetIdString = keys.next();
int targetId = Integer.parseInt(targetIdString);
JSONObject queryDataJson = activeTargets.getJSONObject(targetIdString);
JSONArray queryArrayJson = queryDataJson.getJSONArray("queries");
expectedActiveTargets.put(targetId, new ArrayList<>());
for (int i = 0; i < queryArrayJson.length(); i++) {
Query query = parseQuery(queryArrayJson.getJSONObject(i));
// TODO: populate the purpose of the target once it's possible to encode that in the
// spec tests. For now, hard-code that it's a listen despite the fact that it's not
// always the right value.
TargetData targetData = new TargetData(query.toTarget(), targetId, ARBITRARY_SEQUENCE_NUMBER, QueryPurpose.LISTEN);
if (queryDataJson.has("resumeToken")) {
targetData = targetData.withResumeToken(ByteString.copyFromUtf8(queryDataJson.getString("resumeToken")), SnapshotVersion.NONE);
} else {
targetData = targetData.withResumeToken(ByteString.EMPTY, version(queryDataJson.getInt("readTime")));
}
expectedActiveTargets.get(targetId).add(targetData);
}
}
}
}
// Always validate the we received the expected number of events.
validateUserCallbacks(expectedState);
// Always validate that the expected limbo docs match the actual limbo docs.
validateActiveLimboDocs();
validateEnqueuedLimboDocs();
// Always validate that the expected active targets match the actual active targets.
validateActiveTargets();
}
use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.
the class SpecTestCase method validateActiveTargets.
private void validateActiveTargets() {
if (!networkEnabled) {
return;
}
// Create a copy so we can modify it in tests
Map<Integer, TargetData> actualTargets = new HashMap<>(datastore.activeTargets());
for (Map.Entry<Integer, List<TargetData>> expected : expectedActiveTargets.entrySet()) {
assertTrue("Expected active target not found: " + expected.getValue(), actualTargets.containsKey(expected.getKey()));
List<TargetData> expectedQueries = expected.getValue();
TargetData expectedTarget = expectedQueries.get(0);
TargetData actualTarget = actualTargets.get(expected.getKey());
// TODO: validate the purpose of the target once it's possible to encode that in the
// spec tests. For now, only validate properties that can be validated.
// assertEquals(expectedTarget, actualTarget);
assertEquals(expectedTarget.getTarget(), actualTarget.getTarget());
assertEquals(expectedTarget.getTargetId(), actualTarget.getTargetId());
assertEquals(expectedTarget.getSnapshotVersion(), actualTarget.getSnapshotVersion());
assertEquals(expectedTarget.getResumeToken().toStringUtf8(), actualTarget.getResumeToken().toStringUtf8());
actualTargets.remove(expected.getKey());
}
assertTrue("Unexpected active targets: " + actualTargets, actualTargets.isEmpty());
}
use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.
the class RemoteEventTest method createAggregator.
/**
* Creates an aggregator initialized with the set of provided WatchChanges. Tests can add further
* changes via `handleDocumentChange`, `handleTargetChange` and `handleExistenceFilterChange`.
*
* @param targetMap A map of query data for all active targets. The map must include an entry for
* every target referenced by any of the watch changes.
* @param outstandingResponses The number of outstanding ACKs a target has to receive before it is
* considered active, or `noOutstandingResponses` if all targets are already active.
* @param existingKeys The set of documents that are considered synced with the test targets as
* part of a previous listen. To modify this set during test execution, invoke
* `targetMetadataProvider.setSyncedKeys()`.
* @param watchChanges The watch changes to apply before returning the aggregator. Supported
* changes are DocumentWatchChange and WatchTargetChange.
*/
private WatchChangeAggregator createAggregator(Map<Integer, TargetData> targetMap, Map<Integer, Integer> outstandingResponses, ImmutableSortedSet<DocumentKey> existingKeys, WatchChange... watchChanges) {
WatchChangeAggregator aggregator = new WatchChangeAggregator(targetMetadataProvider);
List<Integer> targetIds = new ArrayList<>();
for (Map.Entry<Integer, TargetData> entry : targetMap.entrySet()) {
targetIds.add(entry.getKey());
targetMetadataProvider.setSyncedKeys(entry.getValue(), existingKeys);
}
for (Map.Entry<Integer, Integer> entry : outstandingResponses.entrySet()) {
for (int i = 0; i < entry.getValue(); ++i) {
aggregator.recordPendingTargetRequest(entry.getKey());
}
}
for (WatchChange watchChange : watchChanges) {
if (watchChange instanceof DocumentChange) {
aggregator.handleDocumentChange((DocumentChange) watchChange);
} else if (watchChange instanceof WatchTargetChange) {
aggregator.handleTargetChange((WatchTargetChange) watchChange);
} else {
fail("Encountered unexpected type of WatchChange");
}
}
aggregator.handleTargetChange(new WatchTargetChange(WatchTargetChangeType.NoChange, targetIds, resumeToken));
return aggregator;
}
use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.
the class RemoteEventTest method testExistenceFilterMismatchRemovesCurrentChanges.
@Test
public void testExistenceFilterMismatchRemovesCurrentChanges() {
Map<Integer, TargetData> targetMap = activeQueries(1);
WatchChangeAggregator aggregator = createAggregator(targetMap, noOutstandingResponses, noExistingKeys);
WatchTargetChange markCurrent = new WatchTargetChange(WatchTargetChangeType.Current, asList(1));
aggregator.handleTargetChange(markCurrent);
MutableDocument doc1 = doc("docs/1", 1, map("value", 1));
DocumentChange addDoc = new DocumentChange(asList(1), emptyList(), doc1.getKey(), doc1);
aggregator.handleDocumentChange(addDoc);
// The existence filter mismatch will remove the document from target 1, but not synthesize a
// document delete.
WatchChange.ExistenceFilterWatchChange existenceFilter = new WatchChange.ExistenceFilterWatchChange(1, new ExistenceFilter(0));
aggregator.handleExistenceFilter(existenceFilter);
RemoteEvent event = aggregator.createRemoteEvent(version(3));
assertEquals(version(3), event.getSnapshotVersion());
assertEquals(1, event.getDocumentUpdates().size());
assertEquals(1, event.getTargetMismatches().size());
assertEquals(doc1, event.getDocumentUpdates().get(doc1.getKey()));
assertEquals(1, event.getTargetChanges().size());
TargetChange mapping1 = targetChange(ByteString.EMPTY, false, null, null, null);
assertEquals(mapping1, event.getTargetChanges().get(1));
}
use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.
the class RemoteEventTest method testWillAccumulateDocumentAddedAndRemovedEvents.
@Test
public void testWillAccumulateDocumentAddedAndRemovedEvents() {
Map<Integer, TargetData> targetMap = activeQueries(1, 2, 3, 4, 5, 6);
MutableDocument existingDoc = doc("docs/1", 1, map("value", 1));
MutableDocument newDoc = doc("docs/2", 2, map("value", 2));
WatchChange change1 = new DocumentChange(asList(1, 2, 3), asList(4, 5, 6), existingDoc.getKey(), existingDoc);
WatchChange change2 = new DocumentChange(asList(1, 4), asList(2, 6), newDoc.getKey(), newDoc);
RemoteEvent event = createRemoteEvent(3, targetMap, noOutstandingResponses, keySet(existingDoc.getKey()), change1, change2);
assertEquals(version(3), event.getSnapshotVersion());
assertEquals(2, event.getDocumentUpdates().size());
assertEquals(existingDoc, event.getDocumentUpdates().get(existingDoc.getKey()));
assertEquals(newDoc, event.getDocumentUpdates().get(newDoc.getKey()));
assertEquals(6, event.getTargetChanges().size());
TargetChange mapping1 = targetChange(resumeToken, false, asList(newDoc), asList(existingDoc), null);
assertEquals(mapping1, event.getTargetChanges().get(1));
TargetChange mapping2 = targetChange(resumeToken, false, null, asList(existingDoc), null);
assertEquals(mapping2, event.getTargetChanges().get(2));
TargetChange mapping3 = targetChange(resumeToken, false, null, asList(existingDoc), null);
assertEquals(mapping3, event.getTargetChanges().get(3));
TargetChange mapping4 = targetChange(resumeToken, false, asList(newDoc), null, asList(existingDoc));
assertEquals(mapping4, event.getTargetChanges().get(4));
TargetChange mapping5 = targetChange(resumeToken, false, null, null, asList(existingDoc));
assertEquals(mapping5, event.getTargetChanges().get(5));
TargetChange mapping6 = targetChange(resumeToken, false, null, null, asList(existingDoc));
assertEquals(mapping6, event.getTargetChanges().get(6));
}
Aggregations