http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/brooklyn/test/TestUtils.groovy ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/brooklyn/test/TestUtils.groovy b/usage/test-support/src/main/java/brooklyn/test/TestUtils.groovy deleted file mode 100644 index 78fefeb..0000000 --- a/usage/test-support/src/main/java/brooklyn/test/TestUtils.groovy +++ /dev/null @@ -1,540 +0,0 @@ -/* - * 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 brooklyn.test - -import static org.testng.Assert.* -import groovy.time.TimeDuration - -import java.util.concurrent.Callable -import java.util.concurrent.ExecutionException -import java.util.concurrent.Executors - -import org.codehaus.groovy.runtime.InvokerInvocationException -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.entity.Entity -import brooklyn.event.AttributeSensor -import brooklyn.util.text.StringFunctions; -import brooklyn.util.time.Duration - -import com.google.common.base.Predicate -import com.google.common.base.Supplier -import com.google.common.collect.Iterables - -/** - * Helper functions for tests of Tomcat, JBoss and others. - * - * Note that methods will migrate from here to {@link Asserts} in future releases. - */ -public class TestUtils { - private static final Logger log = LoggerFactory.getLogger(TestUtils.class) - - private TestUtils() { } - - /** - * True if two attempts to connect to the port succeed. - * - * @deprecated since 0.5; use {@link brooklyn.util.NetworkUtils#isPortAvailable(int)} - */ - @Deprecated - public static boolean isPortInUse(int port, long retryAfterMillis=0) { - try { - def s = new Socket("localhost", port) - s.close() - if (retryAfterMillis>0) { - log.debug "port {} still open, waiting 1s for it to really close", port - //give it 1s to close - Thread.sleep retryAfterMillis - s = new Socket("localhost", port) - s.close() - } - log.debug "port {} still open (conclusive)", port - return true - } catch (ConnectException e) { - return false - } - } - - /** - * Connects to the given HTTP URL and asserts that the response had status code 200. - * @deprecated Use HttpTestUtils.getHttpStatusCode(url) == 200 - */ - @Deprecated - public static boolean urlRespondsWithStatusCode200(String url) { - int status = HttpTestUtils.getHttpStatusCode(url); - log.debug "connection to {} gives {}", url, status - if (status == 404) - throw new Exception("Connection to $url gave 404"); - return status == 200 - } - - /** - * Connects to the given HTTP URL and asserts that the response had status code 200. - * @deprecated Use HttpTestUtils.getHttpStatusCode(url) - */ - @Deprecated - public static int urlRespondsStatusCode(String url) { - return HttpTestUtils.getHttpStatusCode(url); - } - - /** - * Connects to the given url and returns the connection. - * @deprecated Use HttpTestUtils.connectToUrl(url) - */ - @Deprecated - public static URLConnection connectToURL(String url) { - return HttpTestUtils.connectToUrl(url); - } - - // calling groovy from java doesn't cope with generics here; stripping them from here :-( - // <T> void assertEventually(Map flags=[:], Supplier<? extends T> supplier, Predicate<T> predicate) - /** - * @deprecated since 0.5; use {@link Asserts#eventually(Map, Supplier, Predicate)} - */ - @Deprecated - public static void assertEventually(Map flags=[:], Supplier supplier, Predicate predicate) { - Asserts.eventually(flags, supplier, predicate); - } - - /** - * @deprecated since 0.5; use {@link Asserts#eventually(Map, Supplier, Predicate, String)} - */ - @Deprecated - public static <T> void assertEventually(Map flags=[:], Supplier<? extends T> supplier, Predicate<T> predicate, String errMsg) { - Asserts.eventually(flags, supplier, predicate, errMsg); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(java.util.Map, Callable)} - */ - @Deprecated - public static void assertEventually(Map flags=[:], Callable c) { - executeUntilSucceeds(flags, c); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Runnable)} - */ - @Deprecated - public static void assertEventually(Map flags=[:], Runnable c) { - executeUntilSucceeds(flags, c); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)} - */ - @Deprecated - public static void executeUntilSucceeds(Map flags=[:], Closure c) { - Asserts.succeedsEventually(flags, c); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)} - */ - @Deprecated - public static void executeUntilSucceeds(Map flags=[:], Callable c) { - Asserts.succeedsEventually(flags, c); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Runnable)} - */ - @Deprecated - public static void executeUntilSucceeds(Map flags=[:], Runnable r) { - if (r in Callable) - executeUntilSucceedsWithFinallyBlock(flags, {return ((Callable)r).call();}, { }) - else if (r in Closure) // Closure check probably not necessary, just was trying to fix a server build which had a screwy problem - executeUntilSucceedsWithFinallyBlock(flags, {return ((Closure)r).call();}, { }) - else - executeUntilSucceedsWithFinallyBlock(flags, {r.run(); return true}, { }) - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)}, and tear-down with {@link AfterMethod}. - */ - @Deprecated - public static void executeUntilSucceedsElseShutdown(Map flags=[:], Entity entity, Closure c) { - try { - executeUntilSucceedsWithFinallyBlock(flags, c) { } - } catch (Throwable t) { - entity.stop() - throw t - } - } - - /** - * convenience for entities to ensure they shutdown afterwards. - * - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)}, and tear-down with {@link AfterMethod}. - */ - @Deprecated - public static void executeUntilSucceedsWithShutdown(Map flags=[:], Entity entity, Closure c) { - executeUntilSucceedsWithFinallyBlock(flags, c) { entity.stop() } - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)}, and tear-down with {@link AfterMethod}. - */ - @Deprecated - public static void executeUntilSucceedsWithFinallyBlock(Map flags=[:], Closure c, Closure finallyBlock={}) { - executeUntilSucceedsWithFinallyBlockInternal(flags, c, finallyBlock) - } - - /** - * Convenience method for cases where we need to test until something is true. - * - * The runnable will be invoked periodically until it succesfully concludes. - * Additionally, a finally block can be supplied. - * <p> - * The following flags are supported: - * <ul> - * <li>abortOnError (boolean, default true) - * <li>abortOnException - (boolean, default false) - * <li>useGroovyTruth - (defaults to false; any result code apart from 'false' will be treated as success including null; ignored for Runnables which aren't Callables) - * <li>timeout - (a Duration or an integer in millis, defaults to 30*SECONDS) - * <li>period - (a Duration or an integer in millis, for fixed retry time; if not set, defaults to exponentially increasing from 1 to 500ms) - * <li>minPeriod - (a Duration or an integer in millis; only used if period not explicitly set; the minimum period when exponentially increasing; defaults to 1ms) - * <li>maxPeriod - (a Duration or an integer in millis; only used if period not explicitly set; the maximum period when exponentially increasing; defaults to 500ms) - * <li>maxAttempts - (integer, Integer.MAX_VALUE) - * </ul> - * - * @param flags, accepts the flags listed above - * @param r - * @param finallyBlock - * - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)}, and tear-down with {@link AfterMethod}. - */ - @Deprecated - public static void executeUntilSucceedsWithFinallyBlock(Map flags=[:], Callable<?> c, Closure finallyBlock={}) { - executeUntilSucceedsWithFinallyBlockInternal(flags, c, finallyBlock); - } - - /** - * the "real" implementation, renamed to allow multiple entry points (depending whether closure cast to callable) - * - * @deprecated since 0.5; use {@link Asserts#succeedsEventually(Map, Callable)}, and tear-down with {@link AfterMethod}. - */ - @Deprecated - private static void executeUntilSucceedsWithFinallyBlockInternal(Map flags=[:], Callable<?> c, Closure finallyBlock={}) { -// log.trace "abortOnError = {}", flags.abortOnError - boolean abortOnException = flags.abortOnException ?: false - boolean abortOnError = flags.abortOnError ?: false - boolean useGroovyTruth = flags.useGroovyTruth ?: false - boolean logException = flags.logException ?: true - - // To speed up tests, default is for the period to start small and increase... - Duration duration = Duration.of(flags.timeout) ?: Duration.THIRTY_SECONDS; - Duration fixedPeriod = Duration.of(flags.period) ?: null - Duration minPeriod = fixedPeriod ?: Duration.of(flags.minPeriod) ?: Duration.millis(1) - Duration maxPeriod = fixedPeriod ?: Duration.of(flags.maxPeriod) ?: Duration.millis(500) - int maxAttempts = flags.maxAttempts ?: Integer.MAX_VALUE; - int attempt = 0; - long startTime = System.currentTimeMillis(); - try { - Throwable lastException = null; - Object result; - long lastAttemptTime = 0; - long expireTime = startTime+duration.toMilliseconds(); - long sleepTimeBetweenAttempts = minPeriod.toMilliseconds(); - - while (attempt<maxAttempts && lastAttemptTime<expireTime) { - try { - attempt++ - lastAttemptTime = System.currentTimeMillis() - result = c.call() - log.trace "Attempt {} after {} ms: {}", attempt, System.currentTimeMillis() - startTime, result - if (useGroovyTruth) { - if (result) return; - } else if (result != false) { - if (result instanceof BooleanWithMessage) - log.warn "Test returned an instance of BooleanWithMessage but useGroovyTruth is not set! " + - "The result of this probably isn't what you intended." - return; - } - lastException = null - } catch(Throwable e) { - lastException = e - log.trace "Attempt {} after {} ms: {}", attempt, System.currentTimeMillis() - startTime, e.message - if (abortOnException) throw e - if (abortOnError && e in Error) throw e - } - long sleepTime = Math.min(sleepTimeBetweenAttempts, expireTime-System.currentTimeMillis()) - if (sleepTime > 0) Thread.sleep(sleepTime) - sleepTimeBetweenAttempts = Math.min(sleepTimeBetweenAttempts*2, maxPeriod.toMilliseconds()) - } - - log.debug "TestUtils.executeUntilSucceedsWithFinallyBlockInternal exceeded max attempts or timeout - {} attempts lasting {} ms", attempt, System.currentTimeMillis()-startTime - if (lastException != null) - throw lastException - fail "invalid result: $result" - } catch (Throwable t) { - if (logException) log.info("failed execute-until-succeeds, "+attempt+" attempts, "+ - (System.currentTimeMillis()-startTime)+"ms elapsed "+ - "(rethrowing): "+t); - throw t - } finally { - finallyBlock.call() - } - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsContinually(Map, Runnable)} - */ - @Deprecated - public static <T> void assertSucceedsContinually(Map flags=[:], Runnable job) { - assertSucceedsContinually(flags, Executors.callable(job)); - } - - /** - * @deprecated since 0.5; use {@link Asserts#succeedsContinually(Map, Callable)} - */ - @Deprecated - public static void assertSucceedsContinually(Map flags=[:], Callable<?> job) { - Duration duration = Duration.of(flags.timeout) ?: Duration.ONE_SECOND - Duration period = Duration.of(flags.period) ?: Duration.millis(10) - long periodMs = period.toMilliseconds() - long startTime = System.currentTimeMillis() - long expireTime = startTime+duration.toMilliseconds() - - boolean first = true; - while (first || System.currentTimeMillis() <= expireTime) { - job.call(); - if (periodMs > 0) sleep(periodMs); - first = false; - } - } - - /** - * @deprecated since 0.5; use {@link Asserts#continually(Map, Supplier, Predicate)} - */ - @Deprecated - // FIXME When calling from java, the generics declared in groovy messing things up! - public static void assertContinuallyFromJava(Map flags=[:], Supplier<?> supplier, Predicate<?> predicate) { - Asserts.continually(flags, supplier, predicate); - } - - /** - * @deprecated since 0.5; use {@link Asserts#continually(Map, Supplier, Predicate)} - */ - @Deprecated - public static <T> void assertContinually(Map flags=[:], Supplier<? extends T> supplier, Predicate<T> predicate) { - Asserts.continually(flags, supplier, predicate, (String)null); - } - - /** - * @deprecated since 0.5; use {@link Asserts#continually(Map, Supplier, Predicate, String)} - */ - @Deprecated - public static <T> void assertContinually(Map flags=[:], Supplier<? extends T> supplier, Predicate<T> predicate, String errMsg, long durationMs) { - flags.put("duration", Duration.millis(durationMs)); - Asserts.continually(flags, supplier, predicate, errMsg); - } - - /** - * @deprecated since 0.5; use {@link Asserts#continually(Map, Supplier, Predicate, String)} - */ - @Deprecated - public static <T> void assertContinually(Map flags=[:], Supplier<? extends T> supplier, Predicate<T> predicate, String errMsg) { - Asserts.continually(flags, supplier, predicate, errMsg); - } - - public static class BooleanWithMessage { - boolean value; String message; - public BooleanWithMessage(boolean value, String message) { - this.value = value; this.message = message; - } - public boolean asBoolean() { - return value - } - public String toString() { - return message - } - } - - /** - * @deprecated since 0.5; use {@link brooklyn.util.ResourceUtils} - */ - @Deprecated - public static File getResource(String path, ClassLoader loader) { - URL resource = loader.getResource(path) - if (resource==null) - throw new IllegalArgumentException("cannot find required entity '"+path+"'"); - - return new File(resource.path) - } - - /** - * @deprecated since 0.5; use long and {@link TimeUnit} - */ - @Deprecated - public static TimeDuration toTimeDuration(Object duration) { - return toTimeDuration(duration, null); - } - - /** - * @deprecated since 0.5; use long and {@link TimeUnit} - */ - @Deprecated - public static TimeDuration toTimeDuration(Object duration, TimeDuration defaultVal) { - if (duration == null) { - return defaultVal; - } else if (duration instanceof TimeDuration) { - return (TimeDuration) duration - } else if (duration instanceof Number) { - return new TimeDuration(0,0,0,(int)duration) - // TODO would be nice to have this, but we need to sort out utils / test-utils dependency -// } else if (duration instanceof String) { -// return Time.parseTimeString((String)duration); - } else { - throw new IllegalArgumentException("Cannot convert $duration of type ${duration.class.name} to a TimeDuration") - } - } - - public static Throwable unwrapThrowable(Throwable t) { - if (t.getCause() == null) { - return t; - } else if (t instanceof ExecutionException) { - return unwrapThrowable(t.getCause()) - } else if (t instanceof InvokerInvocationException) { - return unwrapThrowable(t.getCause()) - } else { - return t - } - } - - /** - * @deprecated since 0.5; use {@link EntityTestUtils#assertAttributeEqualsEventually(Entity, AttributeSensor, Object)} - */ - @Deprecated - public static <T> void assertAttributeEventually(Entity entity, AttributeSensor<T> attribute, T expected) { - executeUntilSucceeds() { - assertEquals(entity.getAttribute(attribute), expected); - } - } - - /** - * @deprecated since 0.5; use {@link EntityTestUtils#assertAttributeEqualsContinually(Entity, AttributeSensor, Object)} - */ - @Deprecated - public static <T> void assertAttributeContinually(Entity entity, AttributeSensor<T> attribute, T expected) { - assertSucceedsContinually() { - assertEquals(entity.getAttribute(attribute), expected); - } - } - - /** - * @deprecated since 0.5; use {@link HttpTestUtils#assertHttpStatusCodeEquals(String, int)} - */ - @Deprecated - public static void assertUrlStatusCodeEventually(final String url, final int expected) { - executeUntilSucceeds() { - assertEquals(urlRespondsStatusCode(url), expected); - } - } - - /** - * @deprecated since 0.5; use {@link Asserts#assertFails(Runnable)} - */ - @Deprecated - public static void assertFails(Runnable c) { - assertFailsWith(c, (Predicate)null); - } - - /** - * @deprecated since 0.5; use {@link Asserts#assertFailsWith(Closure)} - */ - @Deprecated - public static void assertFailsWith(Runnable c, Closure exceptionChecker) { - assertFailsWith(c, exceptionChecker as Predicate); - } - - /** - * @deprecated since 0.5; use {@link Asserts#assertFailsWith(Runnable, Class, Class...)} - */ - @Deprecated - public static void assertFailsWith(Runnable c, final Class<? extends Throwable> validException, final Class<? extends Throwable> ...otherValidExceptions) { - assertFailsWith(c, { e -> - if (validException.isInstance(e)) return true; - if (otherValidExceptions.find {it.isInstance(e)}) return true; - List expectedTypes = [validException]; - expectedTypes.addAll(Arrays.asList(otherValidExceptions)); - fail("Test threw exception of unexpected type "+e.getClass()+"; expecting "+expectedTypes); - }); - } - - /** - * @deprecated since 0.5; use {@link Asserts#assertFailsWith(Runnable, Predicate)} - */ - @Deprecated - public static void assertFailsWith(Runnable c, Predicate<Throwable> exceptionChecker) { - boolean failed = false; - try { - c.run(); - } catch (Throwable e) { - failed = true; - if (exceptionChecker!=null) { - if (!exceptionChecker.apply(e)) { - fail("Test threw invalid exception: "+e); - } - } - log.debug("Test for exception successful ("+e+")"); - } - if (!failed) fail("Test code should have thrown exception but did not"); - } - - public static void assertSetsEqual(Collection c1, Collection c2) { - Set s = new LinkedHashSet(); - s.addAll(c1); s.removeAll(c2); - if (!s.isEmpty()) fail("First argument contains additional contents: "+s); - s.clear(); s.addAll(c2); s.removeAll(c1); - if (!s.isEmpty()) fail("Second argument contains additional contents: "+s); - } - - /** - * @deprecated since 0.5; use {@code assertFalse(Iterables.isEmpty(c))} - */ - @Deprecated - public static <T> void assertNonEmpty(Iterable<T> c) { - if (c.iterator().hasNext()) return; - fail("Expected non-empty set"); - } - - /** - * @deprecated since 0.5; use {@code assertEquals(Iterables.size(c), expectedSize)} - */ - @Deprecated - public static <T> void assertSize(Iterable<T> c, int expectedSize) { - int actualSize = Iterables.size(c); - if (actualSize==expectedSize) return; - fail("Expected collection of size "+expectedSize+" but got size "+actualSize+": "+c); - } - - /** - * @deprecated since 0.7.0; use {@link Asserts#assertThat(Object, Predicate)} with {@link StringFunctions})} - */ - @Deprecated - public static void assertStringContainsLiteral(String string, String substring) { - if (string==null) fail("String is null"); - if (substring==null) fail("Substring is null"); - if (string.indexOf(substring)>=0) return; - fail("String '"+string+"' does not contain expected pattern '"+substring+"'"); - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/brooklyn/test/TrustingSslSocketFactory.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/brooklyn/test/TrustingSslSocketFactory.java b/usage/test-support/src/main/java/brooklyn/test/TrustingSslSocketFactory.java deleted file mode 100644 index 3cbd94a..0000000 --- a/usage/test-support/src/main/java/brooklyn/test/TrustingSslSocketFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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 brooklyn.test; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.URLConnection; -import java.net.UnknownHostException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Throwables; - -// FIXME copied from brooklyn-core because core not visible here - -public class TrustingSslSocketFactory extends SSLSocketFactory { - - private static final Logger logger = LoggerFactory.getLogger(TrustingSslSocketFactory.class); - - private static TrustingSslSocketFactory INSTANCE; - public synchronized static TrustingSslSocketFactory getInstance() { - if (INSTANCE==null) INSTANCE = new TrustingSslSocketFactory(); - return INSTANCE; - } - - private static SSLContext sslContext; - static { - try { - sslContext = SSLContext.getInstance("TLS"); - } catch (Exception e) { - logger.error("Unable to set up SSLContext with TLS. Https activity will likely fail.", e); - } - } - - /** configures a connection to accept all certificates, if it is for https */ - public static <T extends URLConnection> T configure(T connection) { - if (connection instanceof HttpsURLConnection) { - ((HttpsURLConnection)connection).setSSLSocketFactory(getInstance()); - } - return connection; - } - - /** trusts all SSL certificates */ - public static final TrustManager TRUST_ALL = new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws java.security.cert.CertificateException { - - } - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws java.security.cert.CertificateException { - } - }; - - // no reason this can't be public, but no reason it should be necessary; - // just use getInstance to get the shared INSTANCE - protected TrustingSslSocketFactory() { - super(); - try { - sslContext.init(null, new TrustManager[] { TRUST_ALL }, null); - } catch (Exception e) { - throw Throwables.propagate(e); - } - } - - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } - - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } - - @Override - public String[] getDefaultCipherSuites() { - return sslContext.getSocketFactory().getDefaultCipherSuites(); - } - - @Override - public String[] getSupportedCipherSuites() { - return sslContext.getSocketFactory().getSupportedCipherSuites(); - } - - @Override - public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(arg0, arg1); - } - - @Override - public Socket createSocket(InetAddress arg0, int arg1) throws IOException { - return sslContext.getSocketFactory().createSocket(arg0, arg1); - } - - @Override - public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(arg0, arg1, arg2, arg3); - } - - @Override - public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException { - return sslContext.getSocketFactory().createSocket(arg0, arg1, arg2, arg3); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/brooklyn/test/WebAppMonitor.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/brooklyn/test/WebAppMonitor.java b/usage/test-support/src/main/java/brooklyn/test/WebAppMonitor.java deleted file mode 100644 index 2d0a457..0000000 --- a/usage/test-support/src/main/java/brooklyn/test/WebAppMonitor.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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 brooklyn.test; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -import org.slf4j.Logger; -import org.testng.Assert; - -import brooklyn.util.collections.MutableMap; -import brooklyn.util.time.Duration; - -/** - * Repeatedly polls a given URL, to check if it is always available. - * - * @author Alex, Aled - */ -public class WebAppMonitor implements Runnable { - final AtomicBoolean shouldBeActive = new AtomicBoolean(true); - final AtomicBoolean isActive = new AtomicBoolean(false); - final AtomicInteger successes = new AtomicInteger(0); - final AtomicInteger failures = new AtomicInteger(0); - final AtomicLong lastTime = new AtomicLong(-1); - final AtomicReference<Object> lastStatus = new AtomicReference<Object>(null); - final AtomicReference<Object> lastFailure = new AtomicReference<Object>(null); - Logger log; - Object problem = null; - String url; - long delayMillis = 500; - int expectedResponseCode = 200; - - public WebAppMonitor(String url) { - this.url = url; - } - public WebAppMonitor() { - } - public WebAppMonitor logFailures(Logger log) { - this.log = log; - return this; - } - public WebAppMonitor delayMillis(long val) { - this.delayMillis = val; - return this; - } - public WebAppMonitor expectedResponseCode(int val) { - this.expectedResponseCode = val; - return this; - } - public WebAppMonitor url(String val) { - this.url = val; - return this; - } - - public void run() { - synchronized (isActive) { - if (isActive.getAndSet(true)) - throw new IllegalStateException("already running"); - } - while (shouldBeActive.get()) { - long startTime = System.currentTimeMillis(); - try { - if (preAttempt()) { - int code = HttpTestUtils.getHttpStatusCode(url); - lastTime.set(System.currentTimeMillis() - startTime); - lastStatus.set(code); - if (isResponseOkay(code)) { - successes.incrementAndGet(); - } else { - lastFailure.set(code); - failures.incrementAndGet(); - onFailure("return code "+code); - } - } - } catch (Exception e) { - lastTime.set(System.currentTimeMillis()-startTime); - lastStatus.set(e); - lastFailure.set(e); - failures.incrementAndGet(); - onFailure(e); - } - try { - if (delayMillis > 0) { - Thread.sleep(delayMillis); - } - } catch (InterruptedException e) { - onFailure(e); - shouldBeActive.set(false); - } - } - synchronized (isActive) { - if (!isActive.getAndSet(false)) - throw new IllegalStateException("shouldn't be possible!"); - isActive.notifyAll(); - } - } - - public boolean isResponseOkay(Object code) { - return code!=null && new Integer(expectedResponseCode).equals(code); - } - - public void setDelayMillis(long delayMillis) { - this.delayMillis = delayMillis; - } - public long getDelayMillis() { - return delayMillis; - } - public void terminate() throws InterruptedException { - shouldBeActive.set(false); - synchronized (isActive) { - while (isActive.get()) isActive.wait(); - } - } - public int getFailures() { - return failures.get(); - } - public int getSuccesses() { - return successes.get(); - } - public void setUrl(String url) { - this.url = url; - } - public String getUrl() { - return url; - } - public Object getProblem() { - return problem; - } - public int getAttempts() { - return getFailures()+getSuccesses(); - } - public boolean getLastWasFailed() { - return isResponseOkay(getLastStatus()); - } - public Object getLastStatus() { - return lastStatus.get(); - } - public long getLastTime() { - return lastTime.get(); - } - /** result code (int) or exception */ - public Object getLastFailure() { - return lastFailure.get(); - } - - public void onFailure(Object problem) { - if (log != null) { - log.warn("Detected failure in monitor accessing "+getUrl()+": "+problem); - } - this.problem = problem; - } - - /** return false to skip a run */ - public boolean preAttempt() { - return true; - } - - public WebAppMonitor assertNoFailures(String message) { - return assertSuccessFraction(message, 1.0); - } - public WebAppMonitor assertAttemptsMade(int minAttempts, String message) { - if (getAttempts()<minAttempts) { - Assert.fail(message+" -- webapp access failures! " + - "(0 attempts made; probably blocked on server)"); - } - return this; - } - public WebAppMonitor waitForAtLeastOneAttempt() { - return waitForAtLeastOneAttempt(Asserts.DEFAULT_TIMEOUT); - } - public WebAppMonitor waitForAtLeastOneAttempt(Duration timeout) { - Asserts.succeedsEventually(MutableMap.of("timeout", timeout), new Runnable() { - @Override public void run() { - Assert.assertTrue(getAttempts() >= 1); - }}); - return this; - } - public WebAppMonitor assertSuccessFraction(String message, double fraction) { - int failures = getFailures(); - int attempts = getAttempts(); - if ((failures > (1-fraction) * attempts + 0.0001) || attempts <= 0) { - Assert.fail(message+" -- webapp access failures! " + - "("+failures+" failed of "+attempts+" monitoring attempts) against "+getUrl()+"; " + - "last was "+getLastStatus()+" taking "+getLastTime()+"ms" + - (getLastFailure() != null ? "; last failure was "+getLastFailure() : "")); - } - return this; - } - public WebAppMonitor resetCounts() { - failures.set(0); - successes.set(0); - return this; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/org/apache/brooklyn/test/EntityTestUtils.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/EntityTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/EntityTestUtils.java new file mode 100644 index 0000000..3bceb78 --- /dev/null +++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/EntityTestUtils.java @@ -0,0 +1,181 @@ +/* + * 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.brooklyn.test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import brooklyn.config.ConfigKey; +import brooklyn.entity.Entity; +import brooklyn.entity.Group; +import brooklyn.entity.basic.EntityLocal; +import brooklyn.event.AttributeSensor; +import brooklyn.event.SensorEvent; +import brooklyn.event.SensorEventListener; +import brooklyn.management.SubscriptionHandle; +import brooklyn.test.Asserts; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class EntityTestUtils { + + // TODO would be nice to have this... perhaps moving this class, or perhaps this whole project, to core/src/test ? +// public static LocalManagementContext newManagementContext() { return new LocalManagementContextForTests(); } + + // TODO Delete methods from TestUtils, to just have them here (or switch so TestUtils delegates here, + // and deprecate methods in TestUtils until deleted). + + public static <T> void assertAttributeEquals(Entity entity, AttributeSensor<T> attribute, T expected) { + assertEquals(entity.getAttribute(attribute), expected, "entity="+entity+"; attribute="+attribute); + } + + public static <T> void assertConfigEquals(Entity entity, ConfigKey<T> configKey, T expected) { + assertEquals(entity.getConfig(configKey), expected, "entity="+entity+"; configKey="+configKey); + } + + public static <T> void assertAttributeEqualsEventually(final Entity entity, final AttributeSensor<T> attribute, final T expected) { + assertAttributeEqualsEventually(Maps.newLinkedHashMap(), entity, attribute, expected); + } + + public static <T> void assertAttributeEqualsEventually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final T expected) { + // Not using assertAttributeEventually(predicate) so get nicer error message + Asserts.succeedsEventually((Map)flags, new Runnable() { + @Override public void run() { + assertAttributeEquals(entity, attribute, expected); + }}); + } + + public static <T> T assertAttributeEventuallyNonNull(final Entity entity, final AttributeSensor<T> attribute) { + return assertAttributeEventuallyNonNull(Maps.newLinkedHashMap(), entity, attribute); + } + + public static <T> T assertAttributeEventuallyNonNull(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute) { + return assertAttributeEventually(flags, entity, attribute, Predicates.notNull()); + } + + public static <T> T assertAttributeEventually(final Entity entity, final AttributeSensor<T> attribute, Predicate<? super T> predicate) { + return assertAttributeEventually(ImmutableMap.of(), entity, attribute, predicate); + } + + public static <T> T assertAttributeEventually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final Predicate<? super T> predicate) { + final AtomicReference<T> result = new AtomicReference<T>(); + Asserts.succeedsEventually((Map)flags, new Runnable() { + @Override public void run() { + T val = entity.getAttribute(attribute); + assertTrue(predicate.apply(val), "val="+val); + result.set(val); + }}); + return result.get(); + } + + public static <T> T assertAttribute(final Entity entity, final AttributeSensor<T> attribute, final Predicate<? super T> predicate) { + T val = entity.getAttribute(attribute); + assertTrue(predicate.apply(val), "val="+val); + return val; + } + + public static <T extends Entity> void assertPredicateEventuallyTrue(final T entity, final Predicate<? super T> predicate) { + assertPredicateEventuallyTrue(Maps.newLinkedHashMap(), entity, predicate); + } + + public static <T extends Entity> void assertPredicateEventuallyTrue(Map<?,?> flags, final T entity, final Predicate<? super T> predicate) { + Asserts.succeedsEventually((Map)flags, new Runnable() { + @Override public void run() { + assertTrue(predicate.apply(entity)); + }}); + } + + public static <T> void assertAttributeEqualsContinually(final Entity entity, final AttributeSensor<T> attribute, final T expected) { + assertAttributeEqualsContinually(Maps.newLinkedHashMap(), entity, attribute, expected); + } + + public static <T> void assertAttributeEqualsContinually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final T expected) { + Asserts.succeedsContinually(flags, new Runnable() { + @Override public void run() { + assertAttributeEquals(entity, attribute, expected); + }}); + } + + public static void assertGroupSizeEqualsEventually(final Group group, int expected) { + assertGroupSizeEqualsEventually(ImmutableMap.of(), group, expected); + } + + public static void assertGroupSizeEqualsEventually(Map<?,?> flags, final Group group, final int expected) { + Asserts.succeedsEventually((Map)flags, new Runnable() { + @Override public void run() { + Collection<Entity> members = group.getMembers(); + assertEquals(members.size(), expected, "members="+members); + }}); + } + + /** checks that the entity's value for this attribute changes, by registering a subscription and checking the value */ + public static void assertAttributeChangesEventually(final Entity entity, final AttributeSensor<?> attribute) { + final Object origValue = entity.getAttribute(attribute); + final AtomicBoolean changed = new AtomicBoolean(); + SubscriptionHandle handle = ((EntityLocal)entity).subscribe(entity, attribute, new SensorEventListener<Object>() { + @Override public void onEvent(SensorEvent<Object> event) { + if (!Objects.equal(origValue, event.getValue())) { + changed.set(true); + } + }}); + try { + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + assertTrue(changed.get(), entity+" -> "+attribute+" not changed"); + }}); + } finally { + ((EntityLocal)entity).unsubscribe(entity, handle); + } + } + + /** alternate version of {@link #assertAttributeChangesEventually(Entity, AttributeSensor)} not using subscriptions and + * with simpler code, for comparison */ + @Beta + public static <T> void assertAttributeChangesEventually2(final Entity entity, final AttributeSensor<T> attribute) { + assertAttributeEventually(entity, attribute, + Predicates.not(Predicates.equalTo(entity.getAttribute(attribute)))); + } + + @Beta + public static <T> void assertAttributeNever(final Entity entity, final AttributeSensor<T> attribute, T... disallowed) { + final Set<T> reject = Sets.newHashSet(disallowed); + Asserts.succeedsContinually(new Runnable() { + @Override + public void run() { + T val = entity.getAttribute(attribute); + assertFalse(reject.contains(val), + "Attribute " + attribute + " on " + entity + " has disallowed value " + val); + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java new file mode 100644 index 0000000..455bc7e --- /dev/null +++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java @@ -0,0 +1,392 @@ +/* + * 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.brooklyn.test; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; + +import brooklyn.test.Asserts; +import brooklyn.util.collections.MutableMap; +import brooklyn.util.crypto.SslTrustUtils; +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.stream.Streams; +import brooklyn.util.time.Time; + +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + +/** + * Utility methods to aid testing HTTP. + * + * @author aled + */ +public class HttpTestUtils { + + // TODO Delete methods from TestUtils, to just have them here (or switch so TestUtils delegates here, + // and deprecate methods in TestUtils until deleted). + + private static final Logger LOG = LoggerFactory.getLogger(HttpTestUtils.class); + + static final ExecutorService executor = Executors.newCachedThreadPool(); + + /** + * Connects to the given url and returns the connection. + * Caller should {@code connection.getInputStream().close()} the result of this + * (especially if they are making heavy use of this method). + */ + public static URLConnection connectToUrl(String u) throws Exception { + final URL url = new URL(u); + final AtomicReference<Exception> exception = new AtomicReference<Exception>(); + + // sometimes openConnection hangs, so run in background + Future<URLConnection> f = executor.submit(new Callable<URLConnection>() { + public URLConnection call() { + try { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @Override public boolean verify(String s, SSLSession sslSession) { + return true; + } + }); + URLConnection connection = url.openConnection(); + TrustingSslSocketFactory.configure(connection); + connection.connect(); + + connection.getContentLength(); // Make sure the connection is made. + return connection; + } catch (Exception e) { + exception.set(e); + LOG.debug("Error connecting to url "+url+" (propagating): "+e, e); + } + return null; + } + }); + try { + URLConnection result = null; + try { + result = f.get(60, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw e; + } catch (Exception e) { + LOG.debug("Error connecting to url "+url+", probably timed out (rethrowing): "+e); + throw new IllegalStateException("Connect to URL not complete within 60 seconds, for url "+url+": "+e); + } + if (exception.get() != null) { + LOG.debug("Error connecting to url "+url+", thread caller of "+exception, new Throwable("source of rethrown error "+exception)); + throw exception.get(); + } else { + return result; + } + } finally { + f.cancel(true); + } + } + + public static void assertHealthyStatusCode(int code) { + if (code>=200 && code<=299) return; + Assert.fail("Wrong status code: "+code); + } + + public static int getHttpStatusCode(String url) throws Exception { + URLConnection connection = connectToUrl(url); + long startTime = System.currentTimeMillis(); + int status = ((HttpURLConnection) connection).getResponseCode(); + + // read fully if possible, then close everything, trying to prevent cached threads at server + consumeAndCloseQuietly((HttpURLConnection) connection); + + if (LOG.isDebugEnabled()) + LOG.debug("connection to {} ({}ms) gives {}", new Object[] { url, (System.currentTimeMillis()-startTime), status }); + return status; + } + + /** + * Asserts that gets back any "valid" response - i.e. not an exception. This could be an unauthorized, + * a redirect, a 404, or anything else that implies there is web-server listening on that port. + */ + public static void assertUrlReachable(String url) { + try { + getHttpStatusCode(url); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted for "+url+" (in assertion that is reachable)", e); + } catch (Exception e) { + throw new IllegalStateException("Server at "+url+" failed to respond (in assertion that is reachable): "+e, e); + } + } + + public static void assertUrlUnreachable(String url) { + try { + int statusCode = getHttpStatusCode(url); + fail("Expected url "+url+" unreachable, but got status code "+statusCode); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted for "+url+" (in assertion that unreachable)", e); + } catch (Exception e) { + IOException cause = Exceptions.getFirstThrowableOfType(e, IOException.class); + if (cause != null) { + // success; clean shutdown transitioning from 400 to error + } else { + Throwables.propagate(e); + } + } + } + + public static void assertUrlUnreachableEventually(final String url) { + assertUrlUnreachableEventually(Maps.newLinkedHashMap(), url); + } + + public static void assertUrlUnreachableEventually(Map flags, final String url) { + Asserts.succeedsEventually(flags, new Runnable() { + public void run() { + assertUrlUnreachable(url); + } + }); + } + + public static void assertHttpStatusCodeEquals(String url, int... acceptableReturnCodes) { + List<Integer> acceptableCodes = Lists.newArrayList(); + for (int code : acceptableReturnCodes) { + acceptableCodes.add((Integer)code); + } + try { + int actualCode = getHttpStatusCode(url); + assertTrue(acceptableCodes.contains(actualCode), "code="+actualCode+"; expected="+acceptableCodes+"; url="+url); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted for "+url+" (in assertion that result code is "+acceptableCodes+")", e); + } catch (Exception e) { + throw new IllegalStateException("Server at "+url+" failed to respond (in assertion that result code is "+acceptableCodes+"): "+e, e); + } + } + + public static void assertHttpStatusCodeEventuallyEquals(final String url, final int expectedCode) { + assertHttpStatusCodeEventuallyEquals(Maps.newLinkedHashMap(), url, expectedCode); + } + + public static void assertHttpStatusCodeEventuallyEquals(Map flags, final String url, final int expectedCode) { + Asserts.succeedsEventually(flags, new Runnable() { + public void run() { + assertHttpStatusCodeEquals(url, expectedCode); + } + }); + } + + public static void assertContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { + try { + String contents = getContent(url); + Assert.assertTrue(contents != null && contents.length() > 0); + for (String text: Lists.asList(phrase, additionalPhrases)) { + if (!contents.contains(text)) { + LOG.warn("CONTENTS OF URL "+url+" MISSING TEXT: "+text+"\n"+contents); + Assert.fail("URL "+url+" does not contain text: "+text); + } + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + public static void assertContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { + try { + String contents = getContent(url); + Assert.assertTrue(contents != null); + for (String text: Lists.asList(phrase, additionalPhrases)) { + if (contents.contains(text)) { + LOG.warn("CONTENTS OF URL "+url+" HAS TEXT: "+text+"\n"+contents); + Assert.fail("URL "+url+" contain text: "+text); + } + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + public static void assertErrorContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { + try { + String contents = getErrorContent(url); + Assert.assertTrue(contents != null && contents.length() > 0); + for (String text: Lists.asList(phrase, additionalPhrases)) { + if (!contents.contains(text)) { + LOG.warn("CONTENTS OF URL "+url+" MISSING TEXT: "+text+"\n"+contents); + Assert.fail("URL "+url+" does not contain text: "+text); + } + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + + public static void assertErrorContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { + try { + String err = getErrorContent(url); + Assert.assertTrue(err != null); + for (String text: Lists.asList(phrase, additionalPhrases)) { + if (err.contains(text)) { + LOG.warn("CONTENTS OF URL "+url+" HAS TEXT: "+text+"\n"+err); + Assert.fail("URL "+url+" contain text: "+text); + } + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + public static void assertContentEventuallyContainsText(final String url, final String phrase, final String ...additionalPhrases) { + assertContentEventuallyContainsText(MutableMap.of(), url, phrase, additionalPhrases); + } + + public static void assertContentEventuallyContainsText(Map flags, final String url, final String phrase, final String ...additionalPhrases) { + Asserts.succeedsEventually(flags, new Runnable() { + public void run() { + assertContentContainsText(url, phrase, additionalPhrases); + } + }); + } + + public static void assertContentMatches(String url, String regex) { + String contents = getContent(url); + Assert.assertNotNull(contents); + Assert.assertTrue(contents.matches(regex), "Contents does not match expected regex ("+regex+"): "+contents); + } + + public static void assertContentEventuallyMatches(final String url, final String regex) { + Asserts.succeedsEventually(new Runnable() { + @Override + public void run() { + assertContentMatches(url, regex); + } + }); + } + + public static String getErrorContent(String url) { + try { + HttpURLConnection connection = (HttpURLConnection) connectToUrl(url); + long startTime = System.currentTimeMillis(); + + String err; + int status; + try { + InputStream errStream = connection.getErrorStream(); + err = Streams.readFullyString(errStream); + status = connection.getResponseCode(); + } finally { + closeQuietly(connection); + } + + if (LOG.isDebugEnabled()) + LOG.debug("read of err {} ({}ms) complete; http code {}", new Object[] { url, Time.makeTimeStringRounded(System.currentTimeMillis()-startTime), status}); + return err; + + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + public static String getContent(String url) { + try { + return Streams.readFullyString(SslTrustUtils.trustAll(new URL(url).openConnection()).getInputStream()); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + /** + * Schedules (with the given executor) a poller that repeatedly accesses the given url, to confirm it always gives + * back the expected status code. + * + * Expected usage is to query the future, such as: + * + * <pre> + * {@code + * Future<?> future = assertAsyncHttpStatusCodeContinuallyEquals(executor, url, 200); + * // do other stuff... + * if (future.isDone()) future.get(); // get exception if it's failed + * } + * </pre> + * + * For stopping it, you can either do future.cancel(true), or you can just do executor.shutdownNow(). + * + * TODO Look at difference between this and WebAppMonitor, to decide if this should be kept. + */ + public static ListenableFuture<?> assertAsyncHttpStatusCodeContinuallyEquals(ListeningExecutorService executor, final String url, final int expectedStatusCode) { + return executor.submit(new Runnable() { + @Override public void run() { + // TODO Need to drop logging; remove sleep when that's done. + while (!Thread.currentThread().isInterrupted()) { + assertHttpStatusCodeEquals(url, expectedStatusCode); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return; // graceful return + } + } + } + }); + } + + /** + * Consumes the input stream entirely and then cleanly closes the connection. + * Ignores all exceptions completely, not even logging them! + * + * Consuming the stream fully is useful for preventing idle TCP connections. + * See {@linkplain http://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html}. + */ + public static void consumeAndCloseQuietly(HttpURLConnection connection) { + try { Streams.readFully(connection.getInputStream()); } catch (Exception e) {} + closeQuietly(connection); + } + + /** + * Closes all streams of the connection, and disconnects it. Ignores all exceptions completely, + * not even logging them! + */ + public static void closeQuietly(HttpURLConnection connection) { + try { connection.disconnect(); } catch (Exception e) {} + try { connection.getInputStream().close(); } catch (Exception e) {} + try { connection.getOutputStream().close(); } catch (Exception e) {} + try { connection.getErrorStream().close(); } catch (Exception e) {} + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/org/apache/brooklyn/test/NetworkingTestUtils.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/NetworkingTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/NetworkingTestUtils.java new file mode 100644 index 0000000..9811776 --- /dev/null +++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/NetworkingTestUtils.java @@ -0,0 +1,69 @@ +/* + * 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.brooklyn.test; + +import static org.testng.Assert.assertTrue; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.test.Asserts; +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.net.Networking; +import brooklyn.util.time.Duration; + +import com.google.common.collect.ImmutableMap; + +public class NetworkingTestUtils { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkingTestUtils.class); + + public static void assertPortsAvailableEventually(final Map<String, Integer> ports) { + // If we get into a TCP TIMED-WAIT state, it could take 4 minutes for the port to come available. + // Could that be causing our integration tests to fail sometimes when run in the suite?! + // Let's wait for the required ports in setup, rather than running+failing the test. + assertPortsAvailableEventually(ports, Duration.minutes(4)); + } + + public static void assertPortsAvailableEventually(final Map<String, Integer> ports, final Duration timeout) { + Asserts.succeedsEventually(ImmutableMap.of("timeout", Duration.minutes(4)), new Runnable() { + private boolean logged = false; + public void run() { + try { + assertPortsAvailable(ports); + } catch (Throwable t) { + if (!logged) { + LOG.warn("Port(s) not available; waiting for up to "+timeout+" ("+Exceptions.getFirstInteresting(t)+")"); + logged = true; + } + throw Exceptions.propagate(t); + } + }}); + LOG.debug("Ports are available: "+ports); + } + + public static void assertPortsAvailable(final Map<String, Integer> ports) { + for (Map.Entry<String, Integer> entry : ports.entrySet()) { + String errmsg = "port "+entry.getValue()+" not available for "+entry.getKey(); + assertTrue(Networking.isPortAvailable(entry.getValue()), errmsg); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9e04407d/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java ---------------------------------------------------------------------- diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java new file mode 100644 index 0000000..2b765cd --- /dev/null +++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java @@ -0,0 +1,99 @@ +/* + * 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.brooklyn.test; + +import java.lang.management.ManagementFactory; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.util.time.Duration; +import brooklyn.util.time.Time; + +import com.google.common.base.Stopwatch; + +public class PerformanceTestUtils { + + private static final Logger LOG = LoggerFactory.getLogger(PerformanceTestUtils.class); + + private static boolean hasLoggedProcessCpuTimeUnavailable; + + public static long getProcessCpuTime() { + try { + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + ObjectName osMBeanName = ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); + return (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime"); + } catch (Exception e) { + if (!hasLoggedProcessCpuTimeUnavailable) { + hasLoggedProcessCpuTimeUnavailable = true; + LOG.warn("ProcessCPuTime not available in local JVM MXBean "+ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME+" (only available in sun JVM?)"); + } + return -1; + } + } + + /** + * Creates a background thread that will log.info the CPU fraction usage repeatedly, sampling at the given period. + * Callers <em>must</em> cancel the returned future, e.g. {@code future.cancel(true)}, otherwise it will keep + * logging until the JVM exits. + */ + public static Future<?> sampleProcessCpuTime(final Duration period, final String loggingContext) { + final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "brooklyn-sampleProcessCpuTime-"+loggingContext); + thread.setDaemon(true); // let the JVM exit + return thread; + }}); + Future<?> future = executor.submit(new Runnable() { + @Override public void run() { + try { + long prevCpuTime = getProcessCpuTime(); + if (prevCpuTime == -1) { + LOG.warn("ProcessCPuTime not available; cannot sample; aborting"); + return; + } + while (true) { + Stopwatch stopwatch = Stopwatch.createStarted(); + Thread.sleep(period.toMilliseconds()); + long currentCpuTime = getProcessCpuTime(); + + long elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS); + double fractionCpu = (elapsedTime > 0) ? ((double)currentCpuTime-prevCpuTime) / TimeUnit.MILLISECONDS.toNanos(elapsedTime) : -1; + prevCpuTime = currentCpuTime; + + LOG.info("CPU fraction over last {} was {} ({})", new Object[] { + Time.makeTimeStringRounded(elapsedTime), fractionCpu, loggingContext}); + } + } catch (InterruptedException e) { + return; // graceful termination + } finally { + executor.shutdownNow(); + } + }}); + return future; + } +}
