Skip to content

Commit b8968e8

Browse files
Add indexed string test for Firebase.
- Add dependency on Common module.
1 parent 76853bf commit b8968e8

File tree

3 files changed

+130
-16
lines changed

3 files changed

+130
-16
lines changed

PerformanceTests/Firebase/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ android {
3232
}
3333

3434
dependencies {
35+
androidTestCompile project(':PerformanceTests:Common')
3536
androidTestCompile 'com.firebase:firebase-client-android:2.3.1'
3637
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package de.greenrobot.performance.firebase;
2+
3+
4+
/**
5+
* Simple entity with a string property that is indexed.
6+
*/
7+
public class IndexedStringEntity {
8+
9+
public long _id;
10+
11+
public String indexedString;
12+
13+
}

PerformanceTests/Firebase/src/androidTest/java/de/greenrobot/performance/firebase/PerformanceTestFirebase.java

Lines changed: 116 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,35 @@
33
import android.app.Application;
44
import android.test.ApplicationTestCase;
55
import android.util.Log;
6+
import com.firebase.client.ChildEventListener;
67
import com.firebase.client.DataSnapshot;
78
import com.firebase.client.Firebase;
89
import com.firebase.client.FirebaseError;
10+
import com.firebase.client.Query;
911
import com.firebase.client.ValueEventListener;
12+
import de.greenrobot.performance.StringGenerator;
1013
import java.util.ArrayList;
1114
import java.util.List;
1215
import java.util.concurrent.CountDownLatch;
1316
import java.util.concurrent.TimeUnit;
1417

1518
/**
19+
* Make sure to run the performance tests while in AIRPLANE MODE, as
20+
* <code>Firebase.goOffline()</code> does not seem to work as expected.
21+
*
1622
* https://www.firebase.com/docs/android/guide/
1723
*/
1824
public class PerformanceTestFirebase extends ApplicationTestCase<Application> {
1925

2026
private static final String TAG = "PerfTestFirebase";
2127

2228
private static final int BATCH_SIZE = 10000;
29+
// reduced query count as local datastore can not be indexed, resulting in low performance
30+
private static final int QUERY_COUNT = 100;
2331
private static final int RUNS = 8;
2432

2533
private Firebase rootFirebaseRef;
26-
private Firebase simpleEntityRef;
2734

28-
private CountDownLatch loadLock;
2935
private List<SimpleEntityNotNull> reloaded;
3036

3137
public PerformanceTestFirebase() {
@@ -49,7 +55,6 @@ private void setupFirebase() {
4955
Firebase.goOffline();
5056

5157
rootFirebaseRef = new Firebase("https://luminous-inferno-2264.firebaseio.com");
52-
simpleEntityRef = rootFirebaseRef.child("simpleEntities");
5358
}
5459

5560
@Override
@@ -62,28 +67,115 @@ protected void tearDown() throws Exception {
6267
super.tearDown();
6368
}
6469

65-
public void testPerformance() throws Exception {
70+
public void testIndexedStringEntityQuery() throws InterruptedException {
71+
// Firebase does not support defining indexes locally, only in the cloud component
72+
// We measure the local datastore query time anyhow, but WITHOUT INDEXES.
73+
6674
//noinspection PointlessBooleanExpression
6775
if (!BuildConfig.RUN_PERFORMANCE_TESTS) {
6876
Log.d(TAG, "Performance tests are disabled.");
6977
return;
7078
}
79+
Log.d(TAG, "--------Indexed Queries: Start");
80+
81+
// set up node for entities
82+
Firebase entityRef = rootFirebaseRef.child("indexedStringEntity");
7183

72-
Log.d(TAG, "---------------Start");
7384
for (int i = 0; i < RUNS; i++) {
74-
runTests(BATCH_SIZE);
85+
Log.d(TAG, "----Run " + (i + 1) + " of " + RUNS);
86+
doIndexedStringEntityQuery(entityRef);
7587
}
76-
Log.d(TAG, "---------------End");
88+
89+
Log.d(TAG, "--------Indexed Queries: End");
7790
}
7891

79-
protected void deleteAll() {
92+
public void doIndexedStringEntityQuery(Firebase entityRef) throws InterruptedException {
93+
// create entities
94+
List<IndexedStringEntity> entities = new ArrayList<>(BATCH_SIZE);
95+
String[] fixedRandomStrings = StringGenerator.createFixedRandomStrings(BATCH_SIZE);
96+
for (int i = 0; i < BATCH_SIZE; i++) {
97+
IndexedStringEntity entity = new IndexedStringEntity();
98+
entity._id = (long) i;
99+
entity.indexedString = fixedRandomStrings[i];
100+
entities.add(entity);
101+
}
102+
Log.d(TAG, "Built entities.");
103+
104+
// insert entities
105+
entityRef.setValue(entities);
106+
Log.d(TAG, "Inserted entities.");
107+
108+
// query for entities by indexed string at random
109+
int[] randomIndices = StringGenerator.getFixedRandomIndices(QUERY_COUNT, BATCH_SIZE - 1);
110+
80111
long start = System.currentTimeMillis();
81-
simpleEntityRef.removeValue();
112+
for (int i = 0; i < QUERY_COUNT; i++) {
113+
int nextIndex = randomIndices[i];
114+
115+
final CountDownLatch queryLock = new CountDownLatch(1);
116+
Query query = entityRef.orderByChild("indexedString");
117+
query.equalTo(fixedRandomStrings[nextIndex]);
118+
ChildEventListener queryEventListener = new ChildEventListener() {
119+
@Override
120+
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
121+
//noinspection unused
122+
IndexedStringEntity entity = dataSnapshot.getValue(IndexedStringEntity.class);
123+
queryLock.countDown();
124+
}
125+
126+
@Override
127+
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
128+
129+
}
130+
131+
@Override
132+
public void onChildRemoved(DataSnapshot dataSnapshot) {
133+
134+
}
135+
136+
@Override
137+
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
138+
139+
}
140+
141+
@Override
142+
public void onCancelled(FirebaseError firebaseError) {
143+
144+
}
145+
};
146+
query.addChildEventListener(queryEventListener);
147+
// wait until there are query results
148+
queryLock.await();
149+
query.removeEventListener(queryEventListener);
150+
}
82151
long time = System.currentTimeMillis() - start;
83-
Log.d(TAG, "Deleted all entities in " + time + " ms");
152+
Log.d(TAG,
153+
"Queried for " + QUERY_COUNT + " of " + BATCH_SIZE + " indexed entities in " + time
154+
+ " ms.");
155+
156+
// delete all entities
157+
entityRef.setValue(null);
158+
Log.d(TAG, "Deleted all entities.");
159+
}
160+
161+
public void testPerformance() throws Exception {
162+
//noinspection PointlessBooleanExpression
163+
if (!BuildConfig.RUN_PERFORMANCE_TESTS) {
164+
Log.d(TAG, "Performance tests are disabled.");
165+
return;
166+
}
167+
Log.d(TAG, "---------------Start");
168+
169+
// set up node for entities
170+
Firebase simpleEntityRef = rootFirebaseRef.child("simpleEntities");
171+
172+
for (int i = 0; i < RUNS; i++) {
173+
runTests(simpleEntityRef, BATCH_SIZE);
174+
}
175+
Log.d(TAG, "---------------End");
84176
}
85177

86-
protected void runTests(final int entityCount) throws Exception {
178+
protected void runTests(Firebase simpleEntityRef, final int entityCount) throws Exception {
87179
Log.d(TAG, "---------------Start: " + entityCount);
88180

89181
long start, time;
@@ -94,10 +186,10 @@ protected void runTests(final int entityCount) throws Exception {
94186
}
95187
System.gc();
96188

97-
runOneByOne(list, entityCount / 10);
189+
runOneByOne(simpleEntityRef, list, entityCount / 10);
98190

99191
System.gc();
100-
deleteAll();
192+
deleteAll(simpleEntityRef);
101193

102194
// there is no such thing as batch storing of items in Firebase
103195
// so store the whole list of entities at once
@@ -113,7 +205,7 @@ protected void runTests(final int entityCount) throws Exception {
113205
time = System.currentTimeMillis() - start;
114206
Log.d(TAG, "Updated (batch) " + list.size() + " entities in " + time + " ms");
115207

116-
loadLock = new CountDownLatch(1);
208+
final CountDownLatch loadLock = new CountDownLatch(1);
117209
start = System.currentTimeMillis();
118210
reloaded = new ArrayList<>(entityCount);
119211
simpleEntityRef.addListenerForSingleValueEvent(new ValueEventListener() {
@@ -151,13 +243,14 @@ public void onCancelled(FirebaseError firebaseError) {
151243
time = System.currentTimeMillis() - start;
152244
Log.d(TAG, "Accessed properties of " + childrenCount + " entities in " + time + " ms");
153245

154-
deleteAll();
246+
deleteAll(simpleEntityRef);
155247

156248
System.gc();
157249
Log.d(TAG, "---------------End: " + entityCount);
158250
}
159251

160-
protected void runOneByOne(List<SimpleEntityNotNull> list, int count) {
252+
protected void runOneByOne(Firebase simpleEntityRef, List<SimpleEntityNotNull> list,
253+
int count) {
161254
long start;
162255
long time;
163256
start = System.currentTimeMillis();
@@ -178,4 +271,11 @@ protected void runOneByOne(List<SimpleEntityNotNull> list, int count) {
178271
time = System.currentTimeMillis() - start;
179272
Log.d(TAG, "Updated (one-by-one) " + count + " entities in " + time + " ms");
180273
}
274+
275+
protected void deleteAll(Firebase simpleEntityRef) throws InterruptedException {
276+
long start = System.currentTimeMillis();
277+
simpleEntityRef.setValue(null);
278+
long time = System.currentTimeMillis() - start;
279+
Log.d(TAG, "Deleted all entities in " + time + " ms");
280+
}
181281
}

0 commit comments

Comments
 (0)