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