From c4a99c677055040e3014793df568e8a96e6f29ee Mon Sep 17 00:00:00 2001 From: Allison Morris Date: Wed, 3 Apr 2019 09:20:02 -0800 Subject: [PATCH] Add TestId for reduced flakiness. --- .../testing/database/DatabaseTest.java | 19 ++++++---- .../testing/firestore/FirestoreTest.java | 6 ++-- .../firebase/testing/common/Tasks2.java | 23 ++++++++++++ .../firebase/testing/common/TestId.java | 35 +++++++++++++++++++ .../firebase/testing/storage/StorageTest.java | 19 ++++++---- 5 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 smoke-tests/src/main/java/com/google/firebase/testing/common/TestId.java diff --git a/smoke-tests/src/database/java/com/google/firebase/testing/database/DatabaseTest.java b/smoke-tests/src/database/java/com/google/firebase/testing/database/DatabaseTest.java index 811f2d19ee0..0f385ab830c 100644 --- a/smoke-tests/src/database/java/com/google/firebase/testing/database/DatabaseTest.java +++ b/smoke-tests/src/database/java/com/google/firebase/testing/database/DatabaseTest.java @@ -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; @@ -48,20 +49,24 @@ public void setValueShouldTriggerListenerWithNewlySetData() throws Exception { Task signInTask = auth.signInWithEmailAndPassword("test@mailinator.com", "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 data = new HashMap<>(); data.put("location", "Google NYC"); - Task setTask = doc.setValue(new HashMap<>(data)); - Task snapshotTask = listener.toTask(); - Tasks2.waitForSuccess(setTask); - Tasks2.waitForSuccess(snapshotTask); + try { + Task setTask = doc.setValue(new HashMap<>(data)); + Task 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 { diff --git a/smoke-tests/src/firestore/java/com/google/firebase/testing/firestore/FirestoreTest.java b/smoke-tests/src/firestore/java/com/google/firebase/testing/firestore/FirestoreTest.java index 916e5ffd621..6323f826609 100644 --- a/smoke-tests/src/firestore/java/com/google/firebase/testing/firestore/FirestoreTest.java +++ b/smoke-tests/src/firestore/java/com/google/firebase/testing/firestore/FirestoreTest.java @@ -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; @@ -41,7 +42,7 @@ public final class FirestoreTest { @Rule public final ActivityTestRule activity = new ActivityTestRule<>(Activity.class); @Test - public void listenForUpdate() throws Exception { + public void setShouldTriggerListenerWithNewlySetData() throws Exception { FirebaseAuth auth = FirebaseAuth.getInstance(); FirebaseFirestore firestore = FirebaseFirestore.getInstance(); @@ -49,7 +50,7 @@ public void listenForUpdate() throws Exception { Task signInTask = auth.signInWithEmailAndPassword("test@mailinator.com", "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); @@ -66,6 +67,7 @@ public void listenForUpdate() throws Exception { assertThat(result.getData()).isEqualTo(data); } finally { registration.remove(); + Tasks2.waitBestEffort(doc.delete()); } } diff --git a/smoke-tests/src/main/java/com/google/firebase/testing/common/Tasks2.java b/smoke-tests/src/main/java/com/google/firebase/testing/common/Tasks2.java index 386ae36eef4..96246e479f7 100644 --- a/smoke-tests/src/main/java/com/google/firebase/testing/common/Tasks2.java +++ b/smoke-tests/src/main/java/com/google/firebase/testing/common/Tasks2.java @@ -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. + * + *

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. + * + *

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. * diff --git a/smoke-tests/src/main/java/com/google/firebase/testing/common/TestId.java b/smoke-tests/src/main/java/com/google/firebase/testing/common/TestId.java new file mode 100644 index 00000000000..0dd45211f87 --- /dev/null +++ b/smoke-tests/src/main/java/com/google/firebase/testing/common/TestId.java @@ -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. + * + *

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. + * + *

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(); + } +} diff --git a/smoke-tests/src/storage/java/com/google/firebase/testing/storage/StorageTest.java b/smoke-tests/src/storage/java/com/google/firebase/testing/storage/StorageTest.java index b1647e03e27..7baacef9001 100644 --- a/smoke-tests/src/storage/java/com/google/firebase/testing/storage/StorageTest.java +++ b/smoke-tests/src/storage/java/com/google/firebase/testing/storage/StorageTest.java @@ -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; @@ -45,17 +46,21 @@ public void getShouldReturnNewlyPutData() throws Exception { Task signInTask = auth.signInWithEmailAndPassword("test@mailinator.com", "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 getTask = blob.getBytes(128); - Tasks2.waitForSuccess(getTask); + Task 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()); + } } }