Java tutorial
/* * Copyright 2008 Alin Dreghiciu. * * 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. */ package org.ops4j.pax.exam.junit.internal; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.internal.runners.TestClass; import org.junit.internal.runners.TestMethod; import static org.ops4j.lang.NullArgumentException.*; import static org.ops4j.pax.exam.Constants.*; import org.ops4j.pax.exam.Info; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.OptionUtils; import org.ops4j.pax.exam.junit.extender.CallableTestMethod; import org.ops4j.pax.exam.junit.extender.Constants; import org.ops4j.pax.exam.options.FrameworkOption; import org.ops4j.pax.exam.runtime.PaxExamRuntime; import org.ops4j.pax.exam.spi.container.TestContainer; import org.ops4j.pax.exam.spi.container.TestContainerFactory; /** * A {@link TestMethod} that upon invokation starts a {@link TestContainer} and executes the test in the test container. * * @author Alin Dreghiciu (adreghiciu@gmail.com) * @since 0.3.0 December 16, 2008 */ public class JUnit4TestMethod extends TestMethod { /** * Test flow not yet started. */ private static final int NOT_STARTED = 0; /** * Test container started. */ private static final int CONTAINER_STARTED = 1; /** * Test bundle installed. */ private static final int PROBE_INSTALLED = 2; /** * Test bundle started. */ private static final int PROBE_STARTED = 3; /** * Test flow ended */ private static final int SUCCESFUL = 4; /** * JCL logger. */ private static final Log LOG = LogFactory.getLog(JUnit4TestMethod.class); /** * Test method. Cannot reuse the one from super class as it is not public. */ private final Method m_testMethod; /** * Configuration options. */ private final Option[] m_options; /** * Configuration method name (test method name and eventual the framework and framework version) */ private final String m_name; /** * Test bundle URL. */ private final String m_testBundleUrl; /** * Constructor. * * @param testMethod test method (cannot be null) * @param testClass test class (cannot be null) * @param frameworkOption framework option (on which framework the test method should be run) (can be null = default * framework) * @param userOptions user options (can be null) */ public JUnit4TestMethod(final Method testMethod, final TestClass testClass, final FrameworkOption frameworkOption, final Option... userOptions) { super(testMethod, testClass); validateNotNull(testMethod, "Test method"); validateNotNull(testClass, "Test class"); m_testMethod = testMethod; m_options = OptionUtils.combine(userOptions, frameworkOption); m_name = calculateName(testMethod.getName(), frameworkOption); m_testBundleUrl = getTestBundleUrl(testClass.getName(), m_testMethod.getName()); } /** * {@inheritDoc} Starts the test container, installs the test bundle and executes the test within the container. */ @Override public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Info.showLogo(); final String fullTestName = m_name + "(" + m_testMethod.getDeclaringClass().getName() + ")"; LOG.info("Starting test " + fullTestName); int executionState = NOT_STARTED; final TestContainerFactory containerFactory = PaxExamRuntime.getTestContainerFactory(); TestContainer container = null; try { LOG.trace("Start test container"); container = containerFactory.newInstance(m_options); container.start(); executionState = CONTAINER_STARTED; LOG.trace("Install and start test bundle"); final long bundleId = container.installBundle(m_testBundleUrl); executionState = PROBE_INSTALLED; container.setBundleStartLevel(bundleId, START_LEVEL_TEST_BUNDLE); container.startBundle(bundleId); executionState = PROBE_STARTED; LOG.trace("Execute test [" + m_name + "]"); final CallableTestMethod callable = container.getService(CallableTestMethod.class); try { LOG.info("Starting test " + fullTestName); callable.call(); LOG.info("Test " + fullTestName + " ended succesfully"); executionState = SUCCESFUL; } catch (InstantiationException e) { throw new InvocationTargetException(e); } catch (ClassNotFoundException e) { throw new InvocationTargetException(e); } } finally { if (container != null) { // Leave handling of proper stop to container implementation try { container.stop(); } catch (RuntimeException ignore) { if (executionState >= SUCCESFUL) { // throw catched exception if the test already was successful // noinspection ThrowFromFinallyBlock throw ignore; } else { // Do not throw an exception that could occur during stopping the container in case that an // exception was already being thrown LOG.error("Cannot stop the test container: " + ignore.getMessage()); } } } } } /** * Getter. * * @return test method */ public Method getTestMethod() { return m_testMethod; } /** * Getter. * * @return test method name */ public String getName() { return m_name; } /** * Computes the test method name out of test method name, framework and framework version. * * @param testMethodName test method name * @param frameworkOption framework option * @return test method name */ private static String calculateName(final String testMethodName, final FrameworkOption frameworkOption) { final StringBuilder name = new StringBuilder(); name.append(testMethodName); if (frameworkOption != null) { name.append(" [").append(frameworkOption.getName()); final String version = frameworkOption.getVersion(); if (version != null) { name.append("/").append(version); } name.append("]"); } return name.toString(); } /** * Returns the test bundle url using an Pax URL Dir url. * * @param testClassName test class name * @param testMethodName test method name * @return test bundle url */ private static String getTestBundleUrl(final String testClassName, final String testMethodName) { final StringBuilder url = new StringBuilder(); url.append("dir:").append(new File(".").getAbsolutePath()).append("$").append("tail=") .append(testClassName.replace(".", "/")).append(".class").append("&") .append(Constants.PROBE_TEST_CLASS).append("=").append(testClassName).append("&") .append(Constants.PROBE_TEST_METHOD).append("=").append(testMethodName).append("&") .append(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME).append("=") .append(Constants.PROBE_SYMBOLICNAME).append("&") .append(org.osgi.framework.Constants.DYNAMICIMPORT_PACKAGE).append("=*").append("&") .append(org.osgi.framework.Constants.EXPORT_PACKAGE).append("=!*"); return url.toString(); } }