blob: d67e5e306ba47ad0aaf3a6771a0feb2987a3126d [file] [log] [blame]
/*
* 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.clients.osgi;
import org.apache.sling.testing.clients.ClientException;
import org.apache.sling.testing.clients.exceptions.TestValidationException;
import org.apache.sling.testing.clients.util.poller.Polling;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
* Utility for installing and starting additional bundles for testing
*/
public class BundlesInstaller {
private final Logger log = LoggerFactory.getLogger(getClass());
private final OsgiConsoleClient osgiConsoleClient;
public static final String ACTIVE_STATE = "active";
public BundlesInstaller(OsgiConsoleClient cc) {
osgiConsoleClient = cc;
}
/**
* Checks if a bundle is installed or not. Does not retry.
* @param bundleFile bundle file
* @return true if the bundle is installed
* @throws ClientException if the state of the bundle could not be determined
*/
public boolean isInstalled(File bundleFile) throws ClientException {
String bundleSymbolicName = "";
try {
bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(bundleFile);
log.debug("Checking if installed: " + bundleSymbolicName);
osgiConsoleClient.getBundleState(bundleSymbolicName);
log.debug("Already installed: " + bundleSymbolicName);
return true;
} catch (ClientException e) {
log.debug("Not yet installed: " + bundleSymbolicName);
return false;
} catch (IOException e) {
log.debug("Failed to retrieve bundle symbolic name from file. ", e);
throw new TestValidationException("Failed to retrieve bundle symbolic name from file. ", e);
}
}
/**
* Check if the installed version matches the one of the bundle (file)
* @param bundleFile bundle file
* @return true if the bundle is installed and has the same version
* @throws ClientException if the installed version cannot be retrieved
* @throws IOException if the file version cannot be read
*/
public boolean isInstalledWithSameVersion(File bundleFile) throws ClientException, IOException {
final String bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(bundleFile);
final String versionOnServer = osgiConsoleClient.getBundleVersion(bundleSymbolicName);
final String versionInBundle = OsgiConsoleClient.getBundleVersionFromFile(bundleFile);
if (versionOnServer.equals(versionInBundle)) {
return true;
} else {
log.warn("Installed bundle doesn't match: {}, versionOnServer={}, versionInBundle={}",
bundleSymbolicName, versionOnServer, versionInBundle);
return false;
}
}
/**
* Install a list of bundles supplied as Files
* @param toInstall list ob bundles to install
* @param startBundles whether to start the bundles
* @throws ClientException if an error occurs during installation
* @throws IOException if reading the file fails
*/
public void installBundles(List<File> toInstall, boolean startBundles) throws ClientException, IOException {
for(File f : toInstall) {
final String bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(f);
if (isInstalled(f)) {
if (f.getName().contains("SNAPSHOT")) {
log.info("Reinstalling (due to SNAPSHOT version): {}", bundleSymbolicName);
osgiConsoleClient.uninstallBundle(bundleSymbolicName);
} else if (!isInstalledWithSameVersion(f)) {
log.info("Reinstalling (due to version mismatch): {}", bundleSymbolicName);
osgiConsoleClient.uninstallBundle(bundleSymbolicName);
} else {
log.info("Not reinstalling: {}", bundleSymbolicName);
continue;
}
}
osgiConsoleClient.installBundle(f, startBundles);
log.info("Installed: {}", bundleSymbolicName);
}
// ensure that bundles are re-wired esp. if an existing bundle was updated
osgiConsoleClient.refreshPackages();
log.info("{} additional bundles installed", toInstall.size());
}
/**
* Uninstall a list of bundles supplied as Files
* @param toUninstall bundles to uninstall
* @throws ClientException if one of the requests failed
* @throws IOException if the files cannot be read from disk
*/
public void uninstallBundles(List<File> toUninstall) throws ClientException, IOException {
for(File f : toUninstall) {
final String bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(f);
if (isInstalled(f)) {
log.info("Uninstalling bundle: {}", bundleSymbolicName);
osgiConsoleClient.uninstallBundle(bundleSymbolicName);
} else {
log.info("Could not uninstall: {} as it never was installed", bundleSymbolicName);
}
}
// ensure that bundles are re-wired esp. if an existing bundle was updated
osgiConsoleClient.refreshPackages();
log.info("{} additional bundles uninstalled", toUninstall.size());
}
/**
* Wait for all bundles specified in symbolicNames list to be installed in the OSGi web console.
* @deprecated use {@link #waitBundlesInstalled(List, long)}
* @param symbolicNames the list of names for the bundles
* @param timeoutSeconds how many seconds to wait
* @throws ClientException if something went wrong
* @throws InterruptedException if interrupted
* @return true if all the bundles were installed
*/
@Deprecated
public boolean waitForBundlesInstalled(List<String> symbolicNames, int timeoutSeconds) throws ClientException, InterruptedException {
log.info("Checking that the following bundles are installed (timeout {} seconds): {}", timeoutSeconds, symbolicNames);
for (String symbolicName : symbolicNames) {
boolean started = osgiConsoleClient.checkBundleInstalled(symbolicName, 500, 2 * timeoutSeconds);
if (!started) return false;
}
return true;
}
/**
* Wait for multiple bundles to be installed in the OSGi web console.
* @param symbolicNames the list bundles to be checked
* @param timeout max total time to wait for all bundles, in ms, before throwing {@code TimeoutException}
* @throws TimeoutException if the timeout was reached before all the bundles were installed
* @throws InterruptedException to mark this operation as "waiting", callers should rethrow it
*/
public void waitBundlesInstalled(List<String> symbolicNames, long timeout)
throws InterruptedException, TimeoutException {
log.info("Checking that the following bundles are installed (timeout {} ms): {}", timeout, symbolicNames);
long start = System.currentTimeMillis();
for (String symbolicName : symbolicNames) {
osgiConsoleClient.waitBundleInstalled(symbolicName, timeout, 500);
if (System.currentTimeMillis() > start + timeout) {
throw new TimeoutException("Waiting for bundles did not finish in " + timeout + " ms.");
}
}
}
/**
* Start all the bundles in a {{List}}
* @param symbolicNames the list of bundles to start
* @param timeout total max time to wait for all the bundles, in ms
* @throws TimeoutException if the timeout is reached before all the bundles are started
* @throws InterruptedException to mark this operation as "waiting", callers should rethrow it
*/
public void startAllBundles(final List<String> symbolicNames, int timeout) throws InterruptedException, TimeoutException {
log.info("Starting bundles (timeout {} seconds): {}", timeout, symbolicNames);
Polling p = new Polling() {
@Override
public Boolean call() throws Exception {
boolean allActive = true;
for (String bundle : symbolicNames) {
String state = osgiConsoleClient.getBundleState(bundle);
if (!state.equalsIgnoreCase(ACTIVE_STATE)) {
osgiConsoleClient.startBundle(bundle);
allActive = false;
}
}
return allActive;
}
};
p.poll(timeout, 500);
}
}