Author: bdelacretaz Date: Wed Nov 6 14:39:42 2013 New Revision: 1539351 URL: http://svn.apache.org/r1539351 Log: Sling pax utilities - SlingRepositoryTest demonstrates a simple launchpad-based test
Added: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java (with props) sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingSetupTest.java - copied, changed from r1538561, sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingBundlesTest.java Removed: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingBundlesTest.java Modified: sling/whiteboard/bdelacretaz/sling-pax-util/pom.xml sling/whiteboard/bdelacretaz/sling-pax-util/src/main/java/org/apache/sling/paxexam/util/SlingPaxOptions.java Modified: sling/whiteboard/bdelacretaz/sling-pax-util/pom.xml URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/sling-pax-util/pom.xml?rev=1539351&r1=1539350&r2=1539351&view=diff ============================================================================== --- sling/whiteboard/bdelacretaz/sling-pax-util/pom.xml (original) +++ sling/whiteboard/bdelacretaz/sling-pax-util/pom.xml Wed Nov 6 14:39:42 2013 @@ -105,6 +105,30 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.api</artifactId> + <version>2.4.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.jcr.api</artifactId> + <version>2.1.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.settings</artifactId> + <version>1.3.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.jcr</groupId> + <artifactId>jcr</artifactId> + <version>2.0</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> Modified: sling/whiteboard/bdelacretaz/sling-pax-util/src/main/java/org/apache/sling/paxexam/util/SlingPaxOptions.java URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/sling-pax-util/src/main/java/org/apache/sling/paxexam/util/SlingPaxOptions.java?rev=1539351&r1=1539350&r2=1539351&view=diff ============================================================================== --- sling/whiteboard/bdelacretaz/sling-pax-util/src/main/java/org/apache/sling/paxexam/util/SlingPaxOptions.java (original) +++ sling/whiteboard/bdelacretaz/sling-pax-util/src/main/java/org/apache/sling/paxexam/util/SlingPaxOptions.java Wed Nov 6 14:39:42 2013 @@ -16,7 +16,9 @@ */ package org.apache.sling.paxexam.util; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -25,6 +27,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.ServerSocket; import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -33,14 +36,55 @@ import org.apache.sling.maven.projectsup import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.Bundle; import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.BundleList; import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.StartLevel; +import org.ops4j.pax.exam.CoreOptions; import org.ops4j.pax.exam.options.CompositeOption; import org.ops4j.pax.exam.options.DefaultCompositeOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** Pax exam options utilities for Sling */ +/** Pax exam options and utilities to test Sling applications + * The basic idea is to get a vanilla Sling launchpad instance + * setup with a minimal amount of boilerplate code. + * See {@link SlingSetupTest} for an example. + * */ public class SlingPaxOptions { private static final Logger log = LoggerFactory.getLogger(SlingPaxOptions.class); + public static final int DEFAULT_SLING_START_LEVEL = 30; + public static final String PROP_TELNET_PORT = "osgi.shell.telnet.port"; + public static final String PROP_HTTP_PORT = "org.osgi.service.http.port"; + + private static int getAvailablePort() { + int result = Integer.MIN_VALUE; + try { + final ServerSocket s = new ServerSocket(0); + result = s.getLocalPort(); + s.close(); + } catch(IOException ignore) { + } + return result; + } + + public static CompositeOption defaultLaunchpadOptions() { + final String paxLogLevel = System.getProperty("pax.exam.log.level", "INFO"); + + final int slingStartLevel = DEFAULT_SLING_START_LEVEL; + final String telnetPort = System.getProperty(PROP_TELNET_PORT, String.valueOf(getAvailablePort())); + final String httpPort = System.getProperty(PROP_HTTP_PORT, String.valueOf(getAvailablePort())); + + log.info("{}={}", PROP_TELNET_PORT, telnetPort); + log.info("{}={}", PROP_HTTP_PORT, httpPort); + + return new DefaultCompositeOption( + junitBundles(), + systemProperty( "org.ops4j.pax.logging.DefaultServiceLog.level" ).value(paxLogLevel), + SlingPaxOptions.felixRemoteShellBundles(), + SlingPaxOptions.slingBootstrapBundles(), + SlingPaxOptions.slingLaunchpadBundles(null), + CoreOptions.frameworkStartLevel(slingStartLevel), + CoreOptions.frameworkProperty(PROP_TELNET_PORT).value(telnetPort), + CoreOptions.frameworkProperty(PROP_HTTP_PORT).value(httpPort) + ); + } public static CompositeOption slingBundleList(String groupId, String artifactId, String version, String type, String classifier) { @@ -67,7 +111,10 @@ public class SlingPaxOptions { final BundleList list = BundleListUtils.readBundleList(tmp); int counter = 0; for(StartLevel s : list.getStartLevels()) { - final int startLevel = s.getStartLevel(); + + // Start level < 0 means bootstrap in our bundle lists + final int startLevel = s.getStartLevel() < 0 ? 1 : s.getStartLevel(); + for(Bundle b : s.getBundles()) { counter++; @@ -77,6 +124,12 @@ public class SlingPaxOptions { KNOWN_FRAGMENTS.add("org.apache.sling.extensions.webconsolebranding"); final boolean isFragment = b.getArtifactId().contains("fragment") || KNOWN_FRAGMENTS.contains(b.getArtifactId()); + // TODO need to handle sling run modes + if(b.getArtifactId().contains("oak")) { + log.warn("Ignoring bundle due to hard-coded TODO condition: {}", b.getArtifactId()); + continue; + } + if(isFragment) { result.add(mavenBundle(b.getGroupId(), b.getArtifactId(), b.getVersion()).noStart()); } else if(startLevel == 0){ @@ -113,6 +166,17 @@ public class SlingPaxOptions { return slingBundleList("org.apache.sling", "org.apache.sling.launchpad", version, "xml", "bundlelist"); } + /** @param version can be null, to use default */ + public static CompositeOption felixRemoteShellBundles() { + final String gogoVersion = "0.10.0"; + return new DefaultCompositeOption( + mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.gogo.runtime").version(gogoVersion), + mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.gogo.shell").version(gogoVersion), + mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.gogo.command").version(gogoVersion), + mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.shell.remote").version("1.1.2") + ); + } + private static File dumpMvnUrlToTmpFile(String mvnUrl) throws IOException { final URL url = new URL(mvnUrl); final InputStream is = new BufferedInputStream(url.openStream()); @@ -135,4 +199,4 @@ public class SlingPaxOptions { return tmp; } -} +} \ No newline at end of file Added: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java?rev=1539351&view=auto ============================================================================== --- sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java (added) +++ sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java Wed Nov 6 14:39:42 2013 @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.paxexam.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import javax.inject.Inject; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.sling.jcr.api.SlingRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +/** Verify that our tests have access to a functional Sling instance, + * and demonstrate how a simple test is setup + */ +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class SlingRepositoryTest { + @Inject + private SlingRepository repository; + + @org.ops4j.pax.exam.Configuration + public Option[] config() { + return SlingPaxOptions.defaultLaunchpadOptions().getOptions(); + } + + @Test + public void testNameDescriptor() { + assertEquals("Jackrabbit", repository.getDescriptor("jcr.repository.name")); + } + + @Test + public void testLogin() throws RepositoryException { + final Session s = repository.loginAdministrative(null); + try { + assertNotNull(s); + } finally { + s.logout(); + } + } + } \ No newline at end of file Propchange: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingRepositoryTest.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Copied: sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingSetupTest.java (from r1538561, sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingBundlesTest.java) URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingSetupTest.java?p2=sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingSetupTest.java&p1=sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingBundlesTest.java&r1=1538561&r2=1539351&rev=1539351&view=diff ============================================================================== --- sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingBundlesTest.java (original) +++ sling/whiteboard/bdelacretaz/sling-pax-util/src/test/java/org/apache/sling/paxexam/util/SlingSetupTest.java Wed Nov 6 14:39:42 2013 @@ -19,94 +19,64 @@ package org.apache.sling.paxexam.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; -import static org.ops4j.pax.exam.CoreOptions.junitBundles; -import static org.ops4j.pax.exam.CoreOptions.options; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import javax.inject.Inject; -import org.apache.sling.launchpad.api.StartupListener; -import org.apache.sling.launchpad.api.StartupMode; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +/** Verify that we get a working Sling launchpad with what SlingPaxOptions provide */ @RunWith(PaxExam.class) -public class SlingBundlesTest { - - private final Logger log = LoggerFactory.getLogger(getClass()); +@ExamReactorStrategy(PerClass.class) +public class SlingSetupTest { @Inject private BundleContext bundleContext; @org.ops4j.pax.exam.Configuration public Option[] config() { - final String paxLogLevel = System.getProperty("pax.exam.log.level", "INFO"); - - return options( - junitBundles(), - systemProperty( "org.ops4j.pax.logging.DefaultServiceLog.level" ).value(paxLogLevel), - SlingPaxOptions.slingBootstrapBundles(), - SlingPaxOptions.slingLaunchpadBundles(null) - ); + return SlingPaxOptions.defaultLaunchpadOptions().getOptions(); } + private void assertBundleActive(String symbolicName) { + assertEquals("Expecting bundle to be active:" + symbolicName, Bundle.ACTIVE, getBundleState(symbolicName)); + } + private boolean isFragment(Bundle b) { return b.getHeaders().get("Fragment-Host") != null; } - private void assertBundleActive(String symbolicName) { - Bundle b = null; - for(Bundle x : bundleContext.getBundles()) { - if(symbolicName.equals(x.getSymbolicName())) { - b = x; - break; - } - } - assertNotNull("Expecting bundle " + symbolicName + " to be present", b); - if(!isFragment(b)) { - assertEquals("Expecting bundle " + symbolicName + " to be active", Bundle.ACTIVE, b.getState()); - } - } - - @Before - public void startAllBundles() { - final List<String> notStarted = new LinkedList<String>(); - int lastNotStarted = Integer.MAX_VALUE; - - while(true) { - notStarted.clear(); - for(Bundle b : bundleContext.getBundles()) { - if(!isFragment(b) && b.getState() != Bundle.ACTIVE) { - notStarted.add(b.getSymbolicName()); - try { - b.start(); - } catch(Exception e) { - fail("Cannot start Bundle " + b.getSymbolicName() + ": " + e); - } - } - } - - if(notStarted.isEmpty()) { - break; - } - - if(!notStarted.isEmpty() && notStarted.size() >= lastNotStarted) { - log.error("No bundles started in the last cycle, inactive bundles={}", notStarted); - break; - } - lastNotStarted = notStarted.size(); + private Bundle getBundle(String symbolicName) { + for(Bundle b : bundleContext.getBundles()) { + if(symbolicName.equals(b.getSymbolicName())) { + return b; + } + } + return null; + } + /** @return bundle state, UNINSTALLED if absent */ + private int getBundleState(String symbolicName) { + return getBundleState(getBundle(symbolicName)); + } + + /** @return bundle state, UNINSTALLED if absent, ACTIVE */ + private int getBundleState(Bundle b) { + if(b == null) { + return Bundle.UNINSTALLED; + } else if(isFragment(b)) { + return Bundle.ACTIVE; + } else { + return b.getState(); } } @@ -143,12 +113,10 @@ public class SlingBundlesTest { "org.apache.sling.extensions.threaddump", "org.apache.sling.extensions.webconsolebranding", "org.apache.sling.extensions.webconsolesecurityprovider", - "org.apache.sling.fragment.activation", "org.apache.sling.fragment.transaction", "org.apache.sling.fragment.ws", "org.apache.sling.fragment.xml", "org.apache.sling.fsresource", - "org.apache.sling.installer.api", "org.apache.sling.installer.console", "org.apache.sling.installer.core", "org.apache.sling.installer.factory.configuration", @@ -182,84 +150,41 @@ public class SlingBundlesTest { "org.apache.sling.settings" }; + final List<String> missing = new ArrayList<String>(); for(String bundleName : bundles) { - assertBundleActive(bundleName); + final int state = getBundleState(bundleName); + if(state != Bundle.ACTIVE) { + missing.add(bundleName + " (state=" + state + ")"); + } + } + + if(!missing.isEmpty()) { + fail("Some required bundles are missing or inactive:" + missing); } } @Test public void testSlingServices() { + assertBundleActive("org.apache.sling.commons.mime"); + assertBundleActive("org.apache.sling.engine"); - class LocalStartupListener implements StartupListener { - - boolean testsHaveRun; - - public void inform(StartupMode m, boolean finished) { - log.info("inform(finished={})", finished); - if(finished) { - runTests(); - } - } - - public void startupFinished(StartupMode m) { - log.info("Startup finished"); - runTests(); - } - - public void startupProgress(float f) { - log.info("Startup progress {}", f); - } - - void runTests() { - if(!testsHaveRun) { - testsHaveRun = true; - } - - try { - assertBundleActive("org.apache.sling.commons.mime"); - assertBundleActive("org.apache.sling.engine"); - - final String [] services = { - "org.apache.sling.commons.mime.MimeTypeService", - "org.apache.sling.engine.SlingRequestProcessor" - }; - - for(String svc : services) { - final ServiceReference<?> ref = bundleContext.getServiceReference(svc); - assertNotNull("Expecting " + svc + " to be available", ref); - bundleContext.ungetService(ref); - } - } finally { - log.info("Done running tests"); - synchronized (this) { - notify(); - } - } - } + final String [] services = { + "org.apache.sling.engine.SlingRequestProcessor", + "org.apache.sling.commons.mime.MimeTypeService", + "org.apache.sling.jcr.api.SlingRepository" }; - - final LocalStartupListener s = new LocalStartupListener(); - s.runTests(); - - /* - // TODO generalize this "wait for Sling startup" - assuming we really need it - final ServiceRegistration<?> reg = bundleContext.registerService(StartupListener.class.getName(), s, null); - final long timeout = 5000L; - try { - synchronized (s) { - log.info("Waiting for {} to be done running tests", s); - s.wait(timeout); + final List<String> missing = new ArrayList<String>(); + for(String svc : services) { + final ServiceReference<?> ref = bundleContext.getServiceReference(svc); + if(ref == null) { + missing.add(svc); + } else { + bundleContext.ungetService(ref); } - } catch(InterruptedException ignored) { - fail("InterruptedException waiting tests to be executed"); - } finally { - reg.unregister(); } - - if(!s.testsHaveRun) { - fail("Timeout waiting for tests to run, after " + timeout + " msec"); + if(!missing.isEmpty()) { + fail("Some required services are missing:" + missing); } - */ } } \ No newline at end of file