| /* |
| * 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; |
| } |
| } |
| } |