Skip to content

Commit 3187cd1

Browse files
committed
Port spec tests for realtime ppl
1 parent bfc920f commit 3187cd1

22 files changed

+1429600
-211
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.spec;
16+
17+
public class MemoryPipelineSpecTest extends MemorySpecTest {
18+
public MemoryPipelineSpecTest() {
19+
usePipelineMode = true;
20+
}
21+
}

firebase-firestore/src/test/java/com/google/firebase/firestore/spec/QueryEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616

1717
import androidx.annotation.Nullable;
1818
import com.google.firebase.firestore.FirebaseFirestoreException;
19-
import com.google.firebase.firestore.core.Query;
19+
import com.google.firebase.firestore.core.QueryOrPipeline;
2020
import com.google.firebase.firestore.core.ViewSnapshot;
2121

2222
/** Object that contains exactly one of either a view snapshot or an error for the given query. */
2323
public class QueryEvent {
24-
public Query query;
24+
public QueryOrPipeline queryOrPipeline;
2525
public @Nullable ViewSnapshot view;
2626
public @Nullable FirebaseFirestoreException error;
2727

2828
@Override
2929
public String toString() {
30-
return "QueryEvent(" + query + ", " + view + ", " + error + ")";
30+
return "QueryEvent(" + queryOrPipeline + ", " + view + ", " + error + ")";
3131
}
3232
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.spec;
16+
17+
public class SQLitePipelineSpecTest extends SQLiteSpecTest {
18+
public SQLitePipelineSpecTest() {
19+
usePipelineMode = true;
20+
}
21+
}

firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
import com.google.firebase.firestore.EventListener;
4242
import com.google.firebase.firestore.FirebaseFirestore;
4343
import com.google.firebase.firestore.FirebaseFirestoreException;
44+
import com.google.firebase.firestore.FirebaseFirestoreIntegrationTestFactory;
4445
import com.google.firebase.firestore.ListenSource;
4546
import com.google.firebase.firestore.LoadBundleTask;
47+
import com.google.firebase.firestore.UserDataReader;
4648
import com.google.firebase.firestore.auth.User;
4749
import com.google.firebase.firestore.bundle.BundleReader;
4850
import com.google.firebase.firestore.bundle.BundleSerializer;
@@ -57,6 +59,7 @@
5759
import com.google.firebase.firestore.core.QueryListener;
5860
import com.google.firebase.firestore.core.QueryOrPipeline;
5961
import com.google.firebase.firestore.core.SyncEngine;
62+
import com.google.firebase.firestore.core.Target;
6063
import com.google.firebase.firestore.core.TargetOrPipeline;
6164
import com.google.firebase.firestore.local.LocalStore;
6265
import com.google.firebase.firestore.local.LruDelegate;
@@ -104,6 +107,7 @@
104107
import java.util.ArrayList;
105108
import java.util.Arrays;
106109
import java.util.Collections;
110+
import java.util.Comparator;
107111
import java.util.HashMap;
108112
import java.util.HashSet;
109113
import java.util.Iterator;
@@ -163,6 +167,8 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
163167
// separated by a space character.
164168
private static final String TEST_FILTER_PROPERTY = "specTestFilter";
165169

170+
private static final String NO_PIPELINE_CONVERSION_TAG = "no-pipeline-conversion";
171+
166172
// Tags on tests that should be excluded from execution, useful to allow the platforms to
167173
// temporarily diverge or for features that are designed to be platform specific (such as
168174
// 'multi-client').
@@ -174,6 +180,9 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
174180
private boolean useEagerGcForMemory;
175181
private int maxConcurrentLimboResolutions;
176182
private boolean networkEnabled = true;
183+
protected boolean usePipelineMode = false;
184+
185+
private FirebaseFirestore db;
177186

178187
//
179188
// Parts of the Firestore system that the spec tests need to control.
@@ -196,7 +205,7 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
196205
* A dictionary for tracking the listens on queries. Note that the identity of the listeners is
197206
* used to remove them.
198207
*/
199-
private Map<Query, QueryListener> queryListeners;
208+
private Map<QueryOrPipeline, QueryListener> queryListeners;
200209

201210
/**
202211
* Set of documents that are expected to be in limbo with an active target. Verified at every
@@ -291,6 +300,7 @@ protected void specSetUp(JSONObject config) {
291300

292301
currentUser = User.UNAUTHENTICATED;
293302
databaseInfo = PersistenceTestHelpers.nextDatabaseInfo();
303+
db = new FirebaseFirestoreIntegrationTestFactory(databaseInfo.getDatabaseId()).firestore;
294304

295305
if (config.optInt("numClients", 1) != 1) {
296306
throw Assert.fail("The Android client does not support multi-client tests");
@@ -577,21 +587,30 @@ private void doListen(JSONObject listenSpec) throws Exception {
577587
Query query = parseQuery(listenSpec.getJSONObject("query"));
578588
ListenOptions options = parseListenOptions(listenSpec);
579589

590+
QueryOrPipeline queryOrPipeline;
591+
if (usePipelineMode) {
592+
queryOrPipeline =
593+
new QueryOrPipeline.PipelineWrapper(
594+
query.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId())));
595+
} else {
596+
queryOrPipeline = new QueryOrPipeline.QueryWrapper(query);
597+
}
598+
580599
QueryListener listener =
581600
new QueryListener(
582-
new QueryOrPipeline.QueryWrapper(query),
601+
queryOrPipeline,
583602
options,
584603
(value, error) -> {
585604
QueryEvent event = new QueryEvent();
586-
event.query = query;
605+
event.queryOrPipeline = queryOrPipeline;
587606
if (value != null) {
588607
event.view = value;
589608
} else {
590609
event.error = error;
591610
}
592611
events.add(event);
593612
});
594-
queryListeners.put(query, listener);
613+
queryListeners.put(queryOrPipeline, listener);
595614
queue.runSync(
596615
() -> {
597616
int actualId = eventManager.addQueryListener(listener);
@@ -601,7 +620,15 @@ private void doListen(JSONObject listenSpec) throws Exception {
601620

602621
private void doUnlisten(JSONArray unlistenSpec) throws Exception {
603622
Query query = parseQuery(unlistenSpec.get(1));
604-
QueryListener listener = queryListeners.remove(query);
623+
QueryOrPipeline queryOrPipeline;
624+
if (usePipelineMode) {
625+
queryOrPipeline =
626+
new QueryOrPipeline.PipelineWrapper(
627+
query.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId())));
628+
} else {
629+
queryOrPipeline = new QueryOrPipeline.QueryWrapper(query);
630+
}
631+
QueryListener listener = queryListeners.remove(queryOrPipeline);
605632
queue.runSync(() -> eventManager.removeQueryListener(listener));
606633
}
607634

@@ -990,7 +1017,14 @@ private void doStep(JSONObject step) throws Exception {
9901017

9911018
private void assertEventMatches(JSONObject expected, QueryEvent actual) throws JSONException {
9921019
Query expectedQuery = parseQuery(expected.get("query"));
993-
assertEquals(expectedQuery, actual.query);
1020+
if (usePipelineMode) {
1021+
assertEquals(
1022+
expectedQuery.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId())),
1023+
actual.queryOrPipeline.pipeline());
1024+
} else {
1025+
assertEquals(expectedQuery, actual.queryOrPipeline.query());
1026+
}
1027+
9941028
if (expected.has("errorCode") && !Status.fromCodeValue(expected.getInt("errorCode")).isOk()) {
9951029
assertNotNull(actual.error);
9961030
assertEquals(expected.getInt("errorCode"), actual.error.getCode().value());
@@ -1041,7 +1075,7 @@ private void validateExpectedSnapshotEvents(@Nullable JSONArray expectedEventsJs
10411075
}
10421076

10431077
// Sort both the expected and actual events by the query's canonical ID.
1044-
events.sort((q1, q2) -> q1.query.getCanonicalId().compareTo(q2.query.getCanonicalId()));
1078+
events.sort(Comparator.comparing(q -> q.queryOrPipeline.canonicalId()));
10451079

10461080
List<JSONObject> expectedEvents = new ArrayList<>();
10471081
for (int i = 0; i < expectedEventsJson.length(); ++i) {
@@ -1052,6 +1086,16 @@ private void validateExpectedSnapshotEvents(@Nullable JSONArray expectedEventsJs
10521086
try {
10531087
Query leftQuery = parseQuery(left.get("query"));
10541088
Query rightQuery = parseQuery(right.get("query"));
1089+
if (usePipelineMode) {
1090+
return leftQuery
1091+
.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId()))
1092+
.canonicalId()
1093+
.compareTo(
1094+
rightQuery
1095+
.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId()))
1096+
.canonicalId());
1097+
}
1098+
10551099
return leftQuery.getCanonicalId().compareTo(rightQuery.getCanonicalId());
10561100
} catch (JSONException e) {
10571101
throw new RuntimeException("Failed to parse JSON during event sorting", e);
@@ -1270,9 +1314,25 @@ private void validateActiveTargets() {
12701314
// with the single assertEquals on the TargetData objects themselves if the sequenceNumber is
12711315
// ever made to be consistent.
12721316
// assertEquals(expectedTarget, actualTarget);
1273-
12741317
assertEquals(expectedTarget.getPurpose(), actualTarget.getPurpose());
1275-
assertEquals(expectedTarget.getTarget(), actualTarget.getTarget());
1318+
if (usePipelineMode && !expectedTarget.getPurpose().equals(QueryPurpose.LIMBO_RESOLUTION)) {
1319+
Target target = expectedTarget.getTarget().target();
1320+
assertEquals(
1321+
new TargetOrPipeline.PipelineWrapper(
1322+
new Query(
1323+
target.getPath(),
1324+
target.getCollectionGroup(),
1325+
target.getFilters(),
1326+
target.getOrderBy(),
1327+
target.getLimit(),
1328+
Query.LimitType.LIMIT_TO_FIRST,
1329+
target.getStartAt(),
1330+
target.getEndAt())
1331+
.toRealtimePipeline(db, new UserDataReader(databaseInfo.getDatabaseId()))),
1332+
actualTarget.getTarget());
1333+
} else {
1334+
assertEquals(expectedTarget.getTarget(), actualTarget.getTarget());
1335+
}
12761336
assertEquals(expectedTarget.getTargetId(), actualTarget.getTargetId());
12771337
assertEquals(expectedTarget.getSnapshotVersion(), actualTarget.getSnapshotVersion());
12781338
assertEquals(
@@ -1392,6 +1452,10 @@ public void testSpecTests() throws Exception {
13921452
JSONArray steps = testJSON.getJSONArray("steps");
13931453
Set<String> tags = getTestTags(testJSON);
13941454

1455+
if (name.contains("Newer ")) {
1456+
info("Skipping test: " + name);
1457+
}
1458+
13951459
boolean runTest;
13961460
if (!shouldRunTest(tags)) {
13971461
runTest = false;
@@ -1443,6 +1507,9 @@ private static boolean anyTestsAreMarkedExclusive(JSONObject fileJSON) throws JS
14431507

14441508
/** Called before executing each test to see if it should be run. */
14451509
private boolean shouldRunTest(Set<String> tags) {
1510+
if (usePipelineMode && tags.contains(NO_PIPELINE_CONVERSION_TAG)) {
1511+
return false;
1512+
}
14461513
return shouldRun(tags);
14471514
}
14481515

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
These json files are generated from the web test sources.
2+
3+
TODO(mikelehen): Re-add instructions for generating these.

0 commit comments

Comments
 (0)