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 2014/04/16 11:52:23 UTC

svn commit: r1587850 - in /sling/trunk/testing: samples/integration-tests/ samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/ tools/src/main/java/org/apache/sling/testing/tools/sling/

Author: bdelacretaz
Date: Wed Apr 16 09:52:23 2014
New Revision: 1587850

URL: http://svn.apache.org/r1587850
Log:
SLING-3478 - Facilitate writing integration tests for multiple instances, including MultipleOsgiConsoleTest example. Patch contributed by Marius Petria, thanks!

Added:
    sling/trunk/testing/samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/MultipleOsgiConsoleTest.java
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstance.java
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceManager.java
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceState.java
Modified:
    sling/trunk/testing/samples/integration-tests/pom.xml
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java

Modified: sling/trunk/testing/samples/integration-tests/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/testing/samples/integration-tests/pom.xml?rev=1587850&r1=1587849&r2=1587850&view=diff
==============================================================================
--- sling/trunk/testing/samples/integration-tests/pom.xml (original)
+++ sling/trunk/testing/samples/integration-tests/pom.xml Wed Apr 16 09:52:23 2014
@@ -162,6 +162,8 @@
                         <configuration>
                             <portNames>
                                 <portName>http.port</portName>
+                                <portName>instance1.http.port</portName>
+                                <portName>instance2.http.port</portName>
                             </portNames>
                         </configuration>
                     </execution>
@@ -205,11 +207,15 @@
                         <test.server.username>${test.server.username}</test.server.username>
                         <test.server.password>${test.server.password}</test.server.password>
                         <jar.executor.server.port>${http.port}</jar.executor.server.port>
+                        <instance1.jar.executor.server.port>${instance1.http.port}</instance1.jar.executor.server.port>
+                        <instance2.jar.executor.server.port>${instance2.http.port}</instance2.jar.executor.server.port>
                         <jar.executor.vm.options>${jar.executor.vm.options}</jar.executor.vm.options>
                         <jar.executor.jar.folder>${project.basedir}/target/dependency</jar.executor.jar.folder>
                         <jar.executor.jar.name.regexp>org.apache.sling.launchpad.*jar$</jar.executor.jar.name.regexp>
                         <jar.executor.work.folder>${jar.executor.work.folder}</jar.executor.work.folder>
-                        <jar.executor.jar.options>${jar.executor.jar.options}</jar.executor.jar.options>
+                        <jar.executor.jar.options>${jar.executor.jar.options} -Dsling.home=sling/default</jar.executor.jar.options>
+                        <instance1.jar.executor.jar.options>${jar.executor.jar.options} -Dsling.home=sling/instance1</instance1.jar.executor.jar.options>
+                        <instance2.jar.executor.jar.options>${jar.executor.jar.options} -Dsling.home=sling/instance2</instance2.jar.executor.jar.options>
                         <additional.bundles.path>${project.basedir}/target/sling/additional-bundles</additional.bundles.path>
                         <keepJarRunning>${keepJarRunning}</keepJarRunning>
                         <server.ready.timeout.seconds>60</server.ready.timeout.seconds>
@@ -268,7 +274,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.junit.remote</artifactId>
-            <version>1.0.8</version>
+            <version>1.0.9-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Added: sling/trunk/testing/samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/MultipleOsgiConsoleTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/MultipleOsgiConsoleTest.java?rev=1587850&view=auto
==============================================================================
--- sling/trunk/testing/samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/MultipleOsgiConsoleTest.java (added)
+++ sling/trunk/testing/samples/integration-tests/src/test/java/org/apache/sling/testing/samples/integrationtests/http/MultipleOsgiConsoleTest.java Wed Apr 16 09:52:23 2014
@@ -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.samples.integrationtests.http;
+
+import org.apache.sling.testing.tools.sling.SlingInstance;
+import org.apache.sling.testing.tools.sling.SlingInstanceManager;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Example testing several Sling instances */
+public class MultipleOsgiConsoleTest {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    
+    private static final SlingInstanceManager manager = new SlingInstanceManager("instance1", "instance2");
+
+    @Test
+    public void testSomeConsolePaths() throws Exception {
+        for (SlingInstance slingInstance : manager.getInstances()) {
+            testSomeConsolePaths(slingInstance);
+        }
+    }
+
+    public void testSomeConsolePaths(SlingInstance slingInstance) throws Exception {
+        log.info("Running {} on {}", getClass().getSimpleName(), slingInstance.getServerBaseUrl());
+
+        final String [] subpaths = {
+                "bundles",
+                "components",
+                "configMgr",
+                "config",
+                "licenses",
+                "logs",
+                "memoryusage",
+                "services"
+        };
+
+        for(String subpath : subpaths) {
+            final String path = "/system/console/" + subpath;
+            slingInstance.getRequestExecutor().execute(
+                    slingInstance.getRequestBuilder().buildGetRequest(path)
+                            .withCredentials(slingInstance.getServerUsername(), slingInstance.getServerPassword())
+            ).assertStatus(200);
+        }
+    }
+}
\ No newline at end of file

Added: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstance.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstance.java?rev=1587850&view=auto
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstance.java (added)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstance.java Wed Apr 16 09:52:23 2014
@@ -0,0 +1,44 @@
+/*
+ * 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.tools.sling;
+
+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/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceManager.java?rev=1587850&view=auto
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceManager.java (added)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceManager.java Wed Apr 16 09:52:23 2014
@@ -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.tools.sling;
+
+import java.util.Collection;
+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 {
+    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 Collection<SlingInstance> getInstances() {
+        return slingTestInstances.values();
+    }
+}
\ No newline at end of file

Added: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceState.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceState.java?rev=1587850&view=auto
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceState.java (added)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingInstanceState.java Wed Apr 16 09:52:23 2014
@@ -0,0 +1,142 @@
+/*
+ * 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.tools.sling;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.sling.testing.tools.jarexec.JarExecutor;
+
+/**
+ * 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

Modified: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java?rev=1587850&r1=1587849&r2=1587850&view=diff
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java (original)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java Wed Apr 16 09:52:23 2014
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Properties;
 import java.util.TreeSet;
 
 import org.apache.http.client.HttpClient;
@@ -37,7 +38,7 @@ import org.slf4j.LoggerFactory;
 /** Base class for running tests against a Sling instance,
  *  takes care of starting Sling and waiting for it to be ready.
  */
-public class SlingTestBase {
+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";
@@ -51,54 +52,58 @@ public class SlingTestBase {
     public static final String BUNDLE_INSTALL_TIMEOUT_SECONDS = "bundle.install.timeout.seconds";
     public static final String ADMIN = "admin";
 
-    private static final boolean keepJarRunning = "true".equals(System.getProperty(KEEP_JAR_RUNNING_PROP));
-    private final String serverBaseUrl;
+    private final boolean keepJarRunning;
     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 static boolean serverStarted;
-    private static boolean serverStartedByThisClass;
-    private static boolean serverReady;
-    private static boolean serverReadyTestFailed;
-    private static boolean installBundlesFailed;
-    private static boolean extraBundlesInstalled;
-    private static boolean startupInfoProvided;
-    private static boolean serverInfoLogged;
+    private boolean serverStartedByThisClass;
+
 
     private final Logger log = LoggerFactory.getLogger(getClass());
-    private static JarExecutor jarExecutor;
 
-    /** Get configuration but do not start server yet, that's done on demand */
+
     public SlingTestBase() {
+        this(SlingInstanceState.getInstance(SlingInstanceState.DEFAULT_INSTANCE_NAME),
+                System.getProperties());
+    }
 
-        final String configuredUrl = System.getProperty(TEST_SERVER_URL_PROP, System.getProperty("launchpad.http.server.url"));
+    /** 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));
+
+
+        final String configuredUrl = systemProperties.getProperty(TEST_SERVER_URL_PROP, systemProperties.getProperty("launchpad.http.server.url"));
         if(configuredUrl != null) {
-            serverBaseUrl = configuredUrl;
-            serverStarted = true;
+            slingTestState.setServerBaseUrl(configuredUrl);
+            slingTestState.setServerStarted(true);
         } else {
-            if(jarExecutor == null) {
-                synchronized(this) {
-                    try {
-                        jarExecutor = new JarExecutor(System.getProperties());
-                    } catch(Exception e) {
-                        log.error("JarExecutor setup failed", e);
-                        fail("JarExecutor setup failed: " + e);
+            synchronized(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 = System.getProperty(SERVER_HOSTNAME_PROP);
+            String serverHost = systemProperties.getProperty(SERVER_HOSTNAME_PROP);
             if(serverHost == null || serverHost.trim().length() == 0) {
                 serverHost = "localhost";
             }
-            serverBaseUrl = "http://" + serverHost + ":" + jarExecutor.getServerPort();
+            slingTestState.setServerBaseUrl("http://" + serverHost + ":" + slingTestState.getJarExecutor().getServerPort());
         }
 
         // Set configured username using "admin" as default credential
-        final String configuredUsername = System.getProperty(TEST_SERVER_USERNAME);
+        final String configuredUsername = systemProperties.getProperty(TEST_SERVER_USERNAME);
         if (configuredUsername != null && configuredUsername.trim().length() > 0) {
             serverUsername = configuredUsername;
         } else {
@@ -106,40 +111,42 @@ public class SlingTestBase {
         }
 
         // Set configured password using "admin" as default credential
-        final String configuredPassword = System.getProperty(TEST_SERVER_PASSWORD);
+        final String configuredPassword = systemProperties.getProperty(TEST_SERVER_PASSWORD);
         if (configuredPassword != null && configuredPassword.trim().length() > 0) {
             serverPassword = configuredPassword;
         } else {
             serverPassword = ADMIN;
         }
 
-        builder = new RequestBuilder(serverBaseUrl);
-        webconsoleClient = new WebconsoleClient(serverBaseUrl, serverUsername, serverPassword);
-        builder = new RequestBuilder(serverBaseUrl);
+        builder = new RequestBuilder(slingTestState.getServerBaseUrl());
+        webconsoleClient = new WebconsoleClient(slingTestState.getServerBaseUrl(), serverUsername, serverPassword);
+        builder = new RequestBuilder(slingTestState.getServerBaseUrl());
         bundlesInstaller = new BundlesInstaller(webconsoleClient);
 
-        if(!serverInfoLogged) {
-            log.info("Server base URL={}", serverBaseUrl);
-            serverInfoLogged = true;
+        if(!slingTestState.isServerInfoLogged()) {
+            log.info("Server base URL={}", slingTestState.getServerBaseUrl());
+            slingTestState.setServerInfoLogged(true);
         }
     }
 
     /** Start the server, if not done yet */
     private void startServerIfNeeded() {
         try {
-            if(serverStarted && !serverStartedByThisClass && !startupInfoProvided) {
-                log.info(TEST_SERVER_URL_PROP + " was set: not starting server jar (" + serverBaseUrl + ")");
+            if(slingTestState.isServerStarted() && !serverStartedByThisClass && !slingTestState.isStartupInfoProvided()) {
+                log.info(TEST_SERVER_URL_PROP + " was set: not starting server jar (" + slingTestState.getServerBaseUrl() + ")");
             }
-            if(!serverStarted) {
-                synchronized (jarExecutor) {
-                    if(!serverStarted) {
-                        jarExecutor.start();
+            if(!slingTestState.isServerStarted()) {
+                synchronized (slingTestState) {
+                    if(!slingTestState.isServerStarted()) {
+                        slingTestState.getJarExecutor().start();
                         serverStartedByThisClass = true;
-                        serverStarted = true;
+                        if(!slingTestState.setServerStarted(true)) {
+                            fail("A server is already started at " + slingTestState.getServerBaseUrl());
+                        }
                     }
                 }
             }
-            startupInfoProvided = true;
+            slingTestState.setStartupInfoProvided(true);
             waitForServerReady();
             installAdditionalBundles();
             blockIfRequested();
@@ -150,10 +157,10 @@ public class SlingTestBase {
     }
 
     protected void installAdditionalBundles() {
-        if(installBundlesFailed) {
+        if(slingTestState.isInstallBundlesFailed()) {
             fail("Bundles could not be installed, cannot run tests");
-        } else if(!extraBundlesInstalled) {
-            final String paths = System.getProperty(ADDITONAL_BUNDLES_PATH);
+        } else if(!slingTestState.isExtraBundlesInstalled()) {
+            final String paths = systemProperties.getProperty(ADDITONAL_BUNDLES_PATH);
             if(paths == null) {
                 log.info("System property {} not set, additional bundles won't be installed",
                         ADDITONAL_BUNDLES_PATH);
@@ -178,40 +185,40 @@ public class SlingTestBase {
                             TimeoutsProvider.getInstance().getTimeout(START_BUNDLES_TIMEOUT_SECONDS, 30));
                 } catch(AssertionError ae) {
                     log.info("Exception while installing additional bundles", ae);
-                    installBundlesFailed = true;
+                    slingTestState.setInstallBundlesFailed(true);
                 } catch(Exception e) {
                     log.info("Exception while installing additional bundles", e);
-                    installBundlesFailed = true;
+                    slingTestState.setInstallBundlesFailed(true);
                 }
 
-                if(installBundlesFailed) {
+                if(slingTestState.isInstallBundlesFailed()) {
                     fail("Could not start all installed bundles:" + toInstall);
                 }
             }
         }
 
-        extraBundlesInstalled = !installBundlesFailed;
+        slingTestState.setExtraBundlesInstalled(!slingTestState.isInstallBundlesFailed());
     }
 
     /** Start server if needed, and return a RequestBuilder that points to it */
-    protected RequestBuilder getRequestBuilder() {
+    public RequestBuilder getRequestBuilder() {
         startServerIfNeeded();
         return builder;
     }
 
     /** Start server if needed, and return its base URL */
-    protected String getServerBaseUrl() {
+    public String getServerBaseUrl() {
         startServerIfNeeded();
-        return serverBaseUrl;
+        return slingTestState.getServerBaseUrl();
     }
 
     /** Return username configured for execution of HTTP requests */
-    protected String getServerUsername() {
+    public String getServerUsername() {
         return serverUsername;
     }
 
     /** Return password configured for execution of HTTP requests */
-    protected String getServerPassword() {
+    public String getServerPassword() {
         return serverPassword;
     }
 
@@ -222,7 +229,7 @@ public class SlingTestBase {
         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 (this) {
+            synchronized (slingTestState) {
                 try {
                     wait();
                 } catch(InterruptedException iex) {
@@ -234,15 +241,15 @@ public class SlingTestBase {
 
     /** Check a number of server URLs for readyness */
     protected void waitForServerReady() throws Exception {
-        if(serverReady) {
+        if(slingTestState.isServerReady()) {
             return;
         }
-        if(serverReadyTestFailed) {
+        if(slingTestState.isServerReadyTestFailed()) {
             fail("Server is not ready according to previous tests");
         }
 
         // Timeout for readiness test
-        final String sec = System.getProperty(SERVER_READY_TIMEOUT_PROP);
+        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;
@@ -250,11 +257,11 @@ public class SlingTestBase {
         // 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(System.getProperties().keySet());
+        propertyNames.addAll(systemProperties.keySet());
         for(Object o : propertyNames) {
             final String key = (String)o;
             if(key.startsWith(SERVER_READY_PROP_PREFIX)) {
-                testPaths.add(System.getProperty(key));
+                testPaths.add(systemProperties.getProperty(key));
             }
         }
 
@@ -276,24 +283,24 @@ public class SlingTestBase {
                 } catch(AssertionError ae) {
                     errors = true;
                     log.debug("Request to {}@{}{} failed, will retry ({})",
-                            new Object[] { serverUsername, serverBaseUrl, path, ae});
+                            new Object[] { serverUsername, slingTestState.getServerBaseUrl(), path, ae});
                 } catch(Exception e) {
                     errors = true;
                     log.debug("Request to {}@{}{} failed, will retry ({})",
-                            new Object[] { serverUsername, serverBaseUrl, path, pattern, e });
+                            new Object[] { serverUsername, slingTestState.getServerBaseUrl(), path, pattern, e });
                 }
             }
 
             if(!errors) {
-                serverReady = true;
+                slingTestState.setServerReady(true);
                 log.info("All {} paths return expected content, server ready", testPaths.size());
                 break;
             }
             Thread.sleep(TimeoutsProvider.getInstance().getTimeout(1000L));
         }
 
-        if(!serverReady) {
-            serverReadyTestFailed = true;
+        if(!slingTestState.isServerReady()) {
+            slingTestState.setServerReadyTestFailed(true);
             final String msg = "Server not ready after " + timeoutSec + " seconds, giving up";
             log.info(msg);
             fail(msg);
@@ -326,7 +333,7 @@ public class SlingTestBase {
 
         // We'll install those that are specified by system properties, in order
         final List<String> sortedPropertyKeys = new ArrayList<String>();
-        for(Object key : System.getProperties().keySet()) {
+        for(Object key : systemProperties.keySet()) {
             final String str = key.toString();
             if(str.startsWith(BUNDLE_TO_INSTALL_PREFIX)) {
                 sortedPropertyKeys.add(str);
@@ -334,7 +341,7 @@ public class SlingTestBase {
         }
         Collections.sort(sortedPropertyKeys);
         for(String key : sortedPropertyKeys) {
-            final String filenamePrefix = System.getProperty(key);
+            final String filenamePrefix = systemProperties.getProperty(key);
             for(String bundleFilename : bundleNames) {
                 if(bundleFilename.startsWith(filenamePrefix)) {
                     result.add(new File(dir, bundleFilename));
@@ -345,19 +352,19 @@ public class SlingTestBase {
         return result;
     }
 
-    protected boolean isServerStartedByThisClass() {
+    public boolean isServerStartedByThisClass() {
         return serverStartedByThisClass;
     }
 
-    protected HttpClient getHttpClient() {
+    public HttpClient getHttpClient() {
         return httpClient;
     }
 
-    protected RequestExecutor getRequestExecutor() {
+    public RequestExecutor getRequestExecutor() {
         return executor;
     }
 
-    protected WebconsoleClient getWebconsoleClient() {
+    public WebconsoleClient getWebconsoleClient() {
         startServerIfNeeded();
         return webconsoleClient;
     }