3
3
import android .app .Application ;
4
4
import android .test .ApplicationTestCase ;
5
5
import android .util .Log ;
6
+ import com .firebase .client .ChildEventListener ;
6
7
import com .firebase .client .DataSnapshot ;
7
8
import com .firebase .client .Firebase ;
8
9
import com .firebase .client .FirebaseError ;
10
+ import com .firebase .client .Query ;
9
11
import com .firebase .client .ValueEventListener ;
12
+ import de .greenrobot .performance .StringGenerator ;
10
13
import java .util .ArrayList ;
11
14
import java .util .List ;
12
15
import java .util .concurrent .CountDownLatch ;
13
16
import java .util .concurrent .TimeUnit ;
14
17
15
18
/**
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
+ *
16
22
* https://www.firebase.com/docs/android/guide/
17
23
*/
18
24
public class PerformanceTestFirebase extends ApplicationTestCase <Application > {
19
25
20
26
private static final String TAG = "PerfTestFirebase" ;
21
27
22
28
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 ;
23
31
private static final int RUNS = 8 ;
24
32
25
33
private Firebase rootFirebaseRef ;
26
- private Firebase simpleEntityRef ;
27
34
28
- private CountDownLatch loadLock ;
29
35
private List <SimpleEntityNotNull > reloaded ;
30
36
31
37
public PerformanceTestFirebase () {
@@ -49,7 +55,6 @@ private void setupFirebase() {
49
55
Firebase .goOffline ();
50
56
51
57
rootFirebaseRef = new Firebase ("https://luminous-inferno-2264.firebaseio.com" );
52
- simpleEntityRef = rootFirebaseRef .child ("simpleEntities" );
53
58
}
54
59
55
60
@ Override
@@ -62,28 +67,115 @@ protected void tearDown() throws Exception {
62
67
super .tearDown ();
63
68
}
64
69
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
+
66
74
//noinspection PointlessBooleanExpression
67
75
if (!BuildConfig .RUN_PERFORMANCE_TESTS ) {
68
76
Log .d (TAG , "Performance tests are disabled." );
69
77
return ;
70
78
}
79
+ Log .d (TAG , "--------Indexed Queries: Start" );
80
+
81
+ // set up node for entities
82
+ Firebase entityRef = rootFirebaseRef .child ("indexedStringEntity" );
71
83
72
- Log .d (TAG , "---------------Start" );
73
84
for (int i = 0 ; i < RUNS ; i ++) {
74
- runTests (BATCH_SIZE );
85
+ Log .d (TAG , "----Run " + (i + 1 ) + " of " + RUNS );
86
+ doIndexedStringEntityQuery (entityRef );
75
87
}
76
- Log .d (TAG , "---------------End" );
88
+
89
+ Log .d (TAG , "--------Indexed Queries: End" );
77
90
}
78
91
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
+
80
111
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
+ }
82
151
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" );
84
176
}
85
177
86
- protected void runTests (final int entityCount ) throws Exception {
178
+ protected void runTests (Firebase simpleEntityRef , final int entityCount ) throws Exception {
87
179
Log .d (TAG , "---------------Start: " + entityCount );
88
180
89
181
long start , time ;
@@ -94,10 +186,10 @@ protected void runTests(final int entityCount) throws Exception {
94
186
}
95
187
System .gc ();
96
188
97
- runOneByOne (list , entityCount / 10 );
189
+ runOneByOne (simpleEntityRef , list , entityCount / 10 );
98
190
99
191
System .gc ();
100
- deleteAll ();
192
+ deleteAll (simpleEntityRef );
101
193
102
194
// there is no such thing as batch storing of items in Firebase
103
195
// so store the whole list of entities at once
@@ -113,7 +205,7 @@ protected void runTests(final int entityCount) throws Exception {
113
205
time = System .currentTimeMillis () - start ;
114
206
Log .d (TAG , "Updated (batch) " + list .size () + " entities in " + time + " ms" );
115
207
116
- loadLock = new CountDownLatch (1 );
208
+ final CountDownLatch loadLock = new CountDownLatch (1 );
117
209
start = System .currentTimeMillis ();
118
210
reloaded = new ArrayList <>(entityCount );
119
211
simpleEntityRef .addListenerForSingleValueEvent (new ValueEventListener () {
@@ -151,13 +243,14 @@ public void onCancelled(FirebaseError firebaseError) {
151
243
time = System .currentTimeMillis () - start ;
152
244
Log .d (TAG , "Accessed properties of " + childrenCount + " entities in " + time + " ms" );
153
245
154
- deleteAll ();
246
+ deleteAll (simpleEntityRef );
155
247
156
248
System .gc ();
157
249
Log .d (TAG , "---------------End: " + entityCount );
158
250
}
159
251
160
- protected void runOneByOne (List <SimpleEntityNotNull > list , int count ) {
252
+ protected void runOneByOne (Firebase simpleEntityRef , List <SimpleEntityNotNull > list ,
253
+ int count ) {
161
254
long start ;
162
255
long time ;
163
256
start = System .currentTimeMillis ();
@@ -178,4 +271,11 @@ protected void runOneByOne(List<SimpleEntityNotNull> list, int count) {
178
271
time = System .currentTimeMillis () - start ;
179
272
Log .d (TAG , "Updated (one-by-one) " + count + " entities in " + time + " ms" );
180
273
}
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
+ }
181
281
}
0 commit comments