blob: 0de6a165d55e912b2f054816450ae9f203d123f1 [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.ide.test.impl.helpers;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.junit.rules.ExternalResource;
public class ExternalSlingLaunchpad extends ExternalResource {
private static final Pattern STARTLEVEL_JSON_SNIPPET = Pattern.compile("\"systemStartLevel\":(\\d+)");
private static final int EXPECTED_START_LEVEL = 30;
private static final long MAX_WAIT_TIME_MS = TimeUnit.MINUTES.toMillis(1);
private final LaunchpadConfig config;
public ExternalSlingLaunchpad(LaunchpadConfig config) {
this.config = config;
}
@Override
protected void before() throws Throwable {
Credentials creds = new UsernamePasswordCredentials(config.getUsername(), config.getPassword());
HttpClient client = new HttpClient();
client.getState().setCredentials(new AuthScope(config.getHostname(), config.getPort()), creds);
long cutoff = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
List<SlingReadyRule> rules = new ArrayList<SlingReadyRule>();
rules.add(new StartLevelSlingReadyRule(client));
rules.add(new ActiveBundlesSlingReadyRule(client));
for (SlingReadyRule rule : rules) {
while (true) {
if (rule.evaluate()) {
break;
}
assertTimeout(cutoff);
Thread.sleep(100);
}
}
}
private void assertTimeout(long cutoff) throws AssertionFailedError {
if (System.currentTimeMillis() > cutoff) {
throw new AssertionFailedError("Sling launchpad did not start within " + MAX_WAIT_TIME_MS + " milliseconds");
}
}
private void debug(String string) {
if (System.getProperty("sling.ide.it.debug") != null) {
System.out.println("[" + new Date() + "] " + string);
}
}
private interface SlingReadyRule {
boolean evaluate() throws Exception;
}
private class StartLevelSlingReadyRule implements SlingReadyRule {
private final HttpClient client;
private final GetMethod httpMethod;
public StartLevelSlingReadyRule(HttpClient client) {
this.client = client;
httpMethod = new GetMethod(config.getUrl() + "system/console/vmstat");
}
@Override
public boolean evaluate() throws Exception {
int status = client.executeMethod(httpMethod);
debug("vmstat http call got return code " + status);
InputStream input = null;
try {
if (status == 200) {
String responseBody = IOUtils.toString(httpMethod.getResponseBodyAsStream(),
httpMethod.getResponseCharSet());
Matcher m = STARTLEVEL_JSON_SNIPPET.matcher(responseBody);
if (m.find()) {
int startLevel = Integer.parseInt(m.group(1));
debug("vmstat http call got startLevel " + startLevel);
if (startLevel >= EXPECTED_START_LEVEL) {
debug("current startLevel " + startLevel + " >= " + EXPECTED_START_LEVEL
+ ", we are done here");
return true;
}
}
}
} finally {
IOUtils.closeQuietly(input);
}
return false;
}
}
private class ActiveBundlesSlingReadyRule implements SlingReadyRule {
private final HttpClient client;
private final GetMethod httpMethod;
public ActiveBundlesSlingReadyRule(HttpClient client) {
this.client = client;
httpMethod = new GetMethod(config.getUrl() + "system/console/bundles.json");
}
@Override
public boolean evaluate() throws Exception {
int status = client.executeMethod(httpMethod);
debug("bundles http call got return code " + status);
InputStream input = null;
try {
if (status == 200) {
input = httpMethod.getResponseBodyAsStream();
JSONObject obj = new JSONObject(new JSONTokener(new InputStreamReader(input)));
JSONArray bundleStatus = obj.getJSONArray("s");
int total = bundleStatus.getInt(0);
int active = bundleStatus.getInt(1);
int fragment = bundleStatus.getInt(2);
debug("bundle http call status: total = " + total + ", active = " + active + ", fragment = " + fragment);
if (total == active + fragment) {
debug("All bundles are started, we are done here");
return true;
}
}
} finally {
IOUtils.closeQuietly(input);
}
return false;
}
}
}