package org.infinispan.it.osgi.util; import static org.ops4j.pax.exam.CoreOptions.composite; import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.maven; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.streamBundle; import static org.ops4j.pax.exam.CoreOptions.systemProperty; import static org.ops4j.pax.exam.CoreOptions.vmOptions; import static org.ops4j.pax.exam.CoreOptions.wrappedBundle; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.jar.Attributes; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationConsoleOption; import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel; import org.ops4j.pax.exam.options.AbstractUrlProvisionOption; import org.ops4j.pax.exam.options.MavenUrlReference; import org.ops4j.pax.exam.options.UrlProvisionOption; import org.ops4j.pax.exam.options.WrappedUrlProvisionOption; public class IspnKarafOptions { private static final String PROP_VERSION_KARAF = "version.karaf"; private static final String PROP_VERSION_PAX_EXAM = "version.pax.exam"; private static final String PROP_VERSION_MOCKITO = "version.mockito"; private static final String PROP_VERSION_OBJENESIS = "version.mockito_dep.objenesis"; private static final String PROP_VERSION_BYTEBUDDY = "version.mockito_dep.bytebuddy"; private static final String PROP_VERBOSE_KARAF = "verbose.karaf"; private static final String PROP_UBER_JAR = "uberjar"; private static Pattern PATTERN_HEADER = Pattern.compile("(.+)=(.+)"); static { /* PAX URL calls are made in the junit driver in addition to the container * and this is required for the in-driver calls to find custom local repo * locations. */ PaxURLUtils.configureLocalMavenRepo(); } public static String karafVersion() throws Exception { String karafVersion = System.getProperty(PROP_VERSION_KARAF); if (karafVersion == null) { karafVersion = MavenUtils.getProperties().getProperty(PROP_VERSION_KARAF); } return karafVersion; } public static Option verboseKaraf() { Option result = null; if (Boolean.parseBoolean(System.getProperty(PROP_VERBOSE_KARAF))) { result = logLevel(LogLevel.TRACE); } return result; } public static Option runWithoutConsole() { return new KarafDistributionConfigurationConsoleOption(false, false); } public static Option karafContainer() throws Exception { String karafVersion = karafVersion(); return karafDistributionConfiguration() .frameworkUrl( maven().groupId("org.apache.karaf").artifactId("apache-karaf").type("tar.gz").version(karafVersion)) /* The deploy folder doesn't guarantee that dependencies will be available before the probe runs. */ .useDeployFolder(false) .karafVersion(karafVersion).unpackDirectory(new File("target/pax")); } public static Option featureIspnCore() { return mvnFeature("org.infinispan", "infinispan-core", "infinispan-core"); } public static Option featureIspnCoreAndTests() throws Exception { return composite(featureIspnCore(), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-core", "org.infinispan.core")); } public static Option featureRocksDBJNI() { return mvnFeature("org.infinispan", "infinispan-cachestore-rocksdb", "infinispan-cachestore-rocksdb"); } public static Option featureRemoteStore() { return mvnFeature("org.infinispan", "infinispan-cachestore-remote", "infinispan-cachestore-remote"); } public static Option featureJdbcStore() { return mvnFeature("org.infinispan", "infinispan-cachestore-jdbc", "infinispan-cachestore-jdbc"); } public static Option featureJdbcStoreAndTests() throws Exception { return composite(featureJdbcStore(), bundleTestNG(), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-cachestore-jdbc", "org.infinispan.cachestore-jdbc")); } public static Option bundleTestNG() { return mavenBundle().groupId("org.testng").artifactId("testng").versionAsInProject(); } public static Option bundleLog4J() { return composite( mavenBundle().groupId("org.apache.logging.log4j").artifactId("log4j-api").versionAsInProject(), mavenBundle().groupId("org.apache.logging.log4j").artifactId("log4j-core").versionAsInProject() ); } public static Option bundleTestAnnotations() { return wrappedBundle(mavenBundle().groupId("org.infinispan").artifactId("infinispan-commons-test").versionAsInProject().getURL()); } public static Option featureJpaStore() { return mvnFeature("org.infinispan", "infinispan-cachestore-jpa", "infinispan-cachestore-jpa"); } public static Option featureJpaStoreAndTests() throws Exception { return composite(featureJpaStore(), bundleMockito(), mavenBundle().groupId("org.testng").artifactId("testng").versionAsInProject(), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-cachestore-jpa", "org.infinispan.cachestore-jpa")); } public static Option featureEmbeddedUberJarAndTests() throws Exception { return composite(mvnFeature("org.infinispan", "infinispan-embedded", "infinispan-embedded"), mvnFeature("org.infinispan", "infinispan-embedded", "c3p0"), mvnFeature("org.infinispan", "infinispan-embedded", "hikaricp"), mvnFeature("org.infinispan", "infinispan-embedded", "hibernate"), mvnFeature("org.infinispan", "infinispan-embedded", "rocksdb"), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-core", "org.infinispan.embedded"), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-cachestore-jdbc", "org.infinispan.embedded"), mvnTestsAsFragmentBundle("org.infinispan", "infinispan-cachestore-jpa", "org.infinispan.embedded")); } public static Option bundleMockito() throws Exception { String versionMockito = MavenUtils.getProperties().getProperty(PROP_VERSION_MOCKITO); String versionObjenesis = MavenUtils.getProperties().getProperty(PROP_VERSION_OBJENESIS); String versionByteBuddy = MavenUtils.getProperties().getProperty(PROP_VERSION_BYTEBUDDY); return composite( mavenBundle().groupId("org.objenesis").artifactId("objenesis").version(versionObjenesis), mavenBundle().groupId("org.mockito").artifactId("mockito-core").version(versionMockito), mavenBundle().groupId("net.bytebuddy").artifactId("byte-buddy").version(versionByteBuddy), mavenBundle().groupId("net.bytebuddy").artifactId("byte-buddy-agent").version(versionByteBuddy)); } public static Option featureKarafJNDI() throws Exception { String karafVersion = karafVersion(); String groupId = String.format("org.apache.karaf.%sfeatures", karafVersion.startsWith("2") ? "assemblies." : ""); return features(maven().groupId(groupId).artifactId("enterprise").type("xml") .classifier("features").version(karafVersion), "jndi"); } public static Option bundleH2Database() { return composite( mavenBundle().groupId("com.h2database").artifactId("h2").versionAsInProject(), mavenBundle().groupId("org.osgi").artifactId("org.osgi.enterprise").version("4.2.0")); } public static Option mvnFeature(String groupId, String artifactId, String feature) { return features(maven().groupId(groupId).artifactId(artifactId).type("xml") .classifier("features").versionAsInProject(), feature); } private static UrlProvisionOption testJarAsStreamBundle(String groupId, String artifactId) throws Exception { return asStreamBundle(maven().groupId(groupId).artifactId(artifactId).type("jar").classifier("tests").versionAsInProject().getURL()); } /** * Wraps the specified test jars as bundles fragments and attaches them to the specified host bundle. The host bundle * must be the one exporting the packages contained in the test jar. * * @param groupId * @param artifactId * @param hostBundle * @return * @throws Exception */ public static WrappedUrlProvisionOption mvnTestsAsFragmentBundle(String groupId, String artifactId, String hostBundle, String... instructions) throws Exception { PaxURLUtils.registerURLHandlers(); UrlProvisionOption testBundle = asStreamBundle(testJarAsStreamBundle(groupId, artifactId), "assembly:%s!/!org/infinispan/test/fwk/**"); String[] allInstructions = Arrays.copyOf(instructions, instructions.length + 1); allInstructions[instructions.length] = String.format("Fragment-Host=%s", hostBundle); return wrappedBundle(testBundle).instructions(allInstructions); } public static UrlProvisionOption emptyBundle(String... headers) throws IOException { Manifest manifest = new Manifest(); Attributes mainAttributes = manifest.getMainAttributes(); mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); mainAttributes.putValue("Bundle-ManifestVersion", "2"); for (String header : headers) { Matcher matcher = PATTERN_HEADER.matcher(header); if (!matcher.matches()) { throw new IllegalArgumentException(String.format("Invalid header: %s (expecting '%s')", header, PATTERN_HEADER.pattern())); } mainAttributes.putValue(matcher.group(1), matcher.group(2)); } ByteArrayOutputStream buf = new ByteArrayOutputStream(); JarOutputStream jar = new JarOutputStream(buf, manifest); jar.close(); return streamBundle(new ByteArrayInputStream(buf.toByteArray())); } /** * Some test packages are split across several Maven modules this option repackages them and exposes them through a * single bundle. * * @return * @throws Exception */ public static Option bundleSplitTestPackages() throws Exception { PaxURLUtils.registerURLHandlers(); UrlProvisionOption splitCoreBundle = asStreamBundle( testJarAsStreamBundle("org.infinispan", "infinispan-core"), "assembly:%s!/org/infinispan/test/fwk/**"); UrlProvisionOption splitJDBCBundle = asStreamBundle( testJarAsStreamBundle("org.infinispan", "infinispan-cachestore-jdbc"), "assembly:%s!/org/infinispan/test/fwk/**"); WrappedUrlProvisionOption wrappedSplitCoreBundle = wrappedBundle(splitCoreBundle) .bundleSymbolicName("split-test-core") .instructions("Export-Package=org.infinispan.test.fwk;partial=true;mandatory:=partial"); WrappedUrlProvisionOption wrappedSplitJDBCBundle = wrappedBundle(splitJDBCBundle) .bundleSymbolicName("split-test-jdbc") .instructions("Export-Package=org.infinispan.test.fwk;partial=true;mandatory:=partial"); UrlProvisionOption wrappedSplitTestBundle = emptyBundle( "Bundle-SymbolicName=split-test", "Export-Package=org.infinispan.test.fwk", "Require-Bundle=split-test-core,split-test-jdbc"); return composite(wrappedSplitCoreBundle, wrappedSplitJDBCBundle, wrappedSplitTestBundle); } public static UrlProvisionOption asStreamBundle(AbstractUrlProvisionOption<?> option, String newURLFormat, String... args) throws MalformedURLException, IOException { return asStreamBundle(option.getURL(), newURLFormat, args); } public static UrlProvisionOption asStreamBundle(String url) throws MalformedURLException, IOException { return asStreamBundle(url, "%s"); } /** * Some PAX-URL protocols are not supported by Karaf. This method can be used when one of the unsupported protocol is * required. The URLs are resolved outside Karaf and the bundles are provided as stream bundles. * * @param newURLFormat * @param args * @return * @throws MalformedURLException * @throws IOException */ public static UrlProvisionOption asStreamBundle(String url, String newURLFormat, String... args) throws MalformedURLException, IOException { InputStream in = new URL(String.format(newURLFormat, url, args)).openStream(); try { return streamBundle(in); } finally { try { in.close(); } catch (IOException ex) { } } } /** * PAX URL needs to know the location of the local maven repo to resolve mvn: URLs. When running the tests on the CI * machine TeamCity passes a custom local repo location using -Dmaven.repo.local to isolate the build targets and PAX * URL is not aware there's a custom repo to be used and tries to load from the default local repo location. * <p/> * This option will pass the location specified using -Dmaven.repo.local to the appropriate system property of the * container. * * @return an Option or null if no custom repo location is specified by the maven build. * @throws Exception */ public static Option localRepoForPAXUrl() throws Exception { String localRepo = MavenUtils.getLocalRepository(); if (localRepo == null) { return null; } return composite(systemProperty(PaxURLUtils.PROP_PAX_URL_LOCAL_REPO).value(localRepo), editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", PaxURLUtils.PROP_PAX_URL_LOCAL_REPO, localRepo)); } /** * Sets the system variables used inside persistence.xml to use H2. */ public static Option hibernatePersistenceH2() { return composite(systemProperty("connection.url").value("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"), systemProperty("driver.class").value("org.h2.Driver")); } public static Option bundlePaxExamSpi() throws Exception { String version = MavenUtils.getProperties().getProperty(PROP_VERSION_PAX_EXAM); return wrappedBundle(mavenBundle().groupId("org.ops4j.pax.exam").artifactId("pax-exam-spi").version(version)); } public static Option commonOptions() throws Exception { return composite(karafContainer(), vmOptions("-Djava.net.preferIPv4Stack=true", "-Djgroups.bind_addr=127.0.0.1"), verboseKaraf(), runWithoutConsole(), junitBundles(), keepRuntimeFolder(), /* Required for the @Category(Per{Suite,Class,Method}) annotations. */ bundlePaxExamSpi(), bundleTestAnnotations(), localRepoForPAXUrl()); } public static Option perSuiteOptions() throws Exception { if (!useUberJar()) { return composite(commonOptions(), featureKarafJNDI(), featureIspnCoreAndTests(), featureJdbcStoreAndTests(), featureJpaStoreAndTests(), featureRocksDBJNI(), featureRemoteStore(), bundleH2Database(), bundleLog4J(), hibernatePersistenceH2(), bundleSplitTestPackages()); } else { return composite(commonOptions(), featureKarafJNDI(), featureEmbeddedUberJarAndTests(), bundleSplitTestPackages(), bundleH2Database(), hibernatePersistenceH2(), bundleLog4J(), bundleTestNG(), bundleMockito()); } } /* Run tests with uberjar by default */ private static boolean useUberJar() throws Exception { String uberJar = System.getProperty(PROP_UBER_JAR); return uberJar == null ? true : Boolean.parseBoolean(uberJar); } }