Skip to content

Add TestId for reduced flakiness. #334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.testing.common.Tasks2;
import com.google.firebase.testing.common.TestId;
import java.util.HashMap;
import org.junit.Rule;
import org.junit.Test;
Expand All @@ -48,20 +49,24 @@ public void setValueShouldTriggerListenerWithNewlySetData() throws Exception {
Task<?> signInTask = auth.signInWithEmailAndPassword("[email protected]", "password");
Tasks2.waitForSuccess(signInTask);

DatabaseReference doc = database.getReference("restaurants").child("Baadal");
DatabaseReference doc = database.getReference("restaurants").child(TestId.create());
SnapshotListener listener = new SnapshotListener();
doc.addListenerForSingleValueEvent(listener);

HashMap<String, Object> data = new HashMap<>();
data.put("location", "Google NYC");

Task<?> setTask = doc.setValue(new HashMap<>(data));
Task<DataSnapshot> snapshotTask = listener.toTask();
Tasks2.waitForSuccess(setTask);
Tasks2.waitForSuccess(snapshotTask);
try {
Task<?> setTask = doc.setValue(new HashMap<>(data));
Task<DataSnapshot> snapshotTask = listener.toTask();
Tasks2.waitForSuccess(setTask);
Tasks2.waitForSuccess(snapshotTask);

DataSnapshot result = snapshotTask.getResult();
assertThat(result.getValue()).isEqualTo(data);
DataSnapshot result = snapshotTask.getResult();
assertThat(result.getValue()).isEqualTo(data);
} finally {
Tasks2.waitBestEffort(doc.removeValue());
}
}

private static class SnapshotListener implements ValueEventListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.testing.common.Tasks2;
import com.google.firebase.testing.common.TestId;
import java.util.HashMap;
import org.junit.Rule;
import org.junit.Test;
Expand All @@ -41,15 +42,15 @@ public final class FirestoreTest {
@Rule public final ActivityTestRule<Activity> activity = new ActivityTestRule<>(Activity.class);

@Test
public void listenForUpdate() throws Exception {
public void setShouldTriggerListenerWithNewlySetData() throws Exception {
FirebaseAuth auth = FirebaseAuth.getInstance();
FirebaseFirestore firestore = FirebaseFirestore.getInstance();

auth.signOut();
Task<?> signInTask = auth.signInWithEmailAndPassword("[email protected]", "password");
Tasks2.waitForSuccess(signInTask);

DocumentReference doc = firestore.collection("restaurants").document("Baadal");
DocumentReference doc = firestore.collection("restaurants").document(TestId.create());
SnapshotListener listener = new SnapshotListener();
ListenerRegistration registration = doc.addSnapshotListener(listener);

Expand All @@ -66,6 +67,7 @@ public void listenForUpdate() throws Exception {
assertThat(result.getData()).isEqualTo(data);
} finally {
registration.remove();
Tasks2.waitBestEffort(doc.delete());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,39 @@
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;

/** Test utilities for asynchronous tasks. */
public final class Tasks2 {

private static final long BEST_EFFORT_DURATION = 10;
private static final long WAIT_DURATION = 30;
private static final TimeUnit WAIT_UNIT = TimeUnit.SECONDS;

private Tasks2() {}

/**
* Waits for the task to complete.
*
* <p>The primary use case for this method is to perform test clean-up in a {@code finally} block.
* Clean-up is inherently a best-effort task, because it might not succeed when the test is
* broken.
*
* <p>This method will block the current thread for a short period of time. Unlike the other
* methods in this class, this method is not biased towards success or failure. This method does
* not throw any exceptions.
*/
public static void waitBestEffort(Task<?> task) {
try {
Tasks.await(task, BEST_EFFORT_DURATION, WAIT_UNIT);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException | TimeoutException ex) {
// Ignore.
}
}

/**
* Waits for the task to complete successfully.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.firebase.testing.common;

import java.util.UUID;

/**
* A utility for generating ids for some sort of entity for testing.
*
* <p>Examples of test ids include paths to database documents and storage files. This class
* randomly generates ids so that concurrent test runs do not share state. Ids generated by this
* class are guaranteed to begin with a letter, not use special characters, and have no slashes.
*
* <p>This implementation returns strings 21 characters long. All ids begin with the letter {@code
* t} to ensure the first character is a letter. The remaining characters are lower-case hexadecimal
* characters.
*/
public final class TestId {

public static String create() {
return "t" + UUID.randomUUID().toString().replace("-", "").substring(0, 20).toLowerCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.testing.common.Tasks2;
import com.google.firebase.testing.common.TestId;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.junit.Rule;
Expand All @@ -45,17 +46,21 @@ public void getShouldReturnNewlyPutData() throws Exception {
Task<?> signInTask = auth.signInWithEmailAndPassword("[email protected]", "password");
Tasks2.waitForSuccess(signInTask);

StorageReference blob = storage.getReference("restaurants/Baadal");
StorageReference blob = storage.getReference("restaurants").child(TestId.create());

byte[] data = "Google NYC".getBytes(StandardCharsets.UTF_8);

Task<?> putTask = blob.putBytes(Arrays.copyOf(data, data.length));
Tasks2.waitForSuccess(putTask);
try {
Task<?> putTask = blob.putBytes(Arrays.copyOf(data, data.length));
Tasks2.waitForSuccess(putTask);

Task<byte[]> getTask = blob.getBytes(128);
Tasks2.waitForSuccess(getTask);
Task<byte[]> getTask = blob.getBytes(128);
Tasks2.waitForSuccess(getTask);

byte[] result = getTask.getResult();
assertThat(result).isEqualTo(data);
byte[] result = getTask.getResult();
assertThat(result).isEqualTo(data);
} finally {
Tasks2.waitBestEffort(blob.delete());
}
}
}