aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java')
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java139
1 files changed, 139 insertions, 0 deletions
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
new file mode 100644
index 0000000000..30fffe9d94
--- /dev/null
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.junit;
+
+import java.text.MessageFormat;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * {@link org.junit.rules.TestRule} which enables to run the same JUnit test
+ * repeatedly. Add this rule to the test class
+ *
+ * <pre>
+ * public class MyTest {
+ * &#64;Rule
+ * public RepeatRule repeatRule = new RepeatRule();
+ * ...
+ * }
+ * </pre>
+ *
+ * and annotate the test to be repeated with the
+ * {@code @Repeat(n=<repetitions>)} annotation
+ *
+ * <pre>
+ * &#64;Test
+ * &#64;Repeat(n = 100)
+ * public void test() {
+ * ...
+ * }
+ * </pre>
+ *
+ * then this test will be repeated 100 times. If any test execution fails test
+ * repetition will be stopped.
+ */
+public class RepeatRule implements TestRule {
+
+ private static final Logger LOG = Logger
+ .getLogger(RepeatRule.class.getName());
+
+ /**
+ * Exception thrown if repeated execution of a test annotated with
+ * {@code @Repeat} failed.
+ */
+ public static class RepeatedTestException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor
+ *
+ * @param message
+ * the error message
+ * @since 5.1.9
+ */
+ public RepeatedTestException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param message
+ * the error message
+ * @param cause
+ * exception causing this exception
+ */
+ public RepeatedTestException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private static class RepeatStatement extends Statement {
+
+ private final int repetitions;
+
+ private boolean abortOnFailure;
+
+ private final Statement statement;
+
+ private RepeatStatement(int repetitions, boolean abortOnFailure,
+ Statement statement) {
+ this.repetitions = repetitions;
+ this.abortOnFailure = abortOnFailure;
+ this.statement = statement;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ int failures = 0;
+ for (int i = 0; i < repetitions; i++) {
+ try {
+ statement.evaluate();
+ } catch (Throwable e) {
+ failures += 1;
+ RepeatedTestException ex = new RepeatedTestException(
+ MessageFormat.format(
+ "Repeated test failed when run for the {0}. time",
+ Integer.valueOf(i + 1)),
+ e);
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ if (abortOnFailure) {
+ throw ex;
+ }
+ }
+ }
+ if (failures > 0) {
+ RepeatedTestException e = new RepeatedTestException(
+ MessageFormat.format(
+ "Test failed {0} times out of {1} repeated executions",
+ Integer.valueOf(failures),
+ Integer.valueOf(repetitions)));
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public Statement apply(Statement statement, Description description) {
+ Statement result = statement;
+ Repeat repeat = description.getAnnotation(Repeat.class);
+ if (repeat != null) {
+ int n = repeat.n();
+ boolean abortOnFailure = repeat.abortOnFailure();
+ result = new RepeatStatement(n, abortOnFailure, statement);
+ }
+ return result;
+ }
+}