You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2016/04/29 16:01:27 UTC
svn commit: r1741631 [1/2] - in /sling/trunk/testing/serversetup: ./ src/
src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/sling/ src/main/java/org/apache/sling/testing/
src/main/java/org/apache/sling/testi...
Author: bdelacretaz
Date: Fri Apr 29 14:01:27 2016
New Revision: 1741631
URL: http://svn.apache.org/viewvc?rev=1741631&view=rev
Log:
SLING-5703 - new serversetup module extracted from testing/tools. Contributed by Andrei Dulvac, thanks!
Added:
sling/trunk/testing/serversetup/ (with props)
sling/trunk/testing/serversetup/pom.xml
sling/trunk/testing/serversetup/src/
sling/trunk/testing/serversetup/src/main/
sling/trunk/testing/serversetup/src/main/java/
sling/trunk/testing/serversetup/src/main/java/org/
sling/trunk/testing/serversetup/src/main/java/org/apache/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetup.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetupSingleton.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/SetupPhase.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/StartRunnableJarPhase.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstance.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceManager.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceState.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstancesRule.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingTestBase.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/package-info.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/JarExecutor.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/ShutdownHookSingleProcessDestroyer.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/package-info.java
sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/package-info.java
sling/trunk/testing/serversetup/src/test/
sling/trunk/testing/serversetup/src/test/java/
sling/trunk/testing/serversetup/src/test/java/org/
sling/trunk/testing/serversetup/src/test/java/org/apache/
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/ServerSetupSingletonTest.java
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/TestServerSetup.java
sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/TestSetupPhase.java
Propchange: sling/trunk/testing/serversetup/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Apr 29 14:01:27 2016
@@ -0,0 +1,19 @@
+target
+sling
+bin
+logs
+jackrabbit-repository
+derby.log
+*.iml
+*.ipr
+*.iws
+.settings
+.project
+.classpath
+.externalToolBuilders
+maven-eclipse.xml
+jackrabbit
+
+
+
+
Added: sling/trunk/testing/serversetup/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/pom.xml?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/pom.xml (added)
+++ sling/trunk/testing/serversetup/pom.xml Fri Apr 29 14:01:27 2016
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>25</version>
+ <relativePath/>
+ </parent>
+
+ <artifactId>org.apache.sling.testing.serversetup</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Server Setup Tools</name>
+ <description>
+ Sling Server Setup utilities.
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/serversetup</connection>
+ <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/serversetup</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/testing/serversetup</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.sling.testing.serversetup.*,
+ org.apache.sling.testing.serversetup.jarexec,
+ org.apache.sling.testing.serversetup.instance
+ </Export-Package>
+ <Import-Package>
+ org.apache.commons.exec.*; resolution:=optional,
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.tools</artifactId>
+ <version>1.0.12</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-exec</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.5.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.5.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+</project>
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetup.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetup.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetup.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetup.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,260 @@
+/*
+ * 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.testing.serversetup;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import junit.framework.AssertionFailedError;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/** This is an evolution of the SlingTestBase/JarExecutor
+ * combination that we had at revision 1201491, used
+ * to control the server side of integration tests.
+ *
+ * This class allows a number of startup and shutdown phases
+ * to be defined, and executes some or all of them in a specified
+ * order, according to a property which lists their names.
+ *
+ * Flexibility in those startup/shutdown phases allows for
+ * creating test scenarios like automated testing of
+ * system upgrades, where you would for example:
+ *
+ * <pre>
+ * 1. Start the old runnable jar
+ * 2. Wait for it to be ready
+ * 3. Install some bundles and wait for them to be ready
+ * 4. Create some content in that version
+ * 5. Stop that jar
+ * 6. Start the new runnable jar
+ * 7. Wait for it to be ready
+ * 8. Run tests against that new jar to verify the upgrade
+ * </pre>
+ *
+ * Running the whole thing might take a long time, so when
+ * debugging the upgrade or the tests you might want to
+ * restart from a state saved at step 5, and only run steps
+ * 6 to 8, for example.
+ *
+ * Those steps are SetupPhase objects identified by
+ * their name, and specifying a partial list of names allows you
+ * to run only some of them in a given test run, speeding up
+ * development and troubleshooting as much as possible.
+ *
+ * TODO: the companion samples/integration-tests module
+ * should be updated to use this class to setup the Sling server
+ * that it tests, instead of the SlingTestBase class that it
+ * currently uses.
+ */
+public class ServerSetup {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /** Context that our SetupPhase objects can use to exchange data */
+ private final Map<String, Object> context = new HashMap<String, Object>();
+
+ private final List<String> phasesToRun = new ArrayList<String>();
+
+ /** Our configuration */
+ private Properties config;
+
+ /** Prefix used for our property names */
+ public static final String PROP_NAME_PREFIX = "server.setup";
+
+ /** Config property name: comma-separated list of phases to run */
+ public static final String PHASES_TO_RUN_PROP = PROP_NAME_PREFIX + ".phases";
+
+ /** Standard suffix for shutdown tasks IDs */
+ public static final String SHUTDOWN_ID_SUFFIX = ".shutdown";
+
+ /** Our SetupPhases, keyed by their id which must be unique */
+ private final Map<String, SetupPhase> phases = new HashMap<String, SetupPhase>();
+
+ /** List of phases that already ran */
+ private final Set<String> donePhases = new HashSet<String>();
+
+ /** List of phases that failed */
+ private final Set<String> failedPhases = new HashSet<String>();
+
+ /** Context attribute: server access URL */
+ public static final String SERVER_BASE_URL = "server.base.url";
+
+ /** Shutdown hook thread */
+ private Thread shutdownHook;
+
+ @SuppressWarnings("serial")
+ public static class SetupException extends Exception {
+ public SetupException(String reason) {
+ super(reason);
+ }
+
+ public SetupException(String reason, Throwable cause) {
+ super(reason, cause);
+ }
+ };
+
+ /** Runs all startup phases that have not run yet,
+ * and throws an Exception or call Junit's fail()
+ * method if one of them fails or failed in a
+ * previous call of this method.
+ *
+ * This can be called several times, will only run
+ * setup phases that have not run yet.
+ */
+ public synchronized void setupTestServer() throws Exception {
+
+ // On the first call, list our available phases
+ if(donePhases.isEmpty()) {
+ if(log.isInfoEnabled()) {
+ final List<String> ids = new ArrayList<String>();
+ ids.addAll(phases.keySet());
+ Collections.sort(ids);
+ log.info("Will run SetupPhases {} out of {}", phasesToRun, ids);
+ }
+ }
+
+ // Run all startup phases that didn't run yet
+ runRemainingPhases(true);
+
+ // And setup our shutdown hook
+ if(shutdownHook == null) {
+ shutdownHook = new Thread(getClass().getSimpleName() + "Shutdown") {
+ public void run() {
+ try {
+ shutdown();
+ } catch(Exception e) {
+ log.warn("Exception in shutdown hook", e);
+ }
+
+ }
+ };
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+ log.info("Shutdown hook added to run shutdown phases");
+ }
+ }
+
+ /** Run phases that haven't run yet */
+ private void runRemainingPhases(boolean isStartup) throws Exception {
+ final String mode = isStartup ? "startup" : "shutdown";
+
+ // In startup mode, fail if any phases failed previously
+ // (in shutdown mode it's probably safer to try to run cleanup phases)
+ if(isStartup && !failedPhases.isEmpty()) {
+ throw new SetupException("Some SetupPhases previously failed: " + failedPhases);
+ }
+
+ for(String id : phasesToRun) {
+ final SetupPhase p = phases.get(id);
+
+ if(donePhases.contains(id)) {
+ log.debug("SetupPhase ({}) with id {} already ran, ignored", mode, id);
+ continue;
+ }
+
+ if(p == null) {
+ log.info("SetupPhase ({}) with id {} not found, ignored", mode, id);
+ donePhases.add(id);
+ continue;
+ }
+
+ if(p.isStartupPhase() == isStartup) {
+ log.info("Executing {} phase: {}", mode, p);
+ try {
+ p.run(this);
+ } catch(Exception e) {
+ failedPhases.add(id);
+ throw e;
+ } catch (AssertionFailedError ae) {
+ // Some of our tools throw this, might not to avoid it in the future
+ failedPhases.add(id);
+ throw new Exception("AssertionFailedError in runRemainingPhases", ae);
+ } finally {
+ donePhases.add(id);
+ }
+ }
+ }
+ }
+
+ /** Called by a shutdown hook to run
+ * all shutdown phases, but can also
+ * be called explicitly, each shutdown
+ * phase only runs once anyway.
+ */
+ public void shutdown() throws Exception {
+ runRemainingPhases(false);
+ }
+
+ /** Return a context that {@SetupPhase} can use to
+ * communicate among them and with the outside.
+ */
+ public Map<String, Object> getContext() {
+ return context;
+ }
+
+ /** Set configuration and reset our lists of phases
+ * that already ran or failed.
+ */
+ public void setConfig(Properties props) {
+ config = props;
+
+ final String str = props.getProperty(PHASES_TO_RUN_PROP);
+ phasesToRun.clear();
+ final String [] phases = str == null ? new String [] {} : str.split(",");
+ for(int i=0 ; i < phases.length; i++) {
+ phases[i] = phases[i].trim();
+ }
+ phasesToRun.addAll(Arrays.asList(phases));
+
+ if(phasesToRun.isEmpty()) {
+ log.warn("No setup phases defined, {} is empty, is that on purpose?", PHASES_TO_RUN_PROP);
+ }
+
+ donePhases.clear();
+ failedPhases.clear();
+ }
+
+ /** Return the configuration Properties that were set
+ * by {@link #setConfig}
+ */
+ public Properties getConfig() {
+ return config;
+ }
+
+ /** Return the IDs of phases that should run */
+ public List<String> getPhasesToRun() {
+ return Collections.unmodifiableList(phasesToRun);
+ }
+
+ /** Add a SetupPhase to our list. Its ID must be
+ * unique in that list.
+ */
+ public void addSetupPhase(SetupPhase p) throws SetupException {
+ if(phases.containsKey(p.getId())) {
+ throw new SetupException("A SetupPhase with ID=" + p.getId() + " is already in our list:" + phases.keySet());
+ }
+ phases.put(p.getId(), p);
+ }
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetupSingleton.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetupSingleton.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetupSingleton.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/ServerSetupSingleton.java Fri Apr 29 14:01:27 2016
@@ -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.testing.serversetup;
+
+import java.util.Properties;
+
+/** In general we just need a singleton ServerSetup, that
+ * uses System properties for its configuration - this class
+ * supplies that.
+ */
+public class ServerSetupSingleton {
+
+ /** Property name of the ServerSetup class that we instantiate */
+ public static final String CLASS_NAME_PROP = ServerSetup.PROP_NAME_PREFIX + ".class.name";
+
+ private static ServerSetup instance;
+
+ /** Create an instance based on the {@CLASS_NAME_PROP)
+ * property if needed and return it.
+ *
+ * @param config Ignored unless an instance is created
+ */
+ public static ServerSetup instance(Properties config) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ if(instance == null) {
+ synchronized (ServerSetupSingleton.class) {
+ if(instance == null) {
+ final String className = config.getProperty(CLASS_NAME_PROP);
+ if(className == null) {
+ throw new IllegalArgumentException("Missing config property: " + CLASS_NAME_PROP);
+ }
+ instance = (ServerSetup)
+ ServerSetupSingleton.class.getClassLoader()
+ .loadClass(className)
+ .newInstance();
+ instance.setConfig(config);
+ }
+ }
+ }
+ return instance;
+ }
+
+ /** Same as no-parameter instance() method, but uses System properties
+ * to create its instance.
+ */
+ public static ServerSetup instance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return instance(System.getProperties());
+ }
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/SetupPhase.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/SetupPhase.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/SetupPhase.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/SetupPhase.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,32 @@
+/*
+ * 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.testing.serversetup;
+
+/** A single phase of the test server setup */
+public interface SetupPhase {
+ /** Run this phase in the context of supplied ServerSetup */
+ public void run(ServerSetup owner) throws Exception;
+
+ /** Is this a startup or shutdown phase? */
+ public boolean isStartupPhase();
+
+ /** Get the phase ID string, a list of those
+ * is used by {@link ServerSetup} to decide
+ * which phases to run
+ */
+ public String getId();
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/StartRunnableJarPhase.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/StartRunnableJarPhase.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/StartRunnableJarPhase.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/StartRunnableJarPhase.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,97 @@
+/*
+ * 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.testing.serversetup;
+
+import java.util.Properties;
+
+import org.apache.sling.testing.serversetup.jarexec.JarExecutor;
+import org.apache.sling.testing.serversetup.jarexec.JarExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** SetupPhase that uses a JarExecutor to start
+ * a runnable jar, and stop it at system shutdown
+ * if our SetupServer wants that.
+ */
+public class StartRunnableJarPhase implements SetupPhase {
+
+ public static final String TEST_SERVER_HOSTNAME = "test.server.hostname";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final String id;
+ private final String description;
+ private final JarExecutor executor;
+
+ public StartRunnableJarPhase(final ServerSetup owner, String id, String description, Properties config)
+ throws JarExecutor.ExecutorException {
+ this.id = id;
+ this.description = description;
+ executor = new JarExecutor(config);
+
+ String hostname = config.getProperty(TEST_SERVER_HOSTNAME);
+ if(hostname == null) {
+ hostname = "localhost";
+ }
+ final String url = "http://" + hostname + ":" + executor.getServerPort();
+ log.info("Server base URL={}", url);
+ owner.getContext().put(ServerSetup.SERVER_BASE_URL, url);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " (" + id + ") " + description;
+ }
+
+ /** @inheritDoc */
+ public void run(ServerSetup owner) throws Exception {
+ executor.start();
+ }
+
+ /** @inheritDoc */
+ public boolean isStartupPhase() {
+ return true;
+ }
+
+ /** @inheritDoc */
+ public String getId() {
+ return id;
+ }
+
+ /** Return a SetupPhase that kills the process started by this phase */
+ public SetupPhase getKillPhase(final String id) {
+ return new SetupPhase() {
+ public void run(ServerSetup owner) throws Exception {
+ executor.stop();
+ }
+
+ public boolean isStartupPhase() {
+ // This is not a shutdown phase, it's meant to
+ // use during startup to forcibly kill an instance
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Kill the process started by " + StartRunnableJarPhase.this;
+ }
+
+ public String getId() {
+ return id;
+ }
+ };
+ }
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstance.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstance.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstance.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstance.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,45 @@
+/*
+ * 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.testing.serversetup.instance;
+
+
+import org.apache.sling.testing.tools.http.RequestBuilder;
+import org.apache.sling.testing.tools.http.RequestExecutor;
+
+/**
+ * Interface used to communicate with a sling instance
+ */
+public interface SlingInstance {
+
+ /** Start server if needed, and return a RequestBuilder that points to it */
+ public RequestBuilder getRequestBuilder();
+
+
+ /** Start server if needed, and return its base URL */
+ public String getServerBaseUrl();
+
+
+ /** Return username configured for execution of HTTP requests */
+ public String getServerUsername();
+
+ /** Return password configured for execution of HTTP requests */
+ public String getServerPassword();
+
+
+ /** Returns a RequestExecutor for this server **/
+ public RequestExecutor getRequestExecutor();
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceManager.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceManager.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceManager.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,87 @@
+/*
+ * 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.testing.serversetup.instance;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Helper class for running tests against multiple Sling instances,
+ * takes care of starting the Sling instances and waiting for them to be ready.
+ */
+public class SlingInstanceManager implements Iterable<SlingInstance > {
+ private final Map<String, SlingInstance> slingTestInstances = new ConcurrentHashMap<String, SlingInstance>();
+
+ public SlingInstanceManager(String... instanceNames) {
+ this(System.getProperties(), instanceNames);
+ }
+
+ /** Get configuration but do not start server yet, that's done on demand */
+ public SlingInstanceManager(Properties systemProperties, String... instanceNames) {
+ if (instanceNames == null || instanceNames.length == 0) {
+ instanceNames = new String [] { SlingInstanceState.DEFAULT_INSTANCE_NAME };
+ }
+
+ for (String instanceName : instanceNames) {
+ Properties instanceProperties = removeInstancePrefix(systemProperties, instanceName);
+
+ SlingInstanceState state = SlingInstanceState.getInstance(instanceName);
+ SlingInstance instance = new SlingTestBase(state, instanceProperties);
+ slingTestInstances.put(instanceName, instance);
+ }
+ }
+
+
+ private Properties removeInstancePrefix(Properties properties, String instanceName) {
+ Properties result = new Properties();
+ for (Object propertyKey : properties.keySet()) {
+ Object propertyValue = properties.get(propertyKey);
+
+ if (propertyKey instanceof String) {
+ String propertyName = (String) propertyKey;
+ String instancePropertyName = null;
+ if (propertyName.startsWith(instanceName + ".")) {
+ instancePropertyName = propertyName.substring(instanceName.length()+1);
+ }
+
+ if (instancePropertyName != null) {
+ result.put(instancePropertyName, propertyValue);
+ }
+ else if (!result.containsKey(propertyName)) {
+ result.put(propertyName, propertyValue);
+ }
+ }
+ else {
+ result.put(propertyKey, propertyValue);
+
+ }
+ }
+
+ return result;
+ }
+
+
+ public SlingInstance getInstance(String instanceName) {
+ return slingTestInstances.get(instanceName);
+ }
+
+ public Iterator<SlingInstance> iterator() {
+ return slingTestInstances.values().iterator();
+ }
+}
\ No newline at end of file
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceState.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceState.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceState.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstanceState.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,143 @@
+/*
+ * 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.testing.serversetup.instance;
+
+import org.apache.sling.testing.serversetup.jarexec.JarExecutor;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+
+/**
+ * Information about a sling instance that is shared between tests.
+ */
+public class SlingInstanceState {
+
+ public static final String DEFAULT_INSTANCE_NAME = "default";
+
+ private String serverBaseUrl;
+ private boolean serverStarted;
+ private boolean serverReady;
+ private boolean serverReadyTestFailed;
+ private boolean installBundlesFailed;
+ private boolean extraBundlesInstalled;
+ private boolean startupInfoProvided;
+ private boolean serverInfoLogged;
+ private JarExecutor jarExecutor;
+
+ /**
+ * List of the urls of currently started servers
+ */
+ static Set<String> startedServersUrls = new CopyOnWriteArraySet<String>();
+
+ /**
+ * List of the instance names and states
+ */
+ private static final Map<String, SlingInstanceState> slingInstancesState = new HashMap<String, SlingInstanceState>();
+
+
+ public static synchronized SlingInstanceState getInstance(String instanceName) {
+ if (slingInstancesState.containsKey(instanceName)) {
+ return slingInstancesState.get(instanceName);
+ }
+ else {
+ slingInstancesState.put(instanceName, new SlingInstanceState());
+ }
+
+ return slingInstancesState.get(instanceName);
+ }
+
+
+ private SlingInstanceState() {
+
+ }
+
+ public boolean isServerStarted() {
+ return serverStarted;
+ }
+
+ public boolean setServerStarted(boolean serverStarted) {
+ this.serverStarted = serverStarted;
+ return startedServersUrls.add(serverBaseUrl);
+ }
+
+ public boolean isServerReady() {
+ return serverReady;
+ }
+
+ public void setServerReady(boolean serverReady) {
+ this.serverReady = serverReady;
+ }
+
+ public boolean isServerReadyTestFailed() {
+ return serverReadyTestFailed;
+ }
+
+ public void setServerReadyTestFailed(boolean serverReadyTestFailed) {
+ this.serverReadyTestFailed = serverReadyTestFailed;
+ }
+
+ public boolean isInstallBundlesFailed() {
+ return installBundlesFailed;
+ }
+
+ public void setInstallBundlesFailed(boolean installBundlesFailed) {
+ this.installBundlesFailed = installBundlesFailed;
+ }
+
+ public boolean isExtraBundlesInstalled() {
+ return extraBundlesInstalled;
+ }
+
+ public void setExtraBundlesInstalled(boolean extraBundlesInstalled) {
+ this.extraBundlesInstalled = extraBundlesInstalled;
+ }
+
+ public boolean isStartupInfoProvided() {
+ return startupInfoProvided;
+ }
+
+ public void setStartupInfoProvided(boolean startupInfoProvided) {
+ this.startupInfoProvided = startupInfoProvided;
+ }
+
+ public boolean isServerInfoLogged() {
+ return serverInfoLogged;
+ }
+
+ public void setServerInfoLogged(boolean serverInfoLogged) {
+ this.serverInfoLogged = serverInfoLogged;
+ }
+
+ public JarExecutor getJarExecutor() {
+ return jarExecutor;
+ }
+
+ public void setJarExecutor(JarExecutor jarExecutor) {
+ this.jarExecutor = jarExecutor;
+ }
+
+ public String getServerBaseUrl() {
+ return serverBaseUrl;
+ }
+
+ public void setServerBaseUrl(String serverBaseUrl) {
+ this.serverBaseUrl = serverBaseUrl;
+ }
+}
\ No newline at end of file
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstancesRule.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstancesRule.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstancesRule.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingInstancesRule.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,59 @@
+/*
+ * 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.testing.serversetup.instance;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit Rule that executes tests for multiple Sling instances.
+ */
+public class SlingInstancesRule implements TestRule {
+
+ private SlingInstance currentInstance;
+ private final Iterable<SlingInstance> instances;
+
+ public SlingInstancesRule(String ... instanceNames) {
+ this(new SlingInstanceManager(instanceNames));
+ }
+
+ public SlingInstancesRule(Iterable<SlingInstance> it) {
+ instances = it;
+ }
+
+ /** Evaluate our base statement once for every instance.
+ * Tests can use our getSlingInstance() method to access the current one.
+ * See MultipleOsgiConsoleTest example in the samples integration tests module.
+ */
+ public Statement apply(final Statement base, Description dest) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ for(SlingInstance instance : instances) {
+ currentInstance = instance;
+ base.evaluate();
+ }
+ currentInstance = null;
+ }
+ };
+ }
+
+ public SlingInstance getSlingInstance() {
+ return currentInstance;
+ }
+}
\ No newline at end of file
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingTestBase.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingTestBase.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingTestBase.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/SlingTestBase.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,406 @@
+/*
+ * 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.testing.serversetup.instance;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.sling.testing.tools.http.RequestBuilder;
+import org.apache.sling.testing.tools.http.RequestExecutor;
+import org.apache.sling.testing.tools.junit.TestDescriptionInterceptor;
+import org.apache.sling.testing.tools.osgi.WebconsoleClient;
+import org.apache.sling.testing.tools.sling.BundlesInstaller;
+import org.apache.sling.testing.tools.sling.TimeoutsProvider;
+import org.apache.sling.testing.serversetup.jarexec.JarExecutor;
+import org.junit.After;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.*;
+
+import static org.junit.Assert.fail;
+
+/** Base class for running tests against a Sling instance,
+ * takes care of starting Sling and waiting for it to be ready.
+ */
+public class SlingTestBase implements SlingInstance {
+ public static final String TEST_SERVER_URL_PROP = "test.server.url";
+ public static final String TEST_SERVER_USERNAME = "test.server.username";
+ public static final String TEST_SERVER_PASSWORD = "test.server.password";
+ public static final String SERVER_READY_TIMEOUT_PROP = "server.ready.timeout.seconds";
+ public static final String SERVER_READY_PROP_PREFIX = "server.ready.path";
+ public static final String KEEP_JAR_RUNNING_PROP = "keepJarRunning";
+ public static final String SERVER_HOSTNAME_PROP = "test.server.hostname";
+ public static final String ADDITONAL_BUNDLES_PATH = "additional.bundles.path";
+ public static final String ADDITONAL_BUNDLES_UNINSTALL = "additional.bundles.uninstall";
+ public static final String BUNDLE_TO_INSTALL_PREFIX = "sling.additional.bundle";
+ public static final String START_BUNDLES_TIMEOUT_SECONDS = "start.bundles.timeout.seconds";
+ public static final String BUNDLE_INSTALL_TIMEOUT_SECONDS = "bundle.install.timeout.seconds";
+ public static final String ADMIN = "admin";
+
+ private final boolean keepJarRunning;
+ private final boolean uninstallAdditionalBundles;
+ private final String serverUsername;
+ private final String serverPassword;
+ private final SlingInstanceState slingTestState;
+ private final Properties systemProperties;
+ private RequestBuilder builder;
+ private DefaultHttpClient httpClient = new DefaultHttpClient();
+ private RequestExecutor executor = new RequestExecutor(httpClient);
+ private WebconsoleClient webconsoleClient;
+ private BundlesInstaller bundlesInstaller;
+ private boolean serverStartedByThisClass;
+
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+
+ public SlingTestBase() {
+ this(SlingInstanceState.getInstance(SlingInstanceState.DEFAULT_INSTANCE_NAME),
+ System.getProperties());
+ }
+
+ /** Get configuration but do not start server yet, that's done on demand */
+ public SlingTestBase(SlingInstanceState slingTestState, Properties systemProperties) {
+ this.slingTestState = slingTestState;
+ this.systemProperties = systemProperties;
+ this.keepJarRunning = "true".equals(systemProperties.getProperty(KEEP_JAR_RUNNING_PROP));
+ this.httpClient.addRequestInterceptor(new TestDescriptionInterceptor());
+
+
+ final String configuredUrl = systemProperties.getProperty(TEST_SERVER_URL_PROP, systemProperties.getProperty("launchpad.http.server.url"));
+ if(configuredUrl != null && configuredUrl.trim().length() > 0) {
+ slingTestState.setServerBaseUrl(configuredUrl);
+ slingTestState.setServerStarted(true);
+ uninstallAdditionalBundles = "true".equals(systemProperties.getProperty(ADDITONAL_BUNDLES_UNINSTALL));
+ } else {
+ synchronized(this.slingTestState) {
+ try {
+ if(slingTestState.getJarExecutor() == null) {
+ slingTestState.setJarExecutor(new JarExecutor(systemProperties));
+ }
+ } catch(Exception e) {
+ log.error("JarExecutor setup failed", e);
+ fail("JarExecutor setup failed: " + e);
+ }
+ }
+ String serverHost = systemProperties.getProperty(SERVER_HOSTNAME_PROP);
+ if(serverHost == null || serverHost.trim().length() == 0) {
+ serverHost = "localhost";
+ }
+ slingTestState.setServerBaseUrl("http://" + serverHost + ":" + slingTestState.getJarExecutor().getServerPort());
+ uninstallAdditionalBundles = false; // never undeploy additional bundles in case the server is provisioned here!
+ }
+
+ // Set configured username using "admin" as default credential
+ final String configuredUsername = systemProperties.getProperty(TEST_SERVER_USERNAME);
+ if (configuredUsername != null && configuredUsername.trim().length() > 0) {
+ serverUsername = configuredUsername;
+ } else {
+ serverUsername = ADMIN;
+ }
+
+ // Set configured password using "admin" as default credential
+ final String configuredPassword = systemProperties.getProperty(TEST_SERVER_PASSWORD);
+ if (configuredPassword != null && configuredPassword.trim().length() > 0) {
+ serverPassword = configuredPassword;
+ } else {
+ serverPassword = ADMIN;
+ }
+
+ builder = new RequestBuilder(slingTestState.getServerBaseUrl());
+ webconsoleClient = new WebconsoleClient(slingTestState.getServerBaseUrl(), serverUsername, serverPassword);
+ builder = new RequestBuilder(slingTestState.getServerBaseUrl());
+ bundlesInstaller = new BundlesInstaller(webconsoleClient);
+
+ if(!slingTestState.isServerInfoLogged()) {
+ log.info("Server base URL={}", slingTestState.getServerBaseUrl());
+ slingTestState.setServerInfoLogged(true);
+ }
+ }
+
+ /**
+ * Automatically by the SlingRemoteTestRunner since package version 1.1.0.
+ */
+ @After
+ public void uninstallAdditionalBundlesIfNecessary() {
+ if (uninstallAdditionalBundles) {
+ log.info("Uninstalling additional bundles...");
+ uninstallAdditionalBundles();
+ }
+ }
+
+ /** Start the server, if not done yet */
+ private void startServerIfNeeded() {
+ try {
+ if(slingTestState.isServerStarted() && !serverStartedByThisClass && !slingTestState.isStartupInfoProvided()) {
+ log.info(TEST_SERVER_URL_PROP + " was set: not starting server jar (" + slingTestState.getServerBaseUrl() + ")");
+ }
+ if(!slingTestState.isServerStarted()) {
+ synchronized (slingTestState) {
+ if(!slingTestState.isServerStarted()) {
+ slingTestState.getJarExecutor().start();
+ serverStartedByThisClass = true;
+ if(!slingTestState.setServerStarted(true)) {
+ fail("A server is already started at " + slingTestState.getServerBaseUrl());
+ }
+ }
+ }
+ }
+ slingTestState.setStartupInfoProvided(true);
+ waitForServerReady();
+ installAdditionalBundles();
+ blockIfRequested();
+ } catch(Exception e) {
+ log.error("Exception in maybeStartServer()", e);
+ fail("maybeStartServer() failed: " + e);
+ }
+ }
+
+ protected void installAdditionalBundles() {
+ if(slingTestState.isInstallBundlesFailed()) {
+ fail("Bundles could not be installed, cannot run tests");
+ } else if(!slingTestState.isExtraBundlesInstalled()) {
+ final List<File> toInstall = getBundlesToInstall();
+ if (!toInstall.isEmpty()) {
+ try {
+ // Install bundles, check that they are installed and start them all
+ bundlesInstaller.installBundles(toInstall, false);
+ final List<String> symbolicNames = new LinkedList<String>();
+ for (File f : toInstall) {
+ symbolicNames.add(bundlesInstaller.getBundleSymbolicName(f));
+ }
+ bundlesInstaller.waitForBundlesInstalled(symbolicNames,
+ TimeoutsProvider.getInstance().getTimeout(BUNDLE_INSTALL_TIMEOUT_SECONDS, 10));
+ bundlesInstaller.startAllBundles(symbolicNames,
+ TimeoutsProvider.getInstance().getTimeout(START_BUNDLES_TIMEOUT_SECONDS, 30));
+ } catch(AssertionError ae) {
+ log.info("Exception while installing additional bundles", ae);
+ slingTestState.setInstallBundlesFailed(true);
+ } catch(Exception e) {
+ log.info("Exception while installing additional bundles", e);
+ slingTestState.setInstallBundlesFailed(true);
+ }
+ if(slingTestState.isInstallBundlesFailed()) {
+ fail("Could not start all installed bundles:" + toInstall);
+ }
+ } else {
+ log.info("Not installing additional bundles, probably System property {} not set",
+ ADDITONAL_BUNDLES_PATH);
+ }
+ }
+
+ slingTestState.setExtraBundlesInstalled(!slingTestState.isInstallBundlesFailed());
+ }
+
+ protected void uninstallAdditionalBundles() {
+ try {
+ // always uninstall independent of installation status
+ bundlesInstaller.uninstallBundles(getBundlesToInstall());
+ } catch (Exception e) {
+ log.info("Exception while uninstalling additional bundles", e);
+ }
+ }
+
+ /** Start server if needed, and return a RequestBuilder that points to it */
+ public RequestBuilder getRequestBuilder() {
+ startServerIfNeeded();
+ return builder;
+ }
+
+ /** Start server if needed, and return its base URL */
+ public String getServerBaseUrl() {
+ startServerIfNeeded();
+ return slingTestState.getServerBaseUrl();
+ }
+
+ /** Return username configured for execution of HTTP requests */
+ public String getServerUsername() {
+ return serverUsername;
+ }
+
+ /** Return password configured for execution of HTTP requests */
+ public String getServerPassword() {
+ return serverPassword;
+ }
+
+ /** Optionally block here so that the runnable jar stays up - we can
+ * then run tests against it from another VM.
+ */
+ protected void blockIfRequested() {
+ if (keepJarRunning) {
+ log.info(KEEP_JAR_RUNNING_PROP + " set to true - entering infinite loop"
+ + " so that runnable jar stays up. Kill this process to exit.");
+ synchronized (slingTestState) {
+ try {
+ slingTestState.wait();
+ } catch(InterruptedException iex) {
+ log.info("InterruptedException in blockIfRequested");
+ }
+ }
+ }
+ }
+
+ /** Check a number of server URLs for readyness */
+ protected void waitForServerReady() throws Exception {
+ if(slingTestState.isServerReady()) {
+ return;
+ }
+ if(slingTestState.isServerReadyTestFailed()) {
+ fail("Server is not ready according to previous tests");
+ }
+
+ // Timeout for readiness test
+ final String sec = systemProperties.getProperty(SERVER_READY_TIMEOUT_PROP);
+ final int timeoutSec = TimeoutsProvider.getInstance().getTimeout(sec == null ? 60 : Integer.valueOf(sec));
+ log.info("Will wait up to " + timeoutSec + " seconds for server to become ready");
+ final long endTime = System.currentTimeMillis() + timeoutSec * 1000L;
+
+ // Get the list of paths to test and expected content regexps
+ final List<String> testPaths = new ArrayList<String>();
+ final TreeSet<Object> propertyNames = new TreeSet<Object>();
+ propertyNames.addAll(systemProperties.keySet());
+ for(Object o : propertyNames) {
+ final String key = (String)o;
+ if(key.startsWith(SERVER_READY_PROP_PREFIX)) {
+ testPaths.add(systemProperties.getProperty(key));
+ }
+ }
+
+ // Consider the server ready if it responds to a GET on each of
+ // our configured request paths with a 200 result and content
+ // that contains the pattern that's optionally supplied with the
+ // path, separated by a colon
+ log.info("Checking that GET requests return expected content (timeout={} seconds): {}", timeoutSec, testPaths);
+ while(System.currentTimeMillis() < endTime) {
+ boolean errors = false;
+ for(String p : testPaths) {
+ final String [] s = p.split(":");
+ final String path = s[0];
+ final String pattern = (s.length > 0 ? s[1] : "");
+ try {
+ executor.execute(builder.buildGetRequest(path).withCredentials(serverUsername, serverPassword))
+ .assertStatus(200)
+ .assertContentContains(pattern);
+ } catch(AssertionError ae) {
+ errors = true;
+ log.debug("Request to {}@{}{} failed, will retry ({})",
+ new Object[] { serverUsername, slingTestState.getServerBaseUrl(), path, ae});
+ } catch(Exception e) {
+ errors = true;
+ log.debug("Request to {}@{}{} failed, will retry ({})",
+ new Object[] { serverUsername, slingTestState.getServerBaseUrl(), path, pattern, e });
+ }
+ }
+
+ if(!errors) {
+ slingTestState.setServerReady(true);
+ log.info("All {} paths return expected content, server ready", testPaths.size());
+ break;
+ }
+ Thread.sleep(TimeoutsProvider.getInstance().getTimeout(1000L));
+ }
+
+ if(!slingTestState.isServerReady()) {
+ slingTestState.setServerReadyTestFailed(true);
+ final String msg = "Server not ready after " + timeoutSec + " seconds, giving up";
+ log.info(msg);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Get the list of additional bundles to install, as specified by the system property {@link #ADDITONAL_BUNDLES_PATH}
+ * @return the list of {@link File}s pointing to the Bundle JARs or the empty list in case no additional bundles should be installed (never {@code null}).
+ */
+ protected List<File> getBundlesToInstall() {
+ final String paths = systemProperties.getProperty(ADDITONAL_BUNDLES_PATH);
+ if(paths == null) {
+ return Collections.emptyList();
+ }
+
+ final List<File> toInstall = new ArrayList<File>();
+ // Paths can contain a comma-separated list
+ final String [] allPaths = paths.split(",");
+ for(String path : allPaths) {
+ toInstall.addAll(getBundlesToInstall(path.trim()));
+ }
+ return toInstall;
+ }
+
+ /** Get the list of additional bundles to install, as specified by additionalBundlesPath parameter */
+ protected List<File> getBundlesToInstall(String additionalBundlesPath) {
+ final List<File> result = new LinkedList<File>();
+ if(additionalBundlesPath == null) {
+ return result;
+ }
+
+ final File dir = new File(additionalBundlesPath);
+ if(!dir.isDirectory() || !dir.canRead()) {
+ log.info("Cannot read additional bundles directory {}, ignored", dir.getAbsolutePath());
+ return result;
+ }
+
+ // Collect all filenames of candidate bundles
+ final List<String> bundleNames = new ArrayList<String>();
+ final String [] files = dir.list();
+ if(files != null) {
+ for(String file : files) {
+ if(file.endsWith(".jar")) {
+ bundleNames.add(file);
+ }
+ }
+ }
+
+ // We'll install those that are specified by system properties, in order
+ final List<String> sortedPropertyKeys = new ArrayList<String>();
+ for(Object key : systemProperties.keySet()) {
+ final String str = key.toString();
+ if(str.startsWith(BUNDLE_TO_INSTALL_PREFIX)) {
+ sortedPropertyKeys.add(str);
+ }
+ }
+ Collections.sort(sortedPropertyKeys);
+ for(String key : sortedPropertyKeys) {
+ final String filenamePrefix = systemProperties.getProperty(key);
+ for(String bundleFilename : bundleNames) {
+ if(bundleFilename.startsWith(filenamePrefix)) {
+ result.add(new File(dir, bundleFilename));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public boolean isServerStartedByThisClass() {
+ return serverStartedByThisClass;
+ }
+
+ public HttpClient getHttpClient() {
+ return httpClient;
+ }
+
+ public RequestExecutor getRequestExecutor() {
+ return executor;
+ }
+
+ public WebconsoleClient getWebconsoleClient() {
+ startServerIfNeeded();
+ return webconsoleClient;
+ }
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/package-info.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/package-info.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/instance/package-info.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@Version("1.0.0")
+package org.apache.sling.testing.serversetup.instance;
+
+import aQute.bnd.annotation.Version;
+
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/JarExecutor.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/JarExecutor.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/JarExecutor.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/JarExecutor.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,210 @@
+/*
+ * 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.testing.serversetup.jarexec;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
+import org.apache.commons.exec.ExecuteResultHandler;
+import org.apache.commons.exec.Executor;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Start a runnable jar by forking a JVM process,
+ * and terminate the process when this VM exits.
+ */
+public class JarExecutor {
+ private final File jarToExecute;
+ private final String jvmFullPath;
+ private final int serverPort;
+ private final Properties config;
+ private Executor executor;
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ public static final int DEFAULT_PORT = 8765;
+ public static final int DEFAULT_EXIT_TIMEOUT = 30;
+
+ public static final String DEFAULT_JAR_FOLDER = "target/dependency";
+ public static final String DEFAULT_JAR_NAME_REGEXP = "org.apache.sling.*jar$";
+ public static final String PROP_PREFIX = "jar.executor.";
+ public static final String PROP_SERVER_PORT = PROP_PREFIX + "server.port";
+ public static final String PROP_JAR_FOLDER = PROP_PREFIX + "jar.folder";
+ public static final String PROP_JAR_NAME_REGEXP = PROP_PREFIX + "jar.name.regexp";
+ public static final String PROP_VM_OPTIONS = PROP_PREFIX + "vm.options";
+ public static final String PROP_WORK_FOLDER = PROP_PREFIX + "work.folder";
+ public static final String PROP_JAR_OPTIONS = PROP_PREFIX + "jar.options";
+ public static final String PROP_EXIT_TIMEOUT_SECONDS = PROP_PREFIX + "exit.timeout.seconds";
+ public static final String PROP_WAIT_ONSHUTDOWN = PROP_PREFIX + "wait.on.shutdown";
+ public static final String PROP_JAVA_PATH = PROP_PREFIX + "java.executable.path";
+ public static final String PROP_SYNC_EXEC = PROP_PREFIX + "synchronous.exec";
+ public static final String PROP_SYNC_EXEC_EXPECTED = PROP_PREFIX + "synchronous.exec.expected.result";
+
+ @SuppressWarnings("serial")
+ public static class ExecutorException extends Exception {
+ ExecutorException(String reason) {
+ super(reason);
+ }
+ ExecutorException(String reason, Throwable cause) {
+ super(reason, cause);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": " + jarToExecute.getName() + " (port " + serverPort + ")";
+ }
+
+ public int getServerPort() {
+ return serverPort;
+ }
+
+ /** Build a JarExecutor, locate the jar to run, etc */
+ public JarExecutor(Properties config) throws ExecutorException {
+ this.config = config;
+ final boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
+
+ String portStr = config.getProperty(PROP_SERVER_PORT);
+ serverPort = portStr == null ? DEFAULT_PORT : Integer.valueOf(portStr);
+
+ final String configJvmPath = config.getProperty(PROP_JAVA_PATH);
+ if(configJvmPath == null) {
+ final String javaExecutable = isWindows ? "java.exe" : "java";
+ jvmFullPath = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + javaExecutable;
+ } else {
+ jvmFullPath = configJvmPath;
+ }
+
+ String jarFolderPath = config.getProperty(PROP_JAR_FOLDER);
+ jarFolderPath = jarFolderPath == null ? DEFAULT_JAR_FOLDER : jarFolderPath;
+ final File jarFolder = new File(jarFolderPath);
+
+ String jarNameRegexp = config.getProperty(PROP_JAR_NAME_REGEXP);
+ jarNameRegexp = jarNameRegexp == null ? DEFAULT_JAR_NAME_REGEXP : jarNameRegexp;
+ final Pattern jarPattern = Pattern.compile(jarNameRegexp);
+
+ // Find executable jar
+ final String [] candidates = jarFolder.list();
+ if(candidates == null) {
+ throw new ExecutorException(
+ "No files found in jar folder specified by "
+ + PROP_JAR_FOLDER + " property: " + jarFolder.getAbsolutePath());
+ }
+ File f = null;
+ for(String filename : candidates) {
+ if(jarPattern.matcher(filename).matches()) {
+ f = new File(jarFolder, filename);
+ break;
+ }
+ }
+
+ if(f == null) {
+ throw new ExecutorException("Executable jar matching '" + jarPattern
+ + "' not found in " + jarFolder.getAbsolutePath()
+ + ", candidates are " + Arrays.asList(candidates));
+ }
+ jarToExecute = f;
+ }
+
+ /** Start the jar if not done yet, and setup runtime hook
+ * to stop it.
+ */
+ public void start() throws Exception {
+ final ExecuteResultHandler h = new ExecuteResultHandler() {
+ public void onProcessFailed(ExecuteException ex) {
+ log.error("Process execution failed:" + ex, ex);
+ }
+
+ public void onProcessComplete(int result) {
+ log.info("Process execution complete, exit code=" + result);
+ }
+ };
+
+ final String vmOptions = config.getProperty(PROP_VM_OPTIONS);
+ executor = new DefaultExecutor();
+ final CommandLine cl = new CommandLine(jvmFullPath);
+ if (vmOptions != null && vmOptions.length() > 0) {
+ cl.addArguments(vmOptions);
+ }
+ cl.addArgument("-jar");
+ cl.addArgument(jarToExecute.getAbsolutePath());
+
+ // Additional options for the jar that's executed.
+ // $JAREXEC_SERVER_PORT$ is replaced our serverPort value
+ String jarOptions = config.getProperty(PROP_JAR_OPTIONS);
+ if(jarOptions != null && jarOptions.length() > 0) {
+ jarOptions = jarOptions.replaceAll("\\$JAREXEC_SERVER_PORT\\$", String.valueOf(serverPort));
+ log.info("Executable jar options: {}", jarOptions);
+ cl.addArguments(jarOptions);
+ }
+
+ final String workFolderOption = config.getProperty(PROP_WORK_FOLDER);
+ if(workFolderOption != null && workFolderOption.length() > 0) {
+ final File workFolder = new File(workFolderOption);
+ if(!workFolder.isDirectory()) {
+ throw new IOException("Work dir set by " + PROP_WORK_FOLDER + " option does not exist: "
+ + workFolder.getAbsolutePath());
+ }
+ log.info("Setting working directory for executable jar: {}", workFolder.getAbsolutePath());
+ executor.setWorkingDirectory(workFolder);
+ }
+
+ String tmStr = config.getProperty(PROP_EXIT_TIMEOUT_SECONDS);
+ final int exitTimeoutSeconds = tmStr == null ? DEFAULT_EXIT_TIMEOUT : Integer.valueOf(tmStr);
+
+ if("true".equals(config.getProperty(PROP_SYNC_EXEC, ""))) {
+ final long start = System.currentTimeMillis();
+ log.info("Executing and waiting for result: " + cl);
+ final int result = executor.execute(cl);
+ final int expected = Integer.valueOf(config.getProperty(PROP_SYNC_EXEC_EXPECTED, "0"));
+ log.info("Execution took " + (System.currentTimeMillis() - start) + " msec");
+ if(result != expected) {
+ throw new ExecutorException("Expected result code " + expected + ", got " + result);
+ }
+ } else {
+ log.info("Executing asynchronously: " + cl);
+ executor.setStreamHandler(new PumpStreamHandler());
+ final ShutdownHookSingleProcessDestroyer pd = new ShutdownHookSingleProcessDestroyer("java -jar " + jarToExecute.getName(), exitTimeoutSeconds);
+ final boolean waitOnShutdown = Boolean.valueOf(config.getProperty(PROP_WAIT_ONSHUTDOWN, "false"));
+ log.info("Setting up ProcessDestroyer with waitOnShutdown=" + waitOnShutdown);
+ pd.setWaitOnShutdown(waitOnShutdown);
+ executor.setProcessDestroyer(pd);
+ executor.execute(cl, h);
+ }
+ }
+
+ /** Stop the process that we started, if any, and wait for it to exit before returning */
+ public void stop() {
+ if(executor == null) {
+ throw new IllegalStateException("Process not started, no Executor set");
+ }
+ final Object d = executor.getProcessDestroyer();
+ if(d instanceof ShutdownHookSingleProcessDestroyer) {
+ ((ShutdownHookSingleProcessDestroyer)d).destroyProcess(true);
+ log.info("Process destroyed");
+ } else {
+ throw new IllegalStateException(d + " is not a Runnable, cannot destroy process");
+ }
+ }
+}
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/ShutdownHookSingleProcessDestroyer.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/ShutdownHookSingleProcessDestroyer.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/ShutdownHookSingleProcessDestroyer.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/ShutdownHookSingleProcessDestroyer.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,117 @@
+/*
+ * 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.testing.serversetup.jarexec;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.commons.exec.ProcessDestroyer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Simple ProcessDestroyer for a single process, meant to be used
+ * with our JarExecutor.
+ */
+class ShutdownHookSingleProcessDestroyer implements ProcessDestroyer, Runnable {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private Thread shutdownHookThread;
+ private Process process;
+ private final int timeoutSeconds;
+ private final String processInfo;
+ private boolean waitOnShutdown = false;
+
+ public ShutdownHookSingleProcessDestroyer(String processInfo, int timeoutSeconds) {
+ this.processInfo = processInfo;
+ this.timeoutSeconds = timeoutSeconds;
+ }
+
+ public boolean getWaitOnShutdown() {
+ return waitOnShutdown;
+ }
+
+ public void setWaitOnShutdown(boolean waitOnShutdown) {
+ this.waitOnShutdown = waitOnShutdown;
+ }
+
+ public synchronized boolean add(Process p) {
+ if(process != null) {
+ throw new IllegalStateException("Process already set: " + process);
+ }
+
+ if(shutdownHookThread == null) {
+ shutdownHookThread = new Thread(this, getClass().getSimpleName());
+ Runtime.getRuntime().addShutdownHook(shutdownHookThread);
+ }
+
+ process = p;
+ return true;
+ }
+
+ public synchronized boolean remove(Process p) {
+ p = null;
+ return true;
+ }
+
+ public int size() {
+ return 1;
+ }
+
+ public void run() {
+ destroyProcess(waitOnShutdown);
+ }
+
+ public void destroyProcess(boolean waitForIt) {
+ Process toDestroy = null;
+ synchronized (this) {
+ toDestroy = process;
+ process = null;
+ }
+
+ if(toDestroy == null) {
+ return;
+ }
+
+ toDestroy.destroy();
+
+ if(waitForIt) {
+ log.info("Waiting for destroyed process {} to exit (timeout={} seconds)", processInfo, timeoutSeconds);
+ final Thread mainThread = Thread.currentThread();
+ final Timer t = new Timer(true);
+ final TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ mainThread.interrupt();
+ }
+ };
+ t.schedule(task, timeoutSeconds * 1000L);
+ try {
+ toDestroy.waitFor();
+ try {
+ final int exit = toDestroy.exitValue();
+ log.info("Process {} ended with exit code {}", processInfo, exit);
+ } catch(IllegalStateException ise) {
+ log.error("Failed to destroy process " + processInfo);
+ }
+ } catch (InterruptedException e) {
+ log.error("Timeout waiting for process " + processInfo + " to exit");
+ } finally {
+ t.cancel();
+ }
+ }
+ }
+}
\ No newline at end of file
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/package-info.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/package-info.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/jarexec/package-info.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@Version("1.0.0")
+package org.apache.sling.testing.serversetup.jarexec;
+
+import aQute.bnd.annotation.Version;
+
Added: sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/package-info.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/package-info.java (added)
+++ sling/trunk/testing/serversetup/src/main/java/org/apache/sling/testing/serversetup/package-info.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@Version("1.0.0")
+package org.apache.sling.testing.serversetup;
+
+import aQute.bnd.annotation.Version;
+
Added: sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/ServerSetupSingletonTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/ServerSetupSingletonTest.java?rev=1741631&view=auto
==============================================================================
--- sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/ServerSetupSingletonTest.java (added)
+++ sling/trunk/testing/serversetup/src/test/java/org/apache/sling/testing/serversetup/test/ServerSetupSingletonTest.java Fri Apr 29 14:01:27 2016
@@ -0,0 +1,185 @@
+/*
+ * 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.testing.serversetup.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Properties;
+
+import org.apache.sling.testing.serversetup.ServerSetup;
+import org.apache.sling.testing.serversetup.ServerSetupSingleton;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Test the ServerSetupSingleton */
+public class ServerSetupSingletonTest {
+ private ServerSetup serverSetup;
+ private Properties props;
+
+ @Before
+ public void setup() throws Exception {
+ props = new Properties();
+ props.setProperty(ServerSetupSingleton.CLASS_NAME_PROP, TestServerSetup.class.getName());
+ props.setProperty(ServerSetup.PHASES_TO_RUN_PROP, "one, \t\n two, three, four, five \t");
+ serverSetup = ServerSetupSingleton.instance(props);
+ serverSetup.setConfig(props);
+ TestSetupPhase.clearExecutionLog();
+ TestSetupPhase.failingPhases = "";
+ }
+
+ @Test
+ public void testProperties() {
+ assertTrue(serverSetup.getConfig() == props);
+ }
+
+ @Test
+ public void testContext() {
+ final String key = "foo";
+ assertNull(serverSetup.getContext().get(key));
+ serverSetup.getContext().put(key, this);
+ assertEquals(serverSetup.getContext().get(key), this);
+ }
+
+ @Test
+ public void testStartup() throws Exception {
+ serverSetup.setupTestServer();
+ assertEquals("Expecting all startup phases to have run",
+ "one,two,three", TestSetupPhase.executionLog.toString());
+
+ serverSetup.setupTestServer();
+ assertEquals("Expecting second setup call to have no effect",
+ "one,two,three", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test
+ public void testShutdown() throws Exception {
+ serverSetup.shutdown();
+ assertEquals("Expecting all shutdown phases to have run",
+ "four,five", TestSetupPhase.executionLog.toString());
+
+ serverSetup.shutdown();
+ assertEquals("Expecting second shutdown call to be ignored",
+ "four,five", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test
+ public void testStartupAndShutdown() throws Exception {
+ serverSetup.setupTestServer();
+ assertEquals("Expecting all startup phases to have run",
+ "one,two,three", TestSetupPhase.executionLog.toString());
+
+ serverSetup.shutdown();
+ assertEquals("Expecting all phases to have run",
+ "one,two,three,four,five", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test
+ public void testStartupSomeOnly() throws Exception {
+ props.setProperty(ServerSetup.PHASES_TO_RUN_PROP, "one, three, five");
+ serverSetup.setConfig(props);
+
+ serverSetup.setupTestServer();
+ assertEquals("Expecting only two startup phases to have run",
+ "one,three", TestSetupPhase.executionLog.toString());
+
+ serverSetup.setupTestServer();
+ assertEquals("Expecting second setup call to have no effect",
+ "one,three", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test
+ public void testShutdownSomeOnly() throws Exception {
+ props.setProperty(ServerSetup.PHASES_TO_RUN_PROP, "four");
+ serverSetup.setConfig(props);
+
+ serverSetup.shutdown();
+ assertEquals("Expecting only one shutdown phase to have run",
+ "four", TestSetupPhase.executionLog.toString());
+
+ serverSetup.shutdown();
+ assertEquals("Expecting second setup call to have no effect",
+ "four", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test
+ public void testFailingStartup() {
+ TestSetupPhase.failingPhases = "two, five";
+
+ // setupTestServer will fail every time it's called
+ // after a failure, as that means the server is unusable
+ for(int i=0; i < 3; i++) {
+ try {
+ serverSetup.setupTestServer();
+ fail("startup should have failed");
+ } catch(Exception ignored) {
+ }
+
+ assertEquals("Expecting only one startup phase to have run",
+ "one", TestSetupPhase.executionLog.toString());
+ }
+ }
+
+ @Test
+ public void testFailingShutdown() throws Exception {
+ TestSetupPhase.failingPhases = "two, five";
+
+ try {
+ serverSetup.shutdown();
+ fail("shutdown should have failed");
+ } catch(Exception ignored) {
+ }
+
+ assertEquals("Expecting only one startup phase to have run",
+ "four", TestSetupPhase.executionLog.toString());
+
+ // Calling shutdown again does not throw an Exception again,
+ // it's not really useful at shutdown.
+ serverSetup.shutdown();
+
+ assertEquals("Still expecting only one startup phase to have run",
+ "four", TestSetupPhase.executionLog.toString());
+ }
+
+ @Test(expected=ServerSetup.SetupException.class)
+ public void testDuplicateStartupPhase() throws ServerSetup.SetupException {
+ serverSetup.addSetupPhase(new TestSetupPhase("two", true));
+ }
+
+ @Test(expected=ServerSetup.SetupException.class)
+ public void testDuplicateShutdownPhase() throws ServerSetup.SetupException {
+ serverSetup.addSetupPhase(new TestSetupPhase("two", false));
+ }
+
+ @Test
+ public void testAddPhasesLater() throws Exception {
+ props.setProperty(ServerSetup.PHASES_TO_RUN_PROP, "one, B, five, A, two");
+ serverSetup.setConfig(props);
+ serverSetup.addSetupPhase(new TestSetupPhase("A", true));
+ serverSetup.addSetupPhase(new TestSetupPhase("B", false));
+ serverSetup.setupTestServer();
+
+ assertEquals("Expecting all startup phases to have run",
+ "one,A,two", TestSetupPhase.executionLog.toString());
+
+ serverSetup.shutdown();
+ assertEquals("Expecting all phases to have run",
+ "one,A,two,B,five", TestSetupPhase.executionLog.toString());
+ }
+}
\ No newline at end of file