Skip to content

Commit 071ecbf

Browse files
committed
Overlay performance tests
1 parent 5bc0fef commit 071ecbf

File tree

5 files changed

+129
-5
lines changed

5 files changed

+129
-5
lines changed

firebase-firestore/firebase-firestore.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ dependencies {
168168
annotationProcessor 'com.google.auto.value:auto-value:1.6.5'
169169

170170
testImplementation 'junit:junit:4.12'
171+
testImplementation 'com.github.javafaker:javafaker:1.0.2'
171172
testImplementation 'androidx.test:core:1.2.0'
172173
testImplementation 'org.mockito:mockito-core:2.25.0'
173174
testImplementation ("org.robolectric:robolectric:$robolectricVersion") {
@@ -178,6 +179,7 @@ dependencies {
178179
testImplementation 'com.google.guava:guava-testlib:12.0-rc2'
179180

180181
androidTestImplementation 'junit:junit:4.12'
182+
androidTestImplementation 'com.github.javafaker:javafaker:1.0.2'
181183
androidTestImplementation("com.google.truth:truth:$googleTruthVersion"){
182184
exclude group: "org.codehaus.mojo", module: "animal-sniffer-annotations"
183185
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2021 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.performance;
16+
17+
import static com.google.firebase.firestore.FieldValue.arrayUnion;
18+
import static com.google.firebase.firestore.FieldValue.increment;
19+
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testFirestore;
20+
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor;
21+
import static com.google.firebase.firestore.testutil.TestUtil.map;
22+
23+
import androidx.test.ext.junit.runners.AndroidJUnit4;
24+
import com.github.javafaker.Faker;
25+
import com.github.javafaker.service.RandomService;
26+
import com.google.firebase.firestore.CollectionReference;
27+
import com.google.firebase.firestore.DocumentReference;
28+
import com.google.firebase.firestore.FirebaseFirestore;
29+
import com.google.firebase.firestore.QuerySnapshot;
30+
import com.google.firebase.firestore.Source;
31+
import com.google.firebase.firestore.local.Persistence;
32+
import java.util.ArrayList;
33+
import java.util.HashMap;
34+
import java.util.List;
35+
import java.util.Locale;
36+
import java.util.Map;
37+
import org.junit.Before;
38+
import org.junit.Test;
39+
import org.junit.runner.RunWith;
40+
41+
// TODO: Add the skipped tests from typescript.
42+
@RunWith(AndroidJUnit4.class)
43+
public class PerformanceTest {
44+
Map<String, List<DocumentReference>> docs = new HashMap<>();
45+
FirebaseFirestore db = null;
46+
47+
@Before
48+
public void setUp() {
49+
Persistence.OVERLAY_SUPPORT_ENABLED = true;
50+
// Persistence.OVERLAY_SUPPORT_ENABLED = false;
51+
int mutationPerDoc = 3;
52+
System.out.println(
53+
"PERF: Testing with overlay support: " + Persistence.OVERLAY_SUPPORT_ENABLED);
54+
System.out.println("PERF: Testing with mutation per doc: " + mutationPerDoc * 3);
55+
Faker faker = new Faker(new Locale("zh-CN"));
56+
RandomService randomService = new RandomService();
57+
db = testFirestore();
58+
for (int i = 0; i < 100; ++i) {
59+
String coll = randomService.hex(20);
60+
docs.put(coll, new ArrayList<>());
61+
for (int j = 0; j < 100; ++j) {
62+
Object doc =
63+
map(
64+
"name", faker.pokemon().name(),
65+
"location", faker.pokemon().location(),
66+
"bool", randomService.nextBoolean(),
67+
"double", randomService.nextDouble(),
68+
"color", faker.color().name());
69+
DocumentReference ref = waitFor(db.collection(coll).add(doc));
70+
docs.get(coll).add(ref);
71+
}
72+
}
73+
74+
waitFor(db.disableNetwork());
75+
76+
long milli = System.currentTimeMillis();
77+
for (Map.Entry<String, List<DocumentReference>> entry : docs.entrySet()) {
78+
for (DocumentReference ref : entry.getValue()) {
79+
Object doc =
80+
map(
81+
"name", faker.pokemon().name(),
82+
"location", faker.pokemon().location(),
83+
"bool", randomService.nextBoolean(),
84+
"double", randomService.nextDouble(),
85+
"color", faker.color().name());
86+
ref.set(doc);
87+
for (int i = 0; i < mutationPerDoc; i++) {
88+
ref.update(map("bool", faker.app().version()));
89+
ref.update(map("double", increment(randomService.nextInt(-10, 10))));
90+
ref.update(map("color", arrayUnion(faker.color().name())));
91+
}
92+
}
93+
}
94+
95+
waitFor(db.getAsyncQueue().enqueue(() -> {}));
96+
97+
long durationInMilli = System.currentTimeMillis() - milli;
98+
99+
System.out.println("PERF: Setup mutation takes " + durationInMilli + " milliseconds");
100+
}
101+
102+
@Test
103+
public void testQueries() {
104+
Faker faker = new Faker(new Locale("zh-CN"));
105+
RandomService randomService = new RandomService();
106+
long milli = System.currentTimeMillis();
107+
for (Map.Entry<String, List<DocumentReference>> entry : docs.entrySet()) {
108+
CollectionReference coll = db.collection(entry.getKey());
109+
QuerySnapshot snap =
110+
waitFor(coll.whereEqualTo("name", faker.pokemon().name()).get(Source.CACHE));
111+
snap = waitFor(coll.whereLessThan("double", randomService.nextDouble()).get(Source.CACHE));
112+
snap = waitFor(coll.whereArrayContains("color", faker.color().name()).get(Source.CACHE));
113+
// System.out.println("PERF: Collection query take " + (System.currentTimeMillis() - milli) +
114+
// " milliseconds");
115+
}
116+
long durationInMilli = System.currentTimeMillis() - milli;
117+
System.out.println("PERF: Queries take " + durationInMilli + " milliseconds");
118+
}
119+
}

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.google.firebase.firestore.QuerySnapshot;
3939
import com.google.firebase.firestore.auth.User;
4040
import com.google.firebase.firestore.core.DatabaseInfo;
41-
import com.google.firebase.firestore.local.Persistence;
4241
import com.google.firebase.firestore.model.DatabaseId;
4342
import com.google.firebase.firestore.testutil.provider.FirestoreProvider;
4443
import com.google.firebase.firestore.util.AsyncQueue;
@@ -97,7 +96,7 @@ public class IntegrationTestUtil {
9796
private static final Map<FirebaseFirestore, Boolean> firestoreStatus = new HashMap<>();
9897

9998
/** Default amount of time to wait for a given operation to complete, used by waitFor() helper. */
100-
private static final long OPERATION_WAIT_TIMEOUT_MS = 30000;
99+
private static final long OPERATION_WAIT_TIMEOUT_MS = 300000;
101100

102101
/**
103102
* Firestore databases can be subject to a ~30s "cold start" delay if they have not been used
@@ -256,8 +255,8 @@ public static FirebaseFirestore testFirestore(
256255
Logger.setLogLevel(logLevel);
257256

258257
// TODO(Overlay): Remove below once this is ready to ship.
259-
Persistence.OVERLAY_SUPPORT_ENABLED = true;
260-
Persistence.INDEXING_SUPPORT_ENABLED = true;
258+
// Persistence.OVERLAY_SUPPORT_ENABLED = true;
259+
// Persistence.INDEXING_SUPPORT_ENABLED = true;
261260

262261
Context context = ApplicationProvider.getApplicationContext();
263262
DatabaseId databaseId = DatabaseId.forDatabase(projectId, DatabaseId.DEFAULT_DATABASE_ID);

firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public Task<Void> waitForPendingWrites() {
529529
}
530530

531531
@VisibleForTesting
532-
AsyncQueue getAsyncQueue() {
532+
public AsyncQueue getAsyncQueue() {
533533
return asyncQueue;
534534
}
535535

firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ public Task<Void> configureFieldIndexes(List<FieldIndex> fieldIndices) {
329329
return asyncQueue.enqueue(() -> localStore.configureFieldIndexes(fieldIndices));
330330
}
331331

332+
public AsyncQueue getAsyncQueue() {
333+
return asyncQueue;
334+
}
335+
332336
public void removeSnapshotsInSyncListener(EventListener<Void> listener) {
333337
// Checks for shutdown but does not raise error, allowing remove after shutdown to be a no-op.
334338
if (isTerminated()) {

0 commit comments

Comments
 (0)