/*
* (C) Copyright 2014-2015 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Julien Carsique
*
*/
package org.nuxeo.runtime.test.runner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
import org.nuxeo.runtime.test.Failures;
import org.nuxeo.runtime.test.runner.RandomBug.RepeatRule;
/**
* Tests verifying that test fixtures ({@link Before} and {@link After}) and rules ({@link RandomBug.Repeat}) are
* properly working together.
*
* @since 5.9.5
*/
public class RandomBugTest {
private static final Log log = LogFactory.getLog(RandomBugTest.class);
protected static final String FAILURE_MESSAGE = "FAILURE";
protected static boolean isRunningInners;
private String oldProperty;
protected static class IgnoreInner implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
Assume.assumeTrue(isRunningInners);
return base;
}
}
@BeforeClass
public static void setInner() {
isRunningInners = true;
}
@AfterClass
public static void resetInner() {
isRunningInners = false;
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class })
public static class BeforeWithRandomTest {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Before
public void setup() {
fail(FAILURE_MESSAGE);
}
@Test
@RandomBug.Repeat(issue = FAILURE_MESSAGE)
public void test() throws Exception {
fail("test() should not run");
}
}
@Test
public void beforeShouldNotRunWhenAllTestsAreIgnored() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.BYPASS.toString());
runClassAndVerify(BeforeWithRandomTest.class,
"Before method should not have been executed because the test method is ignored", 1, 0, 1);
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class })
public static class AfterWithRandomTest {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Test
@RandomBug.Repeat(issue = FAILURE_MESSAGE)
public void test() throws Exception {
fail("test() should not run");
}
@After
public void tearDown() {
fail(FAILURE_MESSAGE);
}
}
@Test
public void afterShouldNotRunWhenAllTestsAreIgnored() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.BYPASS.toString());
runClassAndVerify(AfterWithRandomTest.class,
"After method should not have been executed because the test method is ignored", 1, 0, 1);
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class })
@RandomBug.Repeat(issue = "failingTest")
public static class FailingTest {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Inject
@Named("test")
RepeatRule repeatRule;
@Test
@RandomBug.Repeat(issue = "failingTest.other", bypass = true)
public void other() throws Exception {
log.trace(repeatRule.statement.serial);
fail("should be bypassed");
}
@Test
public void success() {
log.trace(repeatRule.statement.serial);
}
@Test
public void failbeforeFiveRetry() throws Exception {
log.trace(repeatRule.statement.serial);
if (repeatRule.statement.serial < 5) {
fail("on retry " + repeatRule.statement.serial);
}
}
@Test
public void successOnSevenRetry() throws Exception {
log.trace(repeatRule.statement.serial);
if (repeatRule.statement.serial != 7) {
fail("on retry " + repeatRule.statement.serial);
}
}
@Test
public void failAfterTenRetry() throws Exception {
log.trace(repeatRule.statement.serial);
if (repeatRule.statement.serial > 10) {
fail("on retry " + repeatRule.statement.serial);
}
}
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class })
public static class FailingMethod {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Inject
@Named("method")
RepeatRule methodRule;
@Test
@RandomBug.Repeat(issue = "failingMethod.other", bypass = true)
public void other() throws Exception {
log.trace(methodRule.statement.serial);
fail("should be bypassed");
}
@Test
public void success() {
log.trace(methodRule.statement);
}
@Test
@RandomBug.Repeat(issue = "failingMethod")
public void failbeforeFiveRetry() throws Exception {
log.trace(methodRule.statement.serial);
if (methodRule.statement.serial < 5) {
fail("on retry " + methodRule.statement.serial);
}
}
@Test
@RandomBug.Repeat(issue = "failingMethod")
public void successOnSevenRetry() throws Exception {
log.trace(methodRule.statement.serial);
if (methodRule.statement.serial != 7) {
fail("on retry " + methodRule.statement.serial);
}
}
@Test
@RandomBug.Repeat(issue = "failingMethod")
public void failAfterTenRetry() throws Exception {
log.trace(methodRule.statement.serial);
if (methodRule.statement.serial > 10) {
fail("on retry " + methodRule.statement.serial);
}
}
}
@Test
public void testBypassOnClass() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.BYPASS.toString());
runClassAndVerify(FailingTest.class, "Test should be ignored in BYPASS mode!", 0, 0, 1);
}
@Test
public void testBypassOnMethod() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.BYPASS.toString());
runClassAndVerify(FailingMethod.class, "Test should be ignored in BYPASS mode!", 5, 0, 4);
}
@Test
public void testStrictOnClass() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.STRICT.toString());
runClassAndVerify(FailingTest.class, "STRICT mode should reveal failure", 5, 2, 1);
}
@Test
public void testStrictOnMethod() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.STRICT.toString());
runClassAndVerify(FailingMethod.class, "STRICT mode should reveal failure", 5, 3, 1);
}
@Test
public void testRelaxOnClass() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.RELAX.toString());
// JC: it remembers the failures: result.wasSuccessful() == false
runClassAndVerify(FailingTest.class, "RELAX mode expects a success", 35, 10, 7);
}
@Test
public void testRelaxOnMethod() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.RELAX.toString());
runClassAndVerify(FailingMethod.class, "RELAX mode expects a success", 5, 0, 1);
}
public static class ThisFeature extends SimpleFeature {
public int repeated;
@Override
public void beforeSetup(FeaturesRunner runner) throws Exception {
repeated++;
log.trace(runner.toString() + " " + repeated);
}
}
public static abstract class AbstractRepeatFeaturesTest {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Inject
public FeaturesRunner runner;
public ThisFeature feature;
@Before
public void injectFeature() {
feature = runner.getFeature(ThisFeature.class);
}
@Test
public void repeatedTest() {
if (feature.repeated < 5) {
fail("should fail");
}
}
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class, ThisFeature.class })
@RandomBug.Repeat(issue = "repeatedTest", onFailure = 5)
public static class RepeatFeaturesTest extends AbstractRepeatFeaturesTest {
}
@Test
public void shouldRepeatFeaturesOnClass() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.RELAX.toString());
runClassAndVerify(RepeatFeaturesTest.class, "RELAX mode expects a success", 5, 4, 0);
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class, ThisFeature.class })
public static class RepeatFeaturesMethod {
@ClassRule
public static final IgnoreInner ignoreInner = new IgnoreInner();
@Inject
public FeaturesRunner runner;
public ThisFeature feature;
@Before
public void injectFeature() {
feature = runner.getFeature(ThisFeature.class);
}
@Test
@RandomBug.Repeat(issue = "repeatedMethod", onFailure = 5)
public void repeatedTest() {
if (feature.repeated < 5) {
fail("should fail");
}
}
}
@Test
public void shouldRepeatFeaturesOnMethod() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.RELAX.toString());
runClassAndVerify(RepeatFeaturesMethod.class, "RELAX mode expects a success", 1, 0, 0);
}
@RandomBug.Repeat(issue = "repeatedTest", onFailure = 5)
public static class ThisRandomFeature extends SimpleFeature {
}
@RunWith(FeaturesRunner.class)
@Features({ RandomBug.Feature.class, ThisFeature.class, ThisRandomFeature.class })
public static class RepeatRandomFeaturesTest extends AbstractRepeatFeaturesTest {
}
@Test
public void shouldRepeatFeaturesOnFeature() {
System.setProperty(RandomBug.MODE_PROPERTY, RandomBug.Mode.RELAX.toString());
runClassAndVerify(RepeatRandomFeaturesTest.class, "RELAX mode expects a success", 5, 4, 0);
}
protected Result runClassAndVerify(Class<?> klass, String testFailureDescription, int runCount, int failureCount,
int ignoreCount) {
Result result = JUnitCore.runClasses(klass);
assertThat(result.getRunCount()).isEqualTo(runCount);
assertThat(result.getFailureCount()).isEqualTo(failureCount);
if (failureCount == 0 && !result.wasSuccessful()) {
new Failures(result).fail(FAILURE_MESSAGE, testFailureDescription);
}
assertThat(result.getIgnoreCount()).isEqualTo(ignoreCount);
return result;
}
@Before
public void storeSystemProperties() {
oldProperty = System.getProperty(RandomBug.MODE_PROPERTY);
}
@After
public void clearSystemProperties() {
if (oldProperty != null) {
System.setProperty(RandomBug.MODE_PROPERTY, oldProperty);
} else {
System.clearProperty(RandomBug.MODE_PROPERTY);
}
}
}