From 73fe13b3cfb07a95838711f3e58b188680348e1d Mon Sep 17 00:00:00 2001 From: Mike <45373284+munkhuushmgl@users.noreply.github.com> Date: Fri, 9 Oct 2020 11:56:13 -0700 Subject: [PATCH] samples: Translate flaky tests (#297) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #292 #268 #267 ☕️ This is the draft I do not know it is considered as good test design using base class I basically got the idea from the stack overflow answer: https://stackoverflow.com/questions/8295100/how-to-re-run-failed-junit-tests-immediately --- .../example/translate/BatchTranslateText.java | 7 +- .../BatchTranslateTextWithGlossary.java | 7 +- ...atchTranslateTextWithGlossaryAndModel.java | 7 +- .../BatchTranslateTextWithModel.java | 7 +- .../translate/BatchTranslateTextTests.java | 9 ++- ...ranslateTextWithGlossaryAndModelTests.java | 8 ++- .../BatchTranslateTextWithGlossaryTests.java | 8 ++- .../BatchTranslateTextWithModelTests.java | 8 ++- .../java/com/example/translate/Retry.java | 65 +++++++++++++++++++ 9 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 translate/snippets/src/test/java/com/example/translate/Retry.java diff --git a/translate/snippets/src/main/java/com/example/translate/BatchTranslateText.java b/translate/snippets/src/main/java/com/example/translate/BatchTranslateText.java index 3f547a9db73..d36b9962b15 100644 --- a/translate/snippets/src/main/java/com/example/translate/BatchTranslateText.java +++ b/translate/snippets/src/main/java/com/example/translate/BatchTranslateText.java @@ -29,6 +29,7 @@ import com.google.cloud.translate.v3.TranslationServiceClient; import java.io.IOException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -85,7 +86,11 @@ public static void batchTranslateText( client.batchTranslateTextAsync(request); System.out.println("Waiting for operation to complete..."); - BatchTranslateResponse response = future.get(450, TimeUnit.SECONDS); + + // random number between 300 - 450 (maximum allowed seconds) + long randomNumber = ThreadLocalRandom.current().nextInt(300, 450); + BatchTranslateResponse response = future.get(randomNumber, TimeUnit.SECONDS); + System.out.printf("Total Characters: %s\n", response.getTotalCharacters()); System.out.printf("Translated Characters: %s\n", response.getTranslatedCharacters()); } diff --git a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossary.java b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossary.java index 8b270bb68d7..1a69412fa9e 100644 --- a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossary.java +++ b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossary.java @@ -31,6 +31,7 @@ import com.google.cloud.translate.v3.TranslationServiceClient; import java.io.IOException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -103,7 +104,11 @@ public static void batchTranslateTextWithGlossary( client.batchTranslateTextAsync(request); System.out.println("Waiting for operation to complete..."); - BatchTranslateResponse response = future.get(450, TimeUnit.SECONDS); + + // random number between 300 - 450 (maximum allowed seconds) + long randomNumber = ThreadLocalRandom.current().nextInt(300, 450); + BatchTranslateResponse response = future.get(randomNumber, TimeUnit.SECONDS); + // Display the translation for each input text provided System.out.printf("Total Characters: %s\n", response.getTotalCharacters()); System.out.printf("Translated Characters: %s\n", response.getTranslatedCharacters()); diff --git a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossaryAndModel.java b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossaryAndModel.java index 8ecab29c8a1..049dac579c1 100644 --- a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossaryAndModel.java +++ b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithGlossaryAndModel.java @@ -31,6 +31,7 @@ import com.google.cloud.translate.v3.TranslationServiceClient; import java.io.IOException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -110,7 +111,11 @@ public static void batchTranslateTextWithGlossaryAndModel( client.batchTranslateTextAsync(request); System.out.println("Waiting for operation to complete..."); - BatchTranslateResponse response = future.get(450, TimeUnit.SECONDS); + + // random number between 300 - 450 (maximum allowed seconds) + long randomNumber = ThreadLocalRandom.current().nextInt(300, 450); + BatchTranslateResponse response = future.get(randomNumber, TimeUnit.SECONDS); + // Display the translation for each input text provided System.out.printf("Total Characters: %s\n", response.getTotalCharacters()); System.out.printf("Translated Characters: %s\n", response.getTranslatedCharacters()); diff --git a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithModel.java b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithModel.java index c8c906619ac..da0624618b4 100644 --- a/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithModel.java +++ b/translate/snippets/src/main/java/com/example/translate/BatchTranslateTextWithModel.java @@ -29,6 +29,7 @@ import com.google.cloud.translate.v3.TranslationServiceClient; import java.io.IOException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -100,7 +101,11 @@ public static void batchTranslateTextWithModel( client.batchTranslateTextAsync(request); System.out.println("Waiting for operation to complete..."); - BatchTranslateResponse response = future.get(450, TimeUnit.SECONDS); + + // random number between 300 - 450 (maximum allowed seconds) + long randomNumber = ThreadLocalRandom.current().nextInt(300, 450); + BatchTranslateResponse response = future.get(randomNumber, TimeUnit.SECONDS); + // Display the translation for each input text provided System.out.printf("Total Characters: %s\n", response.getTotalCharacters()); System.out.printf("Translated Characters: %s\n", response.getTranslatedCharacters()); diff --git a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextTests.java b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextTests.java index 2b41f00d9ac..24ac82dee2a 100644 --- a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextTests.java +++ b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextTests.java @@ -32,6 +32,7 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -48,6 +49,7 @@ public class BatchTranslateTextTests { private ByteArrayOutputStream bout; private PrintStream out; + @Rule public Retry retry = new Retry(3); private static void cleanUpBucket() { Storage storage = StorageOptions.getDefaultInstance().getService(); @@ -87,23 +89,28 @@ public static void checkRequirements() { requireEnvVar("GOOGLE_CLOUD_PROJECT"); } + private PrintStream originalPrintStream; + @Before public void setUp() { bout = new ByteArrayOutputStream(); out = new PrintStream(bout); + originalPrintStream = System.out; System.setOut(out); } @After public void tearDown() { cleanUpBucket(); - System.setOut(null); + System.out.flush(); + System.setOut(originalPrintStream); } @Test public void testBatchTranslateText() throws InterruptedException, ExecutionException, IOException, TimeoutException { BatchTranslateText.batchTranslateText(PROJECT_ID, "en", "es", INPUT_URI, OUTPUT_URI); + String got = bout.toString(); assertThat(got).contains("Total Characters: 13"); } diff --git a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryAndModelTests.java b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryAndModelTests.java index b88419d9d5f..0f079dc6307 100644 --- a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryAndModelTests.java +++ b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryAndModelTests.java @@ -34,6 +34,7 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -56,6 +57,7 @@ public class BatchTranslateTextWithGlossaryAndModelTests { private ByteArrayOutputStream bout; private PrintStream out; + @Rule public Retry retry = new Retry(3); private static final void cleanUpBucket() { Storage storage = StorageOptions.getDefaultInstance().getService(); @@ -95,6 +97,8 @@ public static void checkRequirements() { requireEnvVar("GOOGLE_CLOUD_PROJECT"); } + private PrintStream originalPrintStream; + @Before public void setUp() throws InterruptedException, ExecutionException, IOException { // Create a glossary that can be used in the test @@ -107,6 +111,7 @@ public void setUp() throws InterruptedException, ExecutionException, IOException bout = new ByteArrayOutputStream(); out = new PrintStream(bout); + originalPrintStream = System.out; System.setOut(out); } @@ -115,7 +120,8 @@ public void tearDown() throws InterruptedException, ExecutionException, IOExcept cleanUpBucket(); // Delete the created glossary DeleteGlossary.deleteGlossary(PROJECT_ID, GLOSSARY_ID); - System.setOut(null); + System.out.flush(); + System.setOut(originalPrintStream); } @Test diff --git a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryTests.java b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryTests.java index 92258d8ee89..4ee05d89752 100644 --- a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryTests.java +++ b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithGlossaryTests.java @@ -34,6 +34,7 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -55,6 +56,7 @@ public class BatchTranslateTextWithGlossaryTests { private ByteArrayOutputStream bout; private PrintStream out; + private PrintStream originalPrintStream; private static final void cleanUpBucket() { Storage storage = StorageOptions.getDefaultInstance().getService(); @@ -106,6 +108,7 @@ public void setUp() throws InterruptedException, ExecutionException, IOException bout = new ByteArrayOutputStream(); out = new PrintStream(bout); + originalPrintStream = System.out; System.setOut(out); } @@ -115,9 +118,12 @@ public void tearDown() throws InterruptedException, ExecutionException, IOExcept cleanUpBucket(); // Delete the created glossary DeleteGlossary.deleteGlossary(PROJECT_ID, GLOSSARY_ID); - System.setOut(null); + System.out.flush(); + System.setOut(originalPrintStream); } + @Rule public Retry retry = new Retry(3); + @Test public void testBatchTranslateTextWithGlossary() throws InterruptedException, ExecutionException, IOException, TimeoutException { diff --git a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithModelTests.java b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithModelTests.java index db7ef195c18..4a37362c3ef 100644 --- a/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithModelTests.java +++ b/translate/snippets/src/test/java/com/example/translate/BatchTranslateTextWithModelTests.java @@ -32,6 +32,7 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -50,6 +51,7 @@ public class BatchTranslateTextWithModelTests { private ByteArrayOutputStream bout; private PrintStream out; + private PrintStream originalPrintStream; private static final void cleanUpBucket() { Storage storage = StorageOptions.getDefaultInstance().getService(); @@ -93,15 +95,19 @@ public static void checkRequirements() { public void setUp() { bout = new ByteArrayOutputStream(); out = new PrintStream(bout); + originalPrintStream = System.out; System.setOut(out); } @After public void tearDown() { cleanUpBucket(); - System.setOut(null); + System.out.flush(); + System.setOut(originalPrintStream); } + @Rule public Retry retry = new Retry(3); + @Test public void testBatchTranslateTextWithModel() throws InterruptedException, ExecutionException, IOException, TimeoutException { diff --git a/translate/snippets/src/test/java/com/example/translate/Retry.java b/translate/snippets/src/test/java/com/example/translate/Retry.java new file mode 100644 index 00000000000..6ce19e0ac6f --- /dev/null +++ b/translate/snippets/src/test/java/com/example/translate/Retry.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020 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.example.translate; + +import java.util.Objects; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class Retry implements TestRule { + private int maxAttempts; + + public Retry(int maxAttempts) { + this.maxAttempts = maxAttempts; + } + + @Override + public Statement apply(Statement base, Description description) { + return statement(base, description); + } + + private Statement statement(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Throwable caughtThrowable = null; + + // implement retry logic here + int factor = 1; + for (int attempt = 0; attempt < maxAttempts; attempt++) { + try { + base.evaluate(); + return; + } catch (Throwable t) { + caughtThrowable = t; + + // random_number_milliseconds that is less than or equal to 1000. + int randomNumberMilliseconds = (int) Math.floor(Math.random() * 1000) + 1; + Thread.sleep(1300 * factor + randomNumberMilliseconds); + System.out.println(description.getDisplayName() + ": run " + (attempt + 1) + " failed"); + factor += 1; + + } + } + System.out.println( + description.getDisplayName() + ": giving up after " + maxAttempts + " failures"); + throw Objects.requireNonNull(caughtThrowable); + } + }; + } +}