Skip to content

Commit b79c707

Browse files
committed
Add tests
Change-Id: I71ee6b3021a4e697dc1acbaa97f3bdedaffc0581
1 parent c7ff1ae commit b79c707

File tree

2 files changed

+292
-1
lines changed

2 files changed

+292
-1
lines changed
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. 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 distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.firebase.ui.firestore;
16+
17+
import android.content.Context;
18+
import android.support.annotation.NonNull;
19+
import android.support.test.InstrumentationRegistry;
20+
import android.support.test.runner.AndroidJUnit4;
21+
import android.util.Log;
22+
23+
import com.firebase.ui.common.ChangeEventType;
24+
import com.google.android.gms.tasks.OnCompleteListener;
25+
import com.google.android.gms.tasks.Task;
26+
import com.google.android.gms.tasks.Tasks;
27+
import com.google.firebase.FirebaseApp;
28+
import com.google.firebase.FirebaseOptions;
29+
import com.google.firebase.firestore.CollectionReference;
30+
import com.google.firebase.firestore.DocumentSnapshot;
31+
import com.google.firebase.firestore.FirebaseFirestore;
32+
import com.google.firebase.firestore.FirebaseFirestoreException;
33+
import com.google.firebase.firestore.FirebaseFirestoreSettings;
34+
import com.google.firebase.firestore.Query;
35+
36+
import org.junit.After;
37+
import org.junit.Before;
38+
import org.junit.Test;
39+
import org.junit.runner.RunWith;
40+
41+
import java.util.ArrayList;
42+
import java.util.List;
43+
import java.util.concurrent.Callable;
44+
import java.util.concurrent.Semaphore;
45+
import java.util.concurrent.TimeUnit;
46+
47+
import static org.junit.Assert.assertTrue;
48+
49+
@RunWith(AndroidJUnit4.class)
50+
public class FirestoreArrayTest {
51+
52+
/**
53+
* Simple document class containing only an integer field.
54+
*/
55+
private static class IntegerDocument {
56+
57+
public int field;
58+
59+
public IntegerDocument() {}
60+
61+
public IntegerDocument(int field) {
62+
this.field = field;
63+
}
64+
65+
}
66+
67+
/**
68+
* Simple listener that logs all events, to make test debugging easier.
69+
*/
70+
private static class LoggingListener implements ChangeEventListener {
71+
72+
private static final String TAG = "FirestoreTest_Listener";
73+
74+
@Override
75+
public void onChildChanged(ChangeEventType type,
76+
DocumentSnapshot snapshot,
77+
int newIndex,
78+
int oldIndex) {
79+
Log.d(TAG, "onChildChanged: " + type + " at index " + newIndex);
80+
}
81+
82+
@Override
83+
public void onDataChanged() {
84+
Log.d(TAG, "onDataChanged");
85+
}
86+
87+
@Override
88+
public void onError(FirebaseFirestoreException e) {
89+
Log.w(TAG, "onError", e);
90+
}
91+
}
92+
93+
private static final String TAG = "FirestoreTest";
94+
95+
private static final String FIREBASE_APP_NAME = "test-app";
96+
97+
private static final int TIMEOUT = 30000;
98+
99+
private static final int INITIAL_SIZE = 3;
100+
101+
private FirebaseFirestore mFirestore;
102+
private CollectionReference mCollectionRef;
103+
private Query mQuery;
104+
private FirestoreArray<IntegerDocument> mArray;
105+
private ChangeEventListener mListener;
106+
107+
@Before
108+
public void setUp() throws Exception {
109+
FirebaseApp app = getAppInstance(InstrumentationRegistry.getContext());
110+
111+
// Configure Firestore and disable persistence
112+
mFirestore = FirebaseFirestore.getInstance(app);
113+
mFirestore.setFirestoreSettings(new FirebaseFirestoreSettings.Builder()
114+
.setPersistenceEnabled(false)
115+
.build());
116+
117+
// Get a fresh 'test' subcollection for each test
118+
mCollectionRef = FirebaseFirestore.getInstance(app).collection("firestorearray")
119+
.document().collection("test");
120+
121+
Log.d(TAG, "Test Collection: " + getConsoleLink(mCollectionRef));
122+
123+
// Query is the whole collection ordered by field
124+
mQuery = mCollectionRef.orderBy("field", Query.Direction.ASCENDING);
125+
mArray = new FirestoreArray<>(mQuery, IntegerDocument.class);
126+
127+
// Add a listener to the array so that it's active
128+
mListener = mArray.addChangeEventListener(new LoggingListener());
129+
130+
// Add some initial data
131+
runAndVerify(new Callable<Task<?>>() {
132+
@Override
133+
public Task<?> call() throws Exception {
134+
List<Task> tasks = new ArrayList<>();
135+
for (int i = 0; i < INITIAL_SIZE; i++) {
136+
tasks.add(mCollectionRef.document().set(new IntegerDocument(i)));
137+
}
138+
139+
return Tasks.whenAll(tasks.toArray(new Task[tasks.size()]));
140+
}
141+
}, new Callable<Boolean>() {
142+
@Override
143+
public Boolean call() throws Exception {
144+
return mArray.size() == INITIAL_SIZE;
145+
}
146+
});
147+
}
148+
149+
@After
150+
public void tearDown() throws Exception {
151+
if (mArray != null && mListener != null) {
152+
mArray.removeChangeEventListener(mListener);
153+
} else {
154+
Log.w(TAG, "mArray is null in tearDown");
155+
}
156+
}
157+
158+
/**
159+
* Append a single document and confirm size increases by one.
160+
*/
161+
@Test
162+
public void testPushIncreasesSize() throws Exception {
163+
runAndVerify(new Callable<Task<?>>() {
164+
@Override
165+
public Task<?> call() throws Exception {
166+
return mCollectionRef.document().set(new IntegerDocument(4));
167+
}
168+
}, new Callable<Boolean>() {
169+
@Override
170+
public Boolean call() throws Exception {
171+
return mArray.size() == (INITIAL_SIZE + 1);
172+
}
173+
});
174+
}
175+
176+
/**
177+
* Append a single document to the query and confirm that size increases by one and that the
178+
* document is added to the end of the array.
179+
*/
180+
@Test
181+
public void testAddToEnd() throws Exception {
182+
final int value = 4;
183+
184+
runAndVerify(new Callable<Task<?>>() {
185+
@Override
186+
public Task<?> call() throws Exception {
187+
return mCollectionRef.document().set(new IntegerDocument(value));
188+
}
189+
}, new Callable<Boolean>() {
190+
@Override
191+
public Boolean call() throws Exception {
192+
if (mArray.size() == (INITIAL_SIZE + 1)) {
193+
if (mArray.getObject(mArray.size() - 1).field == value) {
194+
return true;
195+
}
196+
}
197+
198+
return false;
199+
}
200+
});
201+
}
202+
203+
/**
204+
* Append a single document to the query and confirm that size increases by one and that the
205+
* document is added to the beginning of the array.
206+
*/
207+
@Test
208+
public void testAddToBeginning() throws Exception {
209+
final int value = -1;
210+
211+
runAndVerify(new Callable<Task<?>>() {
212+
@Override
213+
public Task<?> call() throws Exception {
214+
return mCollectionRef.document().set(new IntegerDocument(value));
215+
}
216+
}, new Callable<Boolean>() {
217+
@Override
218+
public Boolean call() throws Exception {
219+
if (mArray.size() == (INITIAL_SIZE + 1)) {
220+
if (mArray.getObject(0).field == value) {
221+
return true;
222+
}
223+
}
224+
225+
return false;
226+
}
227+
});
228+
}
229+
230+
/**
231+
* Runs some setup action, waits until it is complete, and then waits for a verification
232+
* condition to be met. Times out after {@link #TIMEOUT}.
233+
*/
234+
@SuppressWarnings("unchecked")
235+
private void runAndVerify(Callable<Task<?>> setup,
236+
Callable<Boolean> verify) throws Exception {
237+
238+
final Semaphore semaphore = new Semaphore(0);
239+
long startTime = System.currentTimeMillis();
240+
241+
// Run the setup action and release the semaphore when it is complete
242+
Task task = setup.call();
243+
task.addOnCompleteListener(new OnCompleteListener() {
244+
@Override
245+
public void onComplete(@NonNull Task task) {
246+
semaphore.release();
247+
}
248+
});
249+
250+
// Wait for the verification condition to be met, or time out
251+
boolean isDone = false;
252+
while (!isDone && (System.currentTimeMillis() - startTime < TIMEOUT)) {
253+
boolean acquired = semaphore.tryAcquire(1, TimeUnit.SECONDS);
254+
if (acquired) {
255+
try {
256+
isDone = verify.call();
257+
} catch (Exception e) {
258+
Log.w(TAG, "error in verification callable", e);
259+
}
260+
}
261+
}
262+
263+
assertTrue("Timed out waiting for setup callable.", task.isComplete());
264+
assertTrue("Timed out waiting for expected results.", isDone);
265+
}
266+
267+
private FirebaseApp getAppInstance(Context context) {
268+
try {
269+
return FirebaseApp.getInstance(FIREBASE_APP_NAME);
270+
} catch (IllegalStateException e) {
271+
return initializeApp(context);
272+
}
273+
}
274+
275+
private FirebaseApp initializeApp(Context context) {
276+
return FirebaseApp.initializeApp(context, new FirebaseOptions.Builder()
277+
.setApplicationId("firebaseuitests-app123")
278+
.setApiKey("AIzaSyCIA_uf-5Y4G83vlZmjMmCM_wkX62iWXf0")
279+
.setProjectId("firebaseuitests")
280+
.build(), FIREBASE_APP_NAME);
281+
}
282+
283+
private String getConsoleLink(CollectionReference reference) {
284+
String base = "https://console.firebase.google.com/project/firebaseuitests/database/firestore/data/";
285+
return base + reference.getPath();
286+
}
287+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2-
package="com.google.firebase.firestore.firestore" />
2+
package="com.google.firebase.firestore.firestore">
3+
4+
<uses-permission android:name="android.permission.INTERNET" />
5+
6+
</manifest>

0 commit comments

Comments
 (0)