/****************************************************************************** | |
* Copyright (c) 2006, 2010 VMware Inc. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* and Apache License v2.0 which accompanies this distribution. | |
* The Eclipse Public License is available at | |
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 | |
* is available at http://www.opensource.org/licenses/apache2.0.php. | |
* You may elect to redistribute this code under either of these licenses. | |
* | |
* Contributors: | |
* VMware Inc. | |
*****************************************************************************/ | |
package org.eclipse.gemini.blueprint.test; | |
import java.io.InputStream; | |
import java.util.Properties; | |
import org.eclipse.gemini.blueprint.test.internal.util.IOUtils; | |
import org.eclipse.gemini.blueprint.test.internal.util.jar.JarCreator; | |
import org.osgi.framework.BundleContext; | |
import org.springframework.core.io.ClassPathResource; | |
import org.springframework.core.io.Resource; | |
import org.springframework.util.StringUtils; | |
/** | |
* Abstract JUnit base class that allows easy OSGi integration testing. It | |
* builds on its super classes to allow full configuration of the underlying | |
* OSGi platform implementation, of the test bundle creation (including the | |
* manifest automatic generation). | |
* <p/> | |
* <p/>This class follows the <em>traditional</em> Spring style of integration | |
* testing in which the test simply indicates the dependencies, leaving the rest | |
* of the work to be done by its super classes. Consider the following simple | |
* example: | |
* <p/> | |
* <pre class="code"> | |
* public class SimpleOsgiTest extends AbstractConfigurableBundleCreatorTests { | |
* <p/> | |
* public void testOsgiPlatformStarts() throws Exception { | |
* System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_VENDOR)); | |
* System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_VERSION)); | |
* System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT)); | |
* } | |
* } | |
* </pre> | |
* <p/> | |
* <p/> The above class can be ran just like any other JUnit test. Equinox | |
* platform will be automatically started, the test will packed in an OSGi | |
* bundle (with its manifest created automatically) which will be deployed | |
* inside the OSGi platform. After running the test inside the OSGi environment, | |
* the test results (whether they are exceptions or failures) will be reported | |
* back to the running tool transparently. Please see the reference | |
* documentation for more examples, customization tips and help on how to do | |
* efficient and fast integration testing. | |
* <p/> | |
* <p/> This class allows the test on-the-fly bundle (jar) can be configured | |
* declarativelyā€ˇ by indicating the locations for: | |
* <ul> | |
* <li>root folder ({@value #ROOT_DIR}) - the starting point on which the | |
* resource patterns are applied</li> | |
* <li>inclusion patterns ({@value #INCLUDE_PATTERNS})- comma separated | |
* strings which identify the resources that should be included into the | |
* archive.</li> | |
* <li>manifest ({@value #MANIFEST})- the location of the manifest used for | |
* testing (if automatic generation is undesired).</li> | |
* </ul> | |
* <p/> These settings can be configured by: | |
* <ul> | |
* <li>using a properties file. By default the property name follows the | |
* pattern "[testName]-bundle.properties", (i.e. /foo/bar/SomeTest will try to | |
* load file /foo/bar/SomeTest-bundle.properties). If no properties file is | |
* found, a set of defaults will be used.</li> | |
* <p/> | |
* <li>overriding the default getXXX methods and providing an alternative | |
* implementation.</li> | |
* </ul> | |
* <p/> | |
* <p/>Another useful functionality inherited from | |
* {@link AbstractOnTheFlyBundleCreatorTests} class is the ability to create a | |
* manifest for the test bundle on the fly, based on the classes present in the | |
* archive. | |
* <p/> | |
* <p/><b>Note:</b> This class is the main testing framework entry point | |
* | |
* @author Costin Leau | |
* @see AbstractOnTheFlyBundleCreatorTests | |
*/ | |
public abstract class AbstractConfigurableBundleCreatorTests extends AbstractOnTheFlyBundleCreatorTests { | |
protected static final String ROOT_DIR = "root.dir"; | |
protected static final String INCLUDE_PATTERNS = "include.patterns"; | |
protected static final String LIBS = "libs"; | |
protected static final String MANIFEST = "manifest"; | |
private static final Properties DEFAULT_SETTINGS = new Properties(); | |
static { | |
DEFAULT_SETTINGS.setProperty(ROOT_DIR, Thread.currentThread().getContextClassLoader().getResource(".").toString()); | |
DEFAULT_SETTINGS.setProperty(INCLUDE_PATTERNS, JarCreator.EVERYTHING_PATTERN); | |
DEFAULT_SETTINGS.setProperty(LIBS, ""); | |
DEFAULT_SETTINGS.setProperty(MANIFEST, ""); | |
} | |
/** | |
* Settings for the jar creation. Static as it has to be cached between test | |
* runs and it is being initialized once in | |
* {@link #postProcessBundleContext(BundleContext)}. | |
*/ | |
private static Properties jarSettings; | |
protected String getRootPath() { | |
return jarSettings.getProperty(ROOT_DIR); | |
} | |
/** | |
* {@inheritDoc} | |
* <p/> | |
* <p/>Ant-style patterns for identifying the resources added to the jar.The | |
* patterns are considered from the root path when performing the search. | |
* <p/> | |
* <p/> By default, the content pattern is <code>**/*</code> which | |
* includes all sources from the root. One can configure the pattern to | |
* include specific files by using different patterns. For example, to | |
* include just the classes, XML and properties files one can use the | |
* following patterns: | |
* <ol> | |
* <li><code>**/*.class</code> for classes | |
* <li><code>**/*.xml</code> for XML files | |
* <li><code>**/*.properties</code> for properties files | |
* </ol> | |
* | |
* @return array of Ant-style pattern | |
*/ | |
protected String[] getBundleContentPattern() { | |
return StringUtils.commaDelimitedListToStringArray(jarSettings.getProperty(INCLUDE_PATTERNS)); | |
} | |
protected String getManifestLocation() { | |
return jarSettings.getProperty(MANIFEST); | |
} | |
/** | |
* Returns the settings location (by default, the test name; i.e. | |
* <code>foo.bar.SomeTest</code> will try to load | |
* <code>foo/bar/SomeTest-bundle.properties</code>). | |
* | |
* @return settings location for this test | |
*/ | |
protected String getSettingsLocation() { | |
return getClass().getName().replace('.', '/') + "-bundle.properties"; | |
} | |
/** | |
* Returns the default settings used when creating the jar, in case no | |
* customisations have been applied. Unless the base class is used as a | |
* testing framework, consider using a properties file for specifying | |
* specific properties for a test case. | |
* | |
* @return default settings for creating the jar | |
* @see #getSettingsLocation() | |
*/ | |
protected Properties getDefaultSettings() { | |
return DEFAULT_SETTINGS; | |
} | |
/** | |
* Returns the settings used for creating this jar. This method tries to | |
* locate and load the settings from the location indicated by | |
* {@link #getSettingsLocation()}. If no file is found, the default | |
* settings will be used. | |
* <p/> | |
* <p/> A non-null properties object will always be returned. | |
* | |
* @return settings for creating the on the fly jar | |
* @throws Exception if loading the settings file fails | |
*/ | |
protected Properties getSettings() throws Exception { | |
Properties settings = new Properties(getDefaultSettings()); | |
// settings.setProperty(ROOT_DIR, getRootPath()); | |
Resource resource = new ClassPathResource(getSettingsLocation()); | |
if (resource.exists()) { | |
InputStream stream = resource.getInputStream(); | |
try { | |
if (stream != null) { | |
settings.load(stream); | |
logger.debug("Loaded jar settings from " + getSettingsLocation()); | |
} | |
} finally { | |
IOUtils.closeStream(stream); | |
} | |
} else { | |
logger.info(getSettingsLocation() + " was not found; using defaults"); | |
} | |
return settings; | |
} | |
/* | |
* Loads the jar settings, first from the disk falling back to the default | |
* settings, if none is found. | |
*/ | |
protected void postProcessBundleContext(BundleContext context) throws Exception { | |
// hook in properties loading | |
// reset the settings (useful when running multiple tests) | |
jarSettings = null; | |
// load settings | |
jarSettings = getSettings(); | |
// Somehow the JarCreator needs to get this | |
jarCreator.setRootPath(getRootPath()); | |
super.postProcessBundleContext(context); | |
} | |
} |