Skip to content

Commit 9ffee19

Browse files
committed
cleanup tests + review feedback
1 parent a0c1f6c commit 9ffee19

File tree

3 files changed

+192
-106
lines changed

3 files changed

+192
-106
lines changed

firebase-database/src/androidTest/java/com/google/firebase/database/QueryTest.java

Lines changed: 145 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
import static org.junit.Assert.assertTrue;
2222
import static org.junit.Assert.fail;
2323

24-
import android.util.Log;
2524
import androidx.annotation.NonNull;
2625
import androidx.test.ext.junit.runners.AndroidJUnit4;
27-
import com.google.android.gms.tasks.Continuation;
28-
import com.google.android.gms.tasks.OnCompleteListener;
29-
import com.google.android.gms.tasks.Task;
26+
import androidx.test.platform.app.InstrumentationRegistry;
27+
import com.google.android.gms.tasks.Tasks;
28+
import com.google.firebase.FirebaseApp;
29+
import com.google.firebase.FirebaseOptions;
3030
import com.google.firebase.database.core.DatabaseConfig;
3131
import com.google.firebase.database.core.Path;
3232
import com.google.firebase.database.core.RepoManager;
@@ -36,6 +36,8 @@
3636
import java.util.Arrays;
3737
import java.util.List;
3838
import java.util.Map;
39+
import java.util.Objects;
40+
import java.util.UUID;
3941
import java.util.concurrent.ExecutionException;
4042
import java.util.concurrent.Semaphore;
4143
import java.util.concurrent.TimeoutException;
@@ -3406,99 +3408,170 @@ public void onComplete(DatabaseError error, DatabaseReference ref) {
34063408
IntegrationTestHelpers.waitFor(semaphore);
34073409
}
34083410

3411+
private static FirebaseApp appForDatabaseUrl(String url, String name) {
3412+
return FirebaseApp.initializeApp(
3413+
InstrumentationRegistry.getInstrumentation().getTargetContext(),
3414+
new FirebaseOptions.Builder()
3415+
.setApplicationId("appid")
3416+
.setApiKey("apikey")
3417+
.setDatabaseUrl(url)
3418+
.build(),
3419+
name);
3420+
}
3421+
34093422
@Test
34103423
public void emptyQueryGet() throws DatabaseException, InterruptedException {
3411-
DatabaseReference node = IntegrationTestHelpers.getRandomNode();
3412-
DatabaseConfig cfg = IntegrationTestHelpers.newTestConfig();
3413-
final Semaphore semaphore = new Semaphore(0);
3414-
node.get()
3415-
.addOnCompleteListener(
3416-
new OnCompleteListener<DataSnapshot>() {
3417-
@Override
3418-
public void onComplete(@NonNull Task<DataSnapshot> task) {
3419-
assertTrue(task.isSuccessful());
3420-
assertNotNull(task.getException());
3421-
assertEquals(task.getException().getMessage(), "Client offline with empty cache!");
3422-
semaphore.release();
3423-
}
3424-
});
3425-
IntegrationTestHelpers.waitFor(semaphore);
3424+
FirebaseApp app =
3425+
appForDatabaseUrl(IntegrationTestValues.getAltNamespace(), UUID.randomUUID().toString());
3426+
FirebaseDatabase db = FirebaseDatabase.getInstance(app);
3427+
db.useEmulator("10.0.2.2", 9000);
3428+
DatabaseReference node = db.getReference();
3429+
try {
3430+
Tasks.await(node.get());
3431+
} catch (ExecutionException e) {
3432+
assertEquals(e.getCause().getMessage(), "Client is offline");
3433+
return;
3434+
}
3435+
fail();
34263436
}
34273437

34283438
@Test
3429-
public void offlineQueryGet() throws DatabaseException {
3439+
public void offlineQueryGet() throws DatabaseException, InterruptedException {
3440+
FirebaseApp app =
3441+
appForDatabaseUrl(IntegrationTestValues.getAltNamespace(), UUID.randomUUID().toString());
3442+
FirebaseDatabase db = FirebaseDatabase.getInstance(app);
3443+
db.useEmulator("10.0.2.2", 9000);
3444+
DatabaseReference node = db.getReference();
34303445
DatabaseConfig cfg = IntegrationTestHelpers.newTestConfig();
34313446
IntegrationTestHelpers.goOffline(cfg);
3432-
DatabaseReference node = IntegrationTestHelpers.getRandomNode();
3433-
node.get()
3434-
.addOnCompleteListener(
3435-
new OnCompleteListener<DataSnapshot>() {
3436-
@Override
3437-
public void onComplete(@NonNull Task<DataSnapshot> task) {
3438-
Log.d("QueryTest", "offlineQueryGet onCompleteListener running.");
3439-
assertFalse(task.isSuccessful());
3440-
assertNotNull(task.getException());
3441-
assertEquals(task.getException().getMessage(), "Client offline with empty cache!");
3442-
}
3443-
});
3447+
try {
3448+
Tasks.await(node.get());
3449+
} catch (ExecutionException e) {
3450+
assertEquals(e.getCause().getMessage(), "Client is offline");
3451+
return;
3452+
}
3453+
fail();
34443454
}
34453455

34463456
@Test
34473457
public void getQueryBasic() throws DatabaseException, InterruptedException {
3448-
DatabaseReference ref = IntegrationTestHelpers.getRandomNode();
3458+
FirebaseApp app =
3459+
appForDatabaseUrl(IntegrationTestValues.getAltNamespace(), UUID.randomUUID().toString());
3460+
FirebaseDatabase db = FirebaseDatabase.getInstance(app);
3461+
db.useEmulator("10.0.2.2", 9000);
3462+
DatabaseReference node = db.getReference();
34493463
final Semaphore semaphore = new Semaphore(0);
3450-
ref.setValue(42)
3451-
.continueWithTask(
3452-
new Continuation<Void, Task<DataSnapshot>>() {
3453-
@Override
3454-
public Task<DataSnapshot> then(@NonNull Task<Void> task) throws Exception {
3455-
assertTrue(task.isSuccessful());
3456-
return ref.get()
3457-
.addOnCompleteListener(
3458-
new OnCompleteListener<DataSnapshot>() {
3459-
@Override
3460-
public void onComplete(@NonNull Task<DataSnapshot> task) {
3461-
assertTrue(task.isSuccessful());
3462-
DataSnapshot snap = task.getResult();
3463-
assertNotNull(snap);
3464-
assertEquals(42, snap.getValue());
3465-
semaphore.release();
3466-
}
3467-
});
3468-
}
3469-
});
3470-
IntegrationTestHelpers.waitFor(semaphore);
3464+
try {
3465+
Tasks.await(node.setValue(42));
3466+
assertEquals(42L, Tasks.await(node.get()).getValue());
3467+
} catch (ExecutionException e) {
3468+
fail();
3469+
}
34713470
}
34723471

34733472
@Test
34743473
public void getQueryCached()
34753474
throws DatabaseException, InterruptedException, TimeoutException, TestFailure {
3476-
DatabaseReference ref = IntegrationTestHelpers.getRandomNode();
3475+
FirebaseApp app =
3476+
appForDatabaseUrl(IntegrationTestValues.getAltNamespace(), UUID.randomUUID().toString());
3477+
FirebaseDatabase db = FirebaseDatabase.getInstance(app);
3478+
db.useEmulator("10.0.2.2", 9000);
3479+
DatabaseReference ref = db.getReference();
34773480
DatabaseConfig cfg = IntegrationTestHelpers.newTestConfig();
34783481
ReadFuture future = ReadFuture.untilNonNull(ref);
34793482
ref.setValue(42);
3480-
assertEquals(42, future.waitForLastValue());
3483+
assertEquals(42L, future.waitForLastValue());
34813484
IntegrationTestHelpers.goOffline(cfg);
3485+
try {
3486+
assertEquals(42L, Tasks.await(ref.get()).getValue());
3487+
} catch (ExecutionException e) {
3488+
fail();
3489+
}
3490+
}
3491+
3492+
@Test
3493+
public void getQueryHitsCacheWhenOffline()
3494+
throws InterruptedException, ExecutionException, TimeoutException, TestFailure {
3495+
FirebaseApp readerApp =
3496+
appForDatabaseUrl(IntegrationTestValues.getNamespace(), UUID.randomUUID().toString());
3497+
FirebaseApp writerApp =
3498+
appForDatabaseUrl(IntegrationTestValues.getNamespace(), UUID.randomUUID().toString());
3499+
FirebaseDatabase readerDb = FirebaseDatabase.getInstance(readerApp);
3500+
FirebaseDatabase writerDb = FirebaseDatabase.getInstance(writerApp);
3501+
readerDb.useEmulator("10.0.2.2", 9000);
3502+
writerDb.useEmulator("10.0.2.2", 9000);
3503+
DatabaseReference reader = readerDb.getReference("/foo");
3504+
DatabaseReference writer = writerDb.getReference("/foo");
3505+
3506+
WriteFuture write = new WriteFuture(writer, 42L);
3507+
assertNull(write.timedGet());
3508+
34823509
final Semaphore semaphore = new Semaphore(0);
3483-
ref.get()
3484-
.addOnCompleteListener(
3485-
new OnCompleteListener<DataSnapshot>() {
3486-
@Override
3487-
public void onComplete(@NonNull Task<DataSnapshot> task) {
3488-
assertTrue(task.isSuccessful());
3489-
DataSnapshot snapshot = task.getResult();
3490-
assertNotNull(snapshot);
3491-
assertEquals(42, snapshot.getValue());
3492-
semaphore.release();
3493-
}
3494-
});
3510+
reader.addValueEventListener(
3511+
new ValueEventListener() {
3512+
@Override
3513+
public void onDataChange(@NonNull DataSnapshot snapshot) {
3514+
if (Objects.requireNonNull(snapshot.getValue()).equals(42L)) {
3515+
semaphore.release();
3516+
}
3517+
}
3518+
3519+
@Override
3520+
public void onCancelled(@NonNull DatabaseError error) {}
3521+
});
34953522
IntegrationTestHelpers.waitFor(semaphore);
3523+
reader.getDatabase().goOffline();
3524+
try {
3525+
DataSnapshot snapshot = Tasks.await(reader.get());
3526+
assertEquals(42L, snapshot.getValue());
3527+
} catch (ExecutionException e) {
3528+
fail();
3529+
}
34963530
}
34973531

34983532
@Test
3499-
public void getQuerySkipsCache() throws DatabaseException {
3500-
DatabaseReference ref = IntegrationTestHelpers.getRandomNode();
3501-
DatabaseConfig cfg = IntegrationTestHelpers.newTestConfig();
3533+
public void getQuerySkipsCacheWhenOnline()
3534+
throws DatabaseException, InterruptedException, ExecutionException, TestFailure,
3535+
TimeoutException {
3536+
FirebaseApp readerApp =
3537+
appForDatabaseUrl(IntegrationTestValues.getNamespace(), UUID.randomUUID().toString());
3538+
FirebaseApp writerApp =
3539+
appForDatabaseUrl(IntegrationTestValues.getNamespace(), UUID.randomUUID().toString());
3540+
FirebaseDatabase readerDb = FirebaseDatabase.getInstance(readerApp);
3541+
FirebaseDatabase writerDb = FirebaseDatabase.getInstance(writerApp);
3542+
readerDb.useEmulator("10.0.2.2", 9000);
3543+
writerDb.useEmulator("10.0.2.2", 9000);
3544+
DatabaseReference reader = readerDb.getReference();
3545+
DatabaseReference writer = writerDb.getReference();
3546+
3547+
reader.addValueEventListener(
3548+
new ValueEventListener() {
3549+
@Override
3550+
public void onDataChange(@NonNull DataSnapshot snapshot) {}
3551+
3552+
@Override
3553+
public void onCancelled(@NonNull DatabaseError error) {}
3554+
});
3555+
3556+
WriteFuture write = new WriteFuture(writer, 42L);
3557+
assertNull(write.timedGet());
3558+
3559+
final Semaphore semaphore = new Semaphore(0);
3560+
3561+
try {
3562+
assertEquals(42L, Tasks.await(reader.get()).getValue());
3563+
} catch (ExecutionException e) {
3564+
fail();
3565+
}
3566+
3567+
write = new WriteFuture(writer, 43L);
3568+
assertNull(write.timedGet());
3569+
3570+
try {
3571+
assertEquals(43L, Tasks.await(reader.get()).getValue());
3572+
} catch (ExecutionException e) {
3573+
fail();
3574+
}
35023575
}
35033576

35043577
@Test
@@ -3508,6 +3581,7 @@ public void querySnapshotChildrenRespectDefaultOrdering()
35083581
List<DatabaseReference> refs = IntegrationTestHelpers.getRandomNode(2);
35093582
DatabaseReference writer = refs.get(0);
35103583
DatabaseReference reader = refs.get(1);
3584+
35113585
final Semaphore semaphore = new Semaphore(0);
35123586

35133587
final Map list =

firebase-database/src/main/java/com/google/firebase/database/connection/PersistentConnectionImpl.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ private enum ConnectionState {
202202
private static final String REQUEST_ACTION = "a";
203203
private static final String REQUEST_ACTION_STATS = "s";
204204
private static final String REQUEST_ACTION_QUERY = "q";
205+
private static final String REQUEST_ACTION_GET = "g";
205206
private static final String REQUEST_ACTION_PUT = "p";
206207
private static final String REQUEST_ACTION_MERGE = "m";
207208
private static final String REQUEST_ACTION_QUERY_UNLISTEN = "n";
@@ -354,7 +355,7 @@ public Task<Object> get(List<String> path, Map<String, Object> queryParams) {
354355
if (connected()) {
355356
task = sendGet(query, source);
356357
} else {
357-
source.setException(new Exception("Client offline!"));
358+
source.setException(new Exception("Client is offline"));
358359
task = source.getTask();
359360
}
360361
doIdleCheck();
@@ -1071,18 +1072,15 @@ private Task<Object> sendGet(final QuerySpec query, TaskCompletionSource<Object>
10711072
request.put(REQUEST_PATH, ConnectionUtils.pathToString(query.path));
10721073
request.put(REQUEST_QUERIES, query.queryParams);
10731074
sendAction(
1074-
REQUEST_ACTION_QUERY,
1075+
REQUEST_ACTION_GET,
10751076
request,
10761077
new ConnectionRequestCallback() {
10771078
@Override
10781079
public void onResponse(Map<String, Object> response) {
10791080
String status = (String) response.get(REQUEST_STATUS);
10801081
if (status.equals("ok")) {
1081-
String pathString = (String) response.get(SERVER_DATA_UPDATE_PATH);
1082-
List<String> path = ConnectionUtils.stringToPath(pathString);
10831082
Object body = response.get(SERVER_DATA_UPDATE_BODY);
1084-
Long tagNumber = ConnectionUtils.longFromObject(response.get(SERVER_DATA_TAG));
1085-
delegate.onDataUpdate(path, body, /*isMerge=*/ false, /*tagNumber=*/ tagNumber);
1083+
delegate.onDataUpdate(query.path, body, /*isMerge=*/ false, /*tagNumber=*/ null);
10861084
source.setResult(body);
10871085
} else {
10881086
source.setException(new Exception((String) response.get(SERVER_DATA_UPDATE_BODY)));

firebase-database/src/main/java/com/google/firebase/database/core/Repo.java

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import static com.google.firebase.database.core.utilities.Utilities.hardAssert;
1818

1919
import androidx.annotation.NonNull;
20-
import com.google.android.gms.tasks.Continuation;
20+
import com.google.android.gms.tasks.OnCompleteListener;
2121
import com.google.android.gms.tasks.Task;
2222
import com.google.android.gms.tasks.TaskCompletionSource;
2323
import com.google.firebase.database.DataSnapshot;
@@ -468,34 +468,48 @@ public void onRequestResult(String optErrorCode, String optErrorMessage) {
468468
}
469469

470470
public Task<DataSnapshot> getValue(Query query) {
471-
return connection
472-
.get(query.getPath().asList(), query.getSpec().getParams().getWireProtocolParams())
473-
.continueWithTask(
474-
new Continuation<Object, Task<DataSnapshot>>() {
475-
@Override
476-
public Task<DataSnapshot> then(@NonNull Task<Object> task) throws Exception {
477-
TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();
478-
if (!task.isSuccessful()) {
479-
Node cached =
480-
serverSyncTree.calcCompleteEventCache(query.getPath(), new ArrayList<>());
481-
if (cached.isEmpty()) {
482-
source.setException(new Exception("Client offline with empty cache!"));
483-
} else {
484-
source.setResult(
485-
InternalHelpers.createDataSnapshot(
486-
query.getRef(), IndexedNode.from(cached, query.getSpec().getIndex())));
487-
}
488-
} else {
489-
Node serverNode = NodeUtilities.NodeFromJSON(task.getResult());
490-
postEvents(serverSyncTree.applyServerOverwrite(query.getPath(), serverNode));
491-
source.setResult(
492-
InternalHelpers.createDataSnapshot(
493-
query.getRef(),
494-
IndexedNode.from(serverNode, query.getSpec().getIndex())));
495-
}
496-
return source.getTask();
497-
}
498-
});
471+
TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();
472+
this.scheduleNow(
473+
new Runnable() {
474+
@Override
475+
public void run() {
476+
connection
477+
.get(query.getPath().asList(), query.getSpec().getParams().getWireProtocolParams())
478+
.addOnCompleteListener(
479+
new OnCompleteListener<Object>() {
480+
@Override
481+
public void onComplete(@NonNull Task<Object> task) {
482+
if (!task.isSuccessful()) {
483+
operationLogger.info(
484+
"get for query "
485+
+ query.getPath()
486+
+ " falling back to cache after error: "
487+
+ task.getException().getMessage());
488+
Node cached =
489+
serverSyncTree.calcCompleteEventCache(
490+
query.getPath(), new ArrayList<>());
491+
if (cached.isEmpty()) {
492+
source.setException(task.getException());
493+
} else {
494+
source.setResult(
495+
InternalHelpers.createDataSnapshot(
496+
query.getRef(),
497+
IndexedNode.from(cached, query.getSpec().getIndex())));
498+
}
499+
return;
500+
}
501+
Node serverNode = NodeUtilities.NodeFromJSON(task.getResult());
502+
postEvents(
503+
serverSyncTree.applyServerOverwrite(query.getPath(), serverNode));
504+
source.setResult(
505+
InternalHelpers.createDataSnapshot(
506+
query.getRef(),
507+
IndexedNode.from(serverNode, query.getSpec().getIndex())));
508+
}
509+
});
510+
}
511+
});
512+
return source.getTask();
499513
}
500514

501515
public void updateChildren(

0 commit comments

Comments
 (0)