Repository: hive
Updated Branches:
  refs/heads/master 50e04b208 -> 4b418a4ae


HIVE-19560: Retry test runner and retry rule for flaky tests (Prasanth 
Jayachandran reviewed by Jesus Camacho Rodriguez)


Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/4b418a4a
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/4b418a4a
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/4b418a4a

Branch: refs/heads/master
Commit: 4b418a4aeacf21bf84e01d03815124fa8b7cb79a
Parents: 50e04b2
Author: Prasanth Jayachandran <prasan...@apache.org>
Authored: Tue May 15 14:26:00 2018 -0700
Committer: Jesus Camacho Rodriguez <jcama...@apache.org>
Committed: Tue May 15 14:26:00 2018 -0700

----------------------------------------------------------------------
 .../test/org/apache/hive/common/util/Retry.java |  76 +++++++++++++
 .../hive/common/util/RetryTestRunner.java       | 107 +++++++++++++++++++
 .../hive/ql/txn/compactor/TestCompactor.java    |   6 ++
 .../jdbc/TestTriggersMoveWorkloadManager.java   |   3 +
 4 files changed, 192 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hive/blob/4b418a4a/common/src/test/org/apache/hive/common/util/Retry.java
----------------------------------------------------------------------
diff --git a/common/src/test/org/apache/hive/common/util/Retry.java 
b/common/src/test/org/apache/hive/common/util/Retry.java
new file mode 100644
index 0000000..9474e90
--- /dev/null
+++ b/common/src/test/org/apache/hive/common/util/Retry.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hive.common.util;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit test rule that reruns test on failure. With Retry test rule only the 
test method will be retried,
+ * the test class will not be re-initialized.
+ */
+public class Retry implements TestRule {
+
+  private final int retryCount;
+
+  public Retry() {
+    this(RetryTestRunner.DEFAULT_RETRY_COUNT);
+  }
+
+  public Retry(final int retryCount) {
+    this.retryCount = retryCount;
+  }
+
+  @Override
+  public Statement apply(Statement base, Description description) {
+    return new RetryingStatement(base, description);
+  }
+
+  private class RetryingStatement extends Statement {
+    private final Statement wrappedStatement;
+    private final Description description;
+
+    private RetryingStatement(Statement wrappedStatement, final Description 
description) {
+      this.wrappedStatement = wrappedStatement;
+      this.description = description;
+    }
+
+    @Override
+    public void evaluate() throws Throwable {
+      int failedAttempts = 0;
+      boolean retry;
+      do {
+        try {
+          wrappedStatement.evaluate();
+          retry = false;
+        } catch (Throwable throwable) {
+          if (retryCount > failedAttempts) {
+            failedAttempts++;
+            retry = true;
+            System.out.println(description + " Caught: " + 
throwable.getMessage() + ". Retrying test " +
+              failedAttempts + "/" + retryCount);
+          } else {
+            throw throwable;
+          }
+        }
+      } while (retry);
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hive/blob/4b418a4a/common/src/test/org/apache/hive/common/util/RetryTestRunner.java
----------------------------------------------------------------------
diff --git a/common/src/test/org/apache/hive/common/util/RetryTestRunner.java 
b/common/src/test/org/apache/hive/common/util/RetryTestRunner.java
new file mode 100644
index 0000000..32ab1af
--- /dev/null
+++ b/common/src/test/org/apache/hive/common/util/RetryTestRunner.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hive.common.util;
+
+import org.junit.Ignore;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runner.notification.StoppedByUserException;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit test runner that reruns test on failure.
+ */
+public class RetryTestRunner extends BlockJUnit4ClassRunner {
+  // TODO: should this be configurable via annotation or extending @RunWith 
annotation?
+  static final int DEFAULT_RETRY_COUNT = 2; // test is executed 3 times in 
worst case 1 original + 2 retries
+  private final int retryCount;
+  private int failedAttempts = 0;
+
+  public RetryTestRunner(final Class<?> klass) throws InitializationError {
+    super(klass);
+    this.retryCount = DEFAULT_RETRY_COUNT;
+  }
+
+  // from ParentRunner, retried under exception (notified only after 
exhausting retryCount)
+  // invoked for test classes
+  @Override
+  public void run(final RunNotifier notifier) {
+    final Description description = getDescription();
+    final EachTestNotifier testNotifier = new EachTestNotifier(notifier, 
description);
+    final Statement statement = classBlock(notifier);
+    try {
+      statement.evaluate();
+    } catch (AssumptionViolatedException e) {
+      testNotifier.fireTestIgnored();
+    } catch (StoppedByUserException e) {
+      // not retrying when user explicitly stops the test
+      throw e;
+    } catch (Throwable e) {
+      // retry on any other exception
+      retry(description, testNotifier, statement, e);
+    }
+  }
+
+  // invoked for test methods
+  @Override
+  protected void runChild(final FrameworkMethod method, final RunNotifier 
notifier) {
+    final Description description = describeChild(method);
+    if (method.getAnnotation(Ignore.class) != null) {
+      notifier.fireTestIgnored(description);
+    } else {
+      runTestUnit(methodBlock(method), description, notifier);
+    }
+  }
+
+  private void runTestUnit(final Statement statement, final Description 
description, final RunNotifier notifier) {
+    final EachTestNotifier eachNotifier = new EachTestNotifier(notifier, 
description);
+    eachNotifier.fireTestStarted();
+    try {
+      statement.evaluate();
+    } catch (AssumptionViolatedException e) {
+      eachNotifier.addFailedAssumption(e);
+    } catch (Throwable e) {
+      retry(description, eachNotifier, statement, e);
+    } finally {
+      eachNotifier.fireTestFinished();
+    }
+  }
+
+  private void retry(final Description description, final EachTestNotifier 
notifier,
+    final Statement statement, final Throwable currentThrowable) {
+    Throwable caughtThrowable = currentThrowable;
+    while (retryCount > failedAttempts) {
+      try {
+        System.out.println(description + " Caught: " + (currentThrowable == 
null ? "exception" :
+          currentThrowable.getMessage()) + ". Retrying test " + failedAttempts 
+ "/" + retryCount);
+        statement.evaluate();
+        return;
+      } catch (Throwable t) {
+        failedAttempts++;
+        caughtThrowable = t;
+      }
+    }
+    notifier.addFailure(caughtThrowable);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hive/blob/4b418a4a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/txn/compactor/TestCompactor.java
----------------------------------------------------------------------
diff --git 
a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/txn/compactor/TestCompactor.java
 
b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/txn/compactor/TestCompactor.java
index 7e17d5d..de61d71 100644
--- 
a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/txn/compactor/TestCompactor.java
+++ 
b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/txn/compactor/TestCompactor.java
@@ -78,6 +78,8 @@ import org.apache.hadoop.hive.ql.io.orc.Reader;
 import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse;
 import org.apache.hadoop.hive.ql.session.SessionState;
 import org.apache.hadoop.mapred.JobConf;
+import org.apache.hive.common.util.Retry;
+import org.apache.hive.common.util.RetryTestRunner;
 import org.apache.hive.hcatalog.common.HCatUtil;
 import org.apache.hive.hcatalog.streaming.DelimitedInputWriter;
 import org.apache.hive.hcatalog.streaming.HiveEndPoint;
@@ -121,6 +123,10 @@ public class TestCompactor {
 
   @Rule
   public TemporaryFolder stagingFolder = new TemporaryFolder();
+
+  @Rule
+  public Retry retry = new Retry(2);
+
   private HiveConf conf;
   IMetaStoreClient msClient;
   private IDriver driver;

http://git-wip-us.apache.org/repos/asf/hive/blob/4b418a4a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestTriggersMoveWorkloadManager.java
----------------------------------------------------------------------
diff --git 
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestTriggersMoveWorkloadManager.java
 
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestTriggersMoveWorkloadManager.java
index e017e63..40af04f 100644
--- 
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestTriggersMoveWorkloadManager.java
+++ 
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestTriggersMoveWorkloadManager.java
@@ -39,13 +39,16 @@ import org.apache.hadoop.hive.ql.wm.ExecutionTrigger;
 import org.apache.hadoop.hive.ql.wm.Expression;
 import org.apache.hadoop.hive.ql.wm.ExpressionFactory;
 import org.apache.hadoop.hive.ql.wm.Trigger;
+import org.apache.hive.common.util.RetryTestRunner;
 import org.apache.hive.jdbc.miniHS2.MiniHS2;
 import org.apache.hive.jdbc.miniHS2.MiniHS2.MiniClusterType;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import com.google.common.collect.Lists;
 
+@RunWith(RetryTestRunner.class)
 public class TestTriggersMoveWorkloadManager extends AbstractJdbcTriggersTest {
 
   @BeforeClass

Reply via email to