diff options
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.java | 139 |
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 { + * @Rule + * public RepeatRule repeatRule = new RepeatRule(); + * ... + * } + * </pre> + * + * and annotate the test to be repeated with the + * {@code @Repeat(n=<repetitions>)} annotation + * + * <pre> + * @Test + * @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; + } +} |