org.mule.tck.junit4.AbstractMuleTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.tck.junit4.AbstractMuleTestCase.java

Source

/*
 * $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;
    }
}