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 2011/09/12 14:38:16 UTC
svn commit: r1169713 - in /sling/trunk/testing: samples/integration-tests/
tools/ tools/src/main/java/org/apache/sling/testing/tools/osgi/
tools/src/main/java/org/apache/sling/testing/tools/sling/
Author: bdelacretaz
Date: Mon Sep 12 12:38:15 2011
New Revision: 1169713
URL: http://svn.apache.org/viewvc?rev=1169713&view=rev
Log:
SLING-2001 and SLING-2197 - try to start all installed bundles repeatedly until success, to cope with inter-bundle dependencies
Added:
sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java (with props)
Modified:
sling/trunk/testing/samples/integration-tests/pom.xml
sling/trunk/testing/tools/pom.xml
sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/osgi/WebconsoleClient.java
sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/SlingTestBase.java
sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/TimeoutsProvider.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=1169713&r1=1169712&r2=1169713&view=diff
==============================================================================
--- sling/trunk/testing/samples/integration-tests/pom.xml (original)
+++ sling/trunk/testing/samples/integration-tests/pom.xml Mon Sep 12 12:38:15 2011
@@ -212,6 +212,8 @@
<server.ready.path.1>/:script src="system/sling.js"</server.ready.path.1>
<server.ready.path.2>/.explorer.html:href="/libs/sling/explorer/css/explorer.css"</server.ready.path.2>
<server.ready.path.3>/sling-test/sling/sling-test.html:Sling client library tests</server.ready.path.3>
+ <start.bundles.timeout.seconds>30</start.bundles.timeout.seconds>
+ <bundle.install.timeout.seconds>20</bundle.install.timeout.seconds>
<!--
Define additional bundles to install by specifying the beginning of their artifact name.
Modified: sling/trunk/testing/tools/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/pom.xml?rev=1169713&r1=1169712&r2=1169713&view=diff
==============================================================================
--- sling/trunk/testing/tools/pom.xml (original)
+++ sling/trunk/testing/tools/pom.xml Mon Sep 12 12:38:15 2011
@@ -66,6 +66,10 @@
<dependencies>
<dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.1</version>
@@ -86,6 +90,11 @@
<version>4.1</version>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.json</artifactId>
+ <version>2.0.6</version>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.11</version>
Modified: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/osgi/WebconsoleClient.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/osgi/WebconsoleClient.java?rev=1169713&r1=1169712&r2=1169713&view=diff
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/osgi/WebconsoleClient.java (original)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/osgi/WebconsoleClient.java Mon Sep 12 12:38:15 2011
@@ -16,14 +16,19 @@
*/
package org.apache.sling.testing.tools.osgi;
+import static org.junit.Assert.fail;
+
import java.io.File;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.testing.tools.http.RequestBuilder;
import org.apache.sling.testing.tools.http.RequestExecutor;
+import org.apache.sling.testing.tools.http.RetryingContentChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,6 +40,10 @@ public class WebconsoleClient {
private final String username;
private final String password;
+ public static final String JSON_KEY_DATA = "data";
+ public static final String JSON_KEY_STATE = "state";
+ public static final String CONSOLE_BUNDLES_PATH = "/system/console/bundles";
+
public WebconsoleClient(String slingServerUrl, String username, String password) {
this.builder = new RequestBuilder(slingServerUrl);
this.executor = new RequestExecutor(new DefaultHttpClient());
@@ -44,7 +53,7 @@ public class WebconsoleClient {
/** Install a bundle using the Felix webconsole HTTP interface */
public void installBundle(File f, boolean startBundle) throws Exception {
- log.info("Installing additional bundle {}", f.getName());
+ log.info("Installing bundle {}", f.getName());
// Setup request for Felix Webconsole bundle install
final MultipartEntity entity = new MultipartEntity();
@@ -57,9 +66,67 @@ public class WebconsoleClient {
// Console returns a 302 on success (and in a POST this
// is not handled automatically as per HTTP spec)
executor.execute(
- builder.buildPostRequest("/system/console/bundles")
+ builder.buildPostRequest(CONSOLE_BUNDLES_PATH)
.withCredentials(username, password)
.withEntity(entity)
).assertStatus(302);
}
+
+ /** Check that specified bundle is installed - must be called
+ * before other methods that take a symbolicName parameter,
+ * in case installBundle was just called and the actual
+ * installation hasn't happened yet. */
+ public void checkBundleInstalled(String symbolicName, int timeoutSeconds) {
+ final String path = getBundlePath(symbolicName, ".json");
+ new RetryingContentChecker(executor, builder).check(path, 200, timeoutSeconds, 500);
+ }
+
+ /** Get specified bundle state */
+ public String getBundleState(String symbolicName) throws Exception {
+ // This returns a data structure like
+ // {"status":"Bundle information: 173 bundles in total - all 173 bundles active.","s":[173,171,2,0,0],"data":
+ // [
+ // {"id":0,"name":"System Bundle","fragment":false,"stateRaw":32,"state":"Active","version":"3.0.7","symbolicName":"org.apache.felix.framework","category":""},
+ // ]}
+ final String path = getBundlePath(symbolicName, ".json");
+ final String content = executor.execute(
+ builder.buildGetRequest(path)
+ .withCredentials(username, password)
+ ).assertStatus(200)
+ .getContent();
+
+ final JSONObject root = new JSONObject(content);
+ if(!root.has(JSON_KEY_DATA)) {
+ fail(path + " does not provide '" + JSON_KEY_DATA + "' element, JSON content=" + content);
+ }
+ final JSONArray data = root.getJSONArray(JSON_KEY_DATA);
+ if(data.length() < 1) {
+ fail(path + "." + JSON_KEY_DATA + " is empty, JSON content=" + content);
+ }
+ final JSONObject bundle = data.getJSONObject(0);
+ if(!bundle.has(JSON_KEY_STATE)) {
+ fail(path + ".data[0].state missing, JSON content=" + content);
+ }
+ return bundle.getString(JSON_KEY_STATE);
+ }
+
+ /** Start specified bundle */
+ public void startBundle(String symbolicName) throws Exception {
+ // To start the bundle we POST action=start to its URL
+ final String path = getBundlePath(symbolicName, null);
+ log.info("Starting bundle {} via {}", symbolicName, path);
+
+ final MultipartEntity entity = new MultipartEntity();
+ entity.addPart("action",new StringBody("start"));
+ executor.execute(
+ builder.buildPostRequest(path)
+ .withCredentials(username, password)
+ .withEntity(entity)
+ ).assertStatus(200);
+ }
+
+ private String getBundlePath(String symbolicName, String extension) {
+ return CONSOLE_BUNDLES_PATH + "/" + symbolicName
+ + (extension == null ? "" : extension);
+ }
}
Added: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java?rev=1169713&view=auto
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java (added)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java Mon Sep 12 12:38:15 2011
@@ -0,0 +1,108 @@
+/*
+ * 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 static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.testing.tools.osgi.WebconsoleClient;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Utility that installs and starts additional bundles for testing */
+public class BundlesInstaller {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final WebconsoleClient webconsoleClient;
+ public static final String ACTIVE_STATE = "active";
+
+ public BundlesInstaller(WebconsoleClient wcc) {
+ webconsoleClient = wcc;
+ }
+
+ /** Install a list of bundles supplied as Files */
+ public void installBundles(List<File> toInstall, boolean startBundles) throws Exception {
+ for(File f : toInstall) {
+ webconsoleClient.installBundle(f, startBundles);
+ }
+ log.info("{} additional bundles installed from {}", toInstall.size(), toInstall.get(0).getAbsolutePath());
+ }
+
+ /** Wait for all bundles specified in symbolicNames list to be installed in the
+ * remote web console.
+ */
+ public void waitForBundlesInstalled(List<String> symbolicNames, int timeoutSeconds) throws Exception {
+ log.info("Checking that bundles are installed (timeout {} seconds): {}", timeoutSeconds, symbolicNames);
+ for(String symbolicName : symbolicNames) {
+ webconsoleClient.checkBundleInstalled(symbolicName, timeoutSeconds);
+ }
+ }
+
+ public void startAllBundles(List<String> symbolicNames, int timeoutSeconds) throws Exception {
+ log.info("Starting bundles (timeout {} seconds): {}", timeoutSeconds, symbolicNames);
+
+ final long timeout = System.currentTimeMillis() + timeoutSeconds * 1000L;
+ final List<String> toStart = new LinkedList<String>();
+ while(System.currentTimeMillis() < timeout) {
+ toStart.clear();
+ for(String name : symbolicNames) {
+ final String state = webconsoleClient.getBundleState(name);
+ if(!state.equalsIgnoreCase(ACTIVE_STATE)) {
+ toStart.add(name);
+ break;
+ }
+ }
+
+ if(toStart.isEmpty()) {
+ log.info("Ok - all bundles are in the {} state", ACTIVE_STATE);
+ break;
+ }
+
+ for(String name : toStart) {
+ webconsoleClient.startBundle(name);
+ }
+
+ Thread.sleep(500L);
+ }
+
+ if(!toStart.isEmpty()) {
+ fail("Some bundles did not start: " + toStart);
+ }
+ }
+
+ public String getBundleSymbolicName(File bundleFile) throws IOException {
+ String name = null;
+ final JarInputStream jis = new JarInputStream(new FileInputStream(bundleFile));
+ try {
+ final Manifest m = jis.getManifest();
+ if(m == null) {
+ fail("Manifest is null in " + bundleFile.getAbsolutePath());
+ }
+ name = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+ } finally {
+ jis.close();
+ }
+ return name;
+ }
+}
\ No newline at end of file
Propchange: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/BundlesInstaller.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
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=1169713&r1=1169712&r2=1169713&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 Mon Sep 12 12:38:15 2011
@@ -21,6 +21,7 @@ import static org.junit.Assert.fail;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
@@ -44,22 +45,27 @@ public class SlingTestBase {
public static final String SERVER_HOSTNAME_PROP = "test.server.hostname";
public static final String ADDITONAL_BUNDLES_PATH = "additional.bundles.path";
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 static final boolean keepJarRunning = "true".equals(System.getProperty(KEEP_JAR_RUNNING_PROP));
private final String serverBaseUrl;
- private static RequestBuilder builder;
- private static DefaultHttpClient httpClient = new DefaultHttpClient();
- private static RequestExecutor executor = new RequestExecutor(httpClient);
- private static WebconsoleClient webconsoleClient;
+ 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 static final Logger log = LoggerFactory.getLogger(SlingTestBase.class);
+ private final Logger log = LoggerFactory.getLogger(getClass());
private static JarExecutor jarExecutor;
/** Get configuration but do not start server yet, that's done on demand */
@@ -87,10 +93,15 @@ public class SlingTestBase {
serverBaseUrl = "http://" + serverHost + ":" + jarExecutor.getServerPort();
}
- log.info("Server base URL={}", serverBaseUrl);
builder = new RequestBuilder(serverBaseUrl);
webconsoleClient = new WebconsoleClient(serverBaseUrl, ADMIN, ADMIN);
builder = new RequestBuilder(serverBaseUrl);
+ bundlesInstaller = new BundlesInstaller(webconsoleClient);
+
+ if(!serverInfoLogged) {
+ log.info("Server base URL={}", serverBaseUrl);
+ serverInfoLogged = true;
+ }
}
/** Start the server, if not done yet */
@@ -110,7 +121,7 @@ public class SlingTestBase {
}
startupInfoProvided = true;
waitForServerReady();
- installExtraBundles();
+ installAdditionalBundles();
blockIfRequested();
} catch(Exception e) {
log.error("Exception in maybeStartServer()", e);
@@ -118,6 +129,45 @@ public class SlingTestBase {
}
}
+ protected void installAdditionalBundles() {
+ if(installBundlesFailed) {
+ fail("Bundles could not be installed, cannot run tests");
+ } else if(!extraBundlesInstalled) {
+ final String path = System.getProperty(ADDITONAL_BUNDLES_PATH);
+ if(path == null) {
+ log.info("System property {} not set, additional bundles won't be installed",
+ ADDITONAL_BUNDLES_PATH);
+ } else {
+ final List<File> toInstall = getBundlesToInstall(path);
+
+ 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);
+ installBundlesFailed = true;
+ } catch(Exception e) {
+ log.info("Exception while installing additional bundles", e);
+ installBundlesFailed = true;
+ }
+
+ if(installBundlesFailed) {
+ fail("Could not start all installed bundles:" + toInstall);
+ }
+ }
+ }
+
+ extraBundlesInstalled = !installBundlesFailed;
+ }
+
/** Start server if needed, and return a RequestBuilder that points to it */
protected RequestBuilder getRequestBuilder() {
startServerIfNeeded();
@@ -215,29 +265,17 @@ public class SlingTestBase {
}
}
- /** Install all bundles found under our additional bundles path */
- protected void installExtraBundles() throws Exception {
- if(extraBundlesInstalled) {
- return;
- }
- extraBundlesInstalled = true;
-
- if(!serverStartedByThisClass) {
- log.info("Server was not started here, additional bundles will not be installed");
- return;
+ /** Get the list of additional bundles to install, as specified by path parameter */
+ protected List<File> getBundlesToInstall(String additionalBundlesPath) {
+ final List<File> result = new LinkedList<File>();
+ if(additionalBundlesPath == null) {
+ return result;
}
- final String path = System.getProperty(ADDITONAL_BUNDLES_PATH);
- if(path == null) {
- log.info("System property {} not set, additional bundles won't be installed",
- ADDITONAL_BUNDLES_PATH);
- return;
- }
-
- final File dir = new File(path);
+ final File dir = new File(additionalBundlesPath);
if(!dir.isDirectory() || !dir.canRead()) {
log.info("Cannot read additional bundles directory {}, ignored", dir.getAbsolutePath());
- return;
+ return result;
}
// Collect all filenames of candidate bundles
@@ -251,8 +289,7 @@ public class SlingTestBase {
}
}
- // And install those that are specified by system properties, in order
- int count = 0;
+ // 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()) {
final String str = key.toString();
@@ -265,15 +302,14 @@ public class SlingTestBase {
final String filenamePrefix = System.getProperty(key);
for(String bundleFilename : bundleNames) {
if(bundleFilename.startsWith(filenamePrefix)) {
- webconsoleClient.installBundle(new File(dir, bundleFilename), true);
- count++;
+ result.add(new File(dir, bundleFilename));
}
}
}
- log.info("{} additional bundles installed from {}", count, dir.getAbsolutePath());
+ return result;
}
-
+
protected boolean isServerStartedByThisClass() {
return serverStartedByThisClass;
}
Modified: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/TimeoutsProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/TimeoutsProvider.java?rev=1169713&r1=1169712&r2=1169713&view=diff
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/TimeoutsProvider.java (original)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/sling/TimeoutsProvider.java Mon Sep 12 12:38:15 2011
@@ -64,4 +64,14 @@ public class TimeoutsProvider {
final int result = (int)(nomimalValue * timeoutFactor);
return result;
}
+
+ /** Get timeout from a system property, with default value */
+ public int getTimeout(String systemPropertyName, int defaultNominalValue) {
+ int result = defaultNominalValue;
+ final String str = System.getProperty(systemPropertyName);
+ if(str != null) {
+ result = Integer.parseInt(str);
+ }
+ return getTimeout(result);
+ }
}