Java tutorial
/* * $Id$ * -------------------------------------------------------------------------------------- * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.tck.junit4; import static org.junit.Assume.assumeThat; import org.mule.RequestContext; import org.mule.tck.junit4.rule.WarningTimeout; import org.mule.util.ClassUtils; import org.mule.util.IOUtils; import org.mule.util.MuleUrlStreamHandlerFactory; import org.mule.util.StringMessageUtils; import org.mule.util.StringUtils; import org.mule.util.SystemUtils; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.util.Iterator; import java.util.Map; import org.apache.commons.collections.IteratorUtils; import org.apache.commons.collections.Predicate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; import org.junit.rules.TestRule; import org.junit.rules.Timeout; /** * <code>AbstractMuleTestCase</code> is a base class for Mule test cases. This * implementation provides services to test code for creating mock and test * objects. */ public abstract class AbstractMuleTestCase { public static final int DEFAULT_TEST_TIMEOUT_SECS = 60; public static final String TEST_TIMEOUT_SYSTEM_PROPERTY = "mule.test.timeoutSecs"; /** * Indicates whether the text boxes will be logged when starting each test case. */ private static final boolean verbose; /** * Indicates if the current test class was excluded using the mule test * exclusion files. Test are executed sequentially, so is not required to * maintain a list of classes. */ private static Boolean excluded = null; static { String muleOpts = SystemUtils.getenv("MULE_TEST_OPTS"); if (StringUtils.isNotBlank(muleOpts)) { Map<String, String> parsedOpts = SystemUtils.parsePropertyDefinitions(muleOpts); String optVerbose = parsedOpts.get("mule.verbose"); verbose = Boolean.valueOf(optVerbose); } else { verbose = true; } // register the custom UrlStreamHandlerFactory. MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory(); } protected final transient Log logger = LogFactory.getLog(this.getClass()); /** * Should be set to a string message describing any prerequisites not met. */ private boolean offline = "true".equalsIgnoreCase(System.getProperty("org.mule.offline")); private int testTimeoutSecs = getTimeoutSystemProperty(); @Rule public TestName name = new TestName(); @Rule public TestRule globalTimeout = createTestTimeoutRule(); public AbstractMuleTestCase() { if (excluded == null) { excluded = isTestIncludedInExclusionFile(this); } } /** * Creates the timeout rule that will be used to run the test. * * @return the rule used to check for test execution timeouts. */ protected TestRule createTestTimeoutRule() { int millisecondsTimeout = getTestTimeoutSecs() * 1000; if (isFailOnTimeout()) { return new Timeout(millisecondsTimeout); } else { return new WarningTimeout(millisecondsTimeout); } } /** * Reads the mule-exclusion file for the current test class and * @param test */ protected boolean isTestIncludedInExclusionFile(AbstractMuleTestCase test) { boolean result = false; final String testName = test.getClass().getName(); try { // We find the physical classpath root URL of the test class and // use that to find the correct resource. Works fine everywhere, // regardless of classloaders. See MULE-2414 URL classUrl = ClassUtils.getClassPathRoot(test.getClass()); URLClassLoader tempClassLoader = new URLClassLoader(new URL[] { classUrl }); URL fileUrl = tempClassLoader.getResource("mule-test-exclusions.txt"); if (fileUrl != null) { InputStream in = null; try { in = fileUrl.openStream(); // this iterates over all lines in the exclusion file Iterator<?> lines = IOUtils.lineIterator(in, "UTF-8"); // ..and this finds non-comments that match the test case name result = IteratorUtils.filteredIterator(lines, new Predicate() { @Override public boolean evaluate(Object object) { return StringUtils.equals(testName, StringUtils.trimToEmpty((String) object)); } }).hasNext(); } finally { IOUtils.closeQuietly(in); } } } catch (IOException ioex) { // ignore } return result; } /** * Defines the number of seconds that a test has in order to run before * throwing a timeout. If the property if not defined then uses the * <code>DEFAULT_MULE_TEST_TIMEOUT_SECS</code> constant. * * @return the timeout value expressed in seconds */ protected int getTimeoutSystemProperty() { String timeoutString = System.getProperty(TEST_TIMEOUT_SYSTEM_PROPERTY, null); if (timeoutString == null) { // unix style: MULE_TEST_TIMEOUTSECS String variableName = TEST_TIMEOUT_SYSTEM_PROPERTY.toUpperCase().replace(".", "_"); timeoutString = System.getenv(variableName); } int result = DEFAULT_TEST_TIMEOUT_SECS; if (timeoutString != null) { try { result = Integer.parseInt(timeoutString); } catch (NumberFormatException e) { // Uses the default value } } return result; } /** * Subclasses can override this method to skip the execution of the entire test class. * * @return <code>true</code> if the test class should not be run. */ protected boolean isDisabledInThisEnvironment() { return false; } /** * Indicates whether this test has been explicitly disabled through the configuration * file loaded by TestInfo. * * @return whether the test has been explicitly disabled */ protected boolean isExcluded() { return excluded; } /** * Should this test run? * * @param testMethodName name of the test method * @return whether the test should execute in the current environment */ protected boolean isDisabledInThisEnvironment(String testMethodName) { return false; } public boolean isOffline(String method) { if (offline) { logger.warn(StringMessageUtils.getBoilerPlate("Working offline cannot run test: " + method, '=', 80)); } return offline; } /** * Defines the timeout in seconds that will be used to run the test. * * @return the timeout in seconds */ public int getTestTimeoutSecs() { return testTimeoutSecs; } @Before public final void initializeMuleTest() { printTestHeader(); skipTestWhenExcluded(); skipTestWhenDisabledInCurrentEnvironment(); } private void printTestHeader() { if (verbose) { System.out.println(StringMessageUtils.getBoilerPlate(getTestHeader(), '=', 80)); } } protected String getTestHeader() { return "Testing: " + name.getMethodName(); } private void skipTestWhenExcluded() { assumeThat(this, new BaseMatcher<AbstractMuleTestCase>() { @Override public boolean matches(Object o) { return !isExcluded(); } @Override public void describeTo(Description description) { description.appendText("Test " + name.getMethodName() + " is excluded"); } }); } private void skipTestWhenDisabledInCurrentEnvironment() { assumeThat(this, new BaseMatcher<AbstractMuleTestCase>() { @Override public boolean matches(Object o) { return !(isDisabledInThisEnvironment() || isDisabledInThisEnvironment(name.getMethodName())); } @Override public void describeTo(Description description) { description.appendText("Test " + name.getMethodName() + " disabled in this environment"); } }); } /** * Indicates whether the test should fail when a timeout is reached. * <p/> * This feature was added to support old test cases that depend on 3rd-party * resources such as a public web service. In such cases it may be desirable * to not fail the test upon timeout but rather to simply log a warning. * * @return true if it must fail on timeout and false otherwise. Default value * is true. */ protected boolean isFailOnTimeout() { return true; } @After public final void clearRequestContext() { RequestContext.clear(); } @AfterClass public static final void clearExcludedFlag() { excluded = null; } }