Add unit tests for HttpAsserts.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/885b6ac4 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/885b6ac4 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/885b6ac4 Branch: refs/heads/master Commit: 885b6ac47c4a72a400ef16c9a11555f1e980eb64 Parents: 70a7189 Author: Geoff Macartney <[email protected]> Authored: Tue Nov 3 17:13:44 2015 +0000 Committer: Geoff Macartney <[email protected]> Committed: Tue Nov 3 17:38:11 2015 +0000 ---------------------------------------------------------------------- .../core/sensor/http/HttpRequestSensorTest.java | 5 +- .../core/test/TestHttpRequestHandler.java | 72 ----- .../brooklyn/core/test/TestHttpServer.java | 143 --------- .../util/core/ResourceUtilsHttpTest.java | 5 +- .../rest/resources/CatalogResetTest.java | 4 +- utils/common/pom.xml | 8 +- .../test/http/TestHttpRequestHandler.java | 72 +++++ .../brooklyn/test/http/TestHttpServer.java | 146 +++++++++ .../apache/brooklyn/util/http/HttpAsserts.java | 108 +++++-- .../apache/brooklyn/util/HttpAssertsTest.java | 293 +++++++++++++++++++ 10 files changed, 600 insertions(+), 256 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java index 0e7495f..20169a9 100644 --- a/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java @@ -25,9 +25,8 @@ import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.core.sensor.http.HttpRequestSensor; -import org.apache.brooklyn.core.test.TestHttpRequestHandler; -import org.apache.brooklyn.core.test.TestHttpServer; +import org.apache.brooklyn.test.http.TestHttpRequestHandler; +import org.apache.brooklyn.test.http.TestHttpServer; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.test.EntityTestUtils; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/core/src/test/java/org/apache/brooklyn/core/test/TestHttpRequestHandler.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/TestHttpRequestHandler.java b/core/src/test/java/org/apache/brooklyn/core/test/TestHttpRequestHandler.java deleted file mode 100644 index d4ab712..0000000 --- a/core/src/test/java/org/apache/brooklyn/core/test/TestHttpRequestHandler.java +++ /dev/null @@ -1,72 +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 org.apache.brooklyn.core.test; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Collection; - -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.entity.StringEntity; -import org.apache.http.message.BasicHeader; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpRequestHandler; - -public class TestHttpRequestHandler implements HttpRequestHandler { - private HttpEntity entity; - private int responseCode = HttpStatus.SC_OK; - private Collection<Header> headers = new ArrayList<Header>(); - - public TestHttpRequestHandler response(String response) { - try { - this.entity = new StringEntity(response); - } catch (UnsupportedEncodingException e) { - throw Exceptions.propagate(e); - } - return this; - } - - public TestHttpRequestHandler code(int responseCode) { - this.responseCode = responseCode; - return this; - } - - public TestHttpRequestHandler header(String name, String value) { - headers.add(new BasicHeader(name, value)); - return this; - } - - @Override - public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { - for (Header h : headers) { - response.setHeader(h); - } - - response.setStatusCode(responseCode); - response.setEntity(entity); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/core/src/test/java/org/apache/brooklyn/core/test/TestHttpServer.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/TestHttpServer.java b/core/src/test/java/org/apache/brooklyn/core/test/TestHttpServer.java deleted file mode 100644 index a9eb7df..0000000 --- a/core/src/test/java/org/apache/brooklyn/core/test/TestHttpServer.java +++ /dev/null @@ -1,143 +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 org.apache.brooklyn.core.test; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.List; - -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.net.Networking; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponseInterceptor; -import org.apache.http.impl.bootstrap.HttpServer; -import org.apache.http.impl.bootstrap.ServerBootstrap; -import org.apache.http.protocol.HttpProcessor; -import org.apache.http.protocol.HttpRequestHandler; -import org.apache.http.protocol.ImmutableHttpProcessor; -import org.apache.http.protocol.ResponseConnControl; -import org.apache.http.protocol.ResponseContent; - -public class TestHttpServer { - private static class HandlerTuple { - String path; - HttpRequestHandler handler; - public HandlerTuple(String path, HttpRequestHandler handler) { - this.path = path; - this.handler = handler; - } - } - private HttpServer server; - private List<HttpRequestInterceptor> requestInterceptors = MutableList.of(); - private List<HttpResponseInterceptor> responseInterceptors = MutableList.of(new ResponseContent(), new ResponseConnControl()); - private int basePort = 50505; - private Collection<HandlerTuple> handlers = MutableList.of(); - - public TestHttpServer interceptor(HttpResponseInterceptor interceptor) { - checkNotStarted(); - responseInterceptors.add(interceptor); - return this; - } - - public TestHttpServer requestInterceptors(List<HttpResponseInterceptor> interceptors) { - checkNotStarted(); - this.responseInterceptors = interceptors; - return this; - } - - public TestHttpServer interceptor(HttpRequestInterceptor interceptor) { - checkNotStarted(); - requestInterceptors.add(interceptor); - return this; - } - - public TestHttpServer responseInterceptors(List<HttpRequestInterceptor> interceptors) { - checkNotStarted(); - this.requestInterceptors = interceptors; - return this; - } - - public TestHttpServer basePort(int basePort) { - checkNotStarted(); - this.basePort = basePort; - return this; - } - - public TestHttpServer handler(String path, HttpRequestHandler handler) { - checkNotStarted(); - handlers.add(new HandlerTuple(path, handler)); - return this; - } - - public TestHttpServer start() { - checkNotStarted(); - - HttpProcessor httpProcessor = new ImmutableHttpProcessor(requestInterceptors, responseInterceptors); - int port = Networking.nextAvailablePort(basePort); - ServerBootstrap bootstrap = ServerBootstrap.bootstrap() - .setListenerPort(port) - .setLocalAddress(getLocalAddress()) - .setHttpProcessor(httpProcessor); - - for (HandlerTuple tuple : handlers) { - bootstrap.registerHandler(tuple.path, tuple.handler); - } - server = bootstrap.create(); - - try { - server.start(); - } catch (IOException e) { - throw Exceptions.propagate(e); - } - - return this; - } - - public void stop() { - server.stop(); - } - - private void checkNotStarted() { - if (server != null) { - throw new IllegalStateException("Server already started"); - } - } - - private InetAddress getLocalAddress() { - try { - return InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - throw Exceptions.propagate(e); - } - } - - public String getUrl() { - try { - return new URL("http", server.getInetAddress().getHostAddress(), server.getLocalPort(), "").toExternalForm(); - } catch (MalformedURLException e) { - throw Exceptions.propagate(e); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsHttpTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsHttpTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsHttpTest.java index c1cebb8..0952707 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsHttpTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsHttpTest.java @@ -24,9 +24,8 @@ import static org.testng.Assert.assertFalse; import java.io.IOException; import java.io.InputStream; -import org.apache.brooklyn.core.test.TestHttpRequestHandler; -import org.apache.brooklyn.core.test.TestHttpServer; -import org.apache.brooklyn.util.core.ResourceUtils; +import org.apache.brooklyn.test.http.TestHttpRequestHandler; +import org.apache.brooklyn.test.http.TestHttpServer; import org.apache.brooklyn.util.stream.Streams; import org.apache.brooklyn.util.text.Strings; import org.apache.http.HttpException; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java index 6adfdb5..c0e0089 100644 --- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java +++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java @@ -27,8 +27,8 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.apache.brooklyn.api.catalog.BrooklynCatalog; -import org.apache.brooklyn.core.test.TestHttpRequestHandler; -import org.apache.brooklyn.core.test.TestHttpServer; +import org.apache.brooklyn.test.http.TestHttpRequestHandler; +import org.apache.brooklyn.test.http.TestHttpServer; import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest; import org.apache.brooklyn.util.core.ResourceUtils; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/utils/common/pom.xml ---------------------------------------------------------------------- diff --git a/utils/common/pom.xml b/utils/common/pom.xml index 8bc0ae9..037dcd9 100644 --- a/utils/common/pom.xml +++ b/utils/common/pom.xml @@ -66,7 +66,13 @@ <artifactId>snakeyaml</artifactId> <version>${snakeyaml.version}</version> </dependency> - + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRequestHandler.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRequestHandler.java b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRequestHandler.java new file mode 100644 index 0000000..18f5c44 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRequestHandler.java @@ -0,0 +1,72 @@ +/* + * 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.http; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicHeader; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; + +public class TestHttpRequestHandler implements HttpRequestHandler { + private HttpEntity entity; + private int responseCode = HttpStatus.SC_OK; + private Collection<Header> headers = new ArrayList<Header>(); + + public TestHttpRequestHandler response(String response) { + try { + this.entity = new StringEntity(response); + } catch (UnsupportedEncodingException e) { + throw Exceptions.propagate(e); + } + return this; + } + + public TestHttpRequestHandler code(int responseCode) { + this.responseCode = responseCode; + return this; + } + + public TestHttpRequestHandler header(String name, String value) { + headers.add(new BasicHeader(name, value)); + return this; + } + + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + for (Header h : headers) { + response.setHeader(h); + } + + response.setStatusCode(responseCode); + response.setEntity(entity); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpServer.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpServer.java b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpServer.java new file mode 100644 index 0000000..75f5e60 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpServer.java @@ -0,0 +1,146 @@ +/* + * 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.http; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.List; + +import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.net.Networking; +import org.apache.http.HttpRequestInterceptor; +import org.apache.http.HttpResponseInterceptor; +import org.apache.http.impl.bootstrap.HttpServer; +import org.apache.http.impl.bootstrap.ServerBootstrap; +import org.apache.http.protocol.HttpProcessor; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.ImmutableHttpProcessor; +import org.apache.http.protocol.ResponseConnControl; +import org.apache.http.protocol.ResponseContent; + +public class TestHttpServer { + private static class HandlerTuple { + String path; + HttpRequestHandler handler; + public HandlerTuple(String path, HttpRequestHandler handler) { + this.path = path; + this.handler = handler; + } + } + private HttpServer server; + private List<HttpRequestInterceptor> requestInterceptors = MutableList.of(); + private List<HttpResponseInterceptor> responseInterceptors = MutableList.of(new ResponseContent(), new ResponseConnControl()); + private int basePort = 50505; + private Collection<HandlerTuple> handlers = MutableList.of(); + + public TestHttpServer interceptor(HttpResponseInterceptor interceptor) { + checkNotStarted(); + responseInterceptors.add(interceptor); + return this; + } + + public TestHttpServer requestInterceptors(List<HttpResponseInterceptor> interceptors) { + checkNotStarted(); + this.responseInterceptors = interceptors; + return this; + } + + public TestHttpServer interceptor(HttpRequestInterceptor interceptor) { + checkNotStarted(); + requestInterceptors.add(interceptor); + return this; + } + + public TestHttpServer responseInterceptors(List<HttpRequestInterceptor> interceptors) { + checkNotStarted(); + this.requestInterceptors = interceptors; + return this; + } + + public TestHttpServer basePort(int basePort) { + checkNotStarted(); + this.basePort = basePort; + return this; + } + + public TestHttpServer handler(String path, HttpRequestHandler handler) { + checkNotStarted(); + handlers.add(new HandlerTuple(path, handler)); + return this; + } + + public TestHttpServer start() { + checkNotStarted(); + + HttpProcessor httpProcessor = new ImmutableHttpProcessor(requestInterceptors, responseInterceptors); + int port = Networking.nextAvailablePort(basePort); + ServerBootstrap bootstrap = ServerBootstrap.bootstrap() + .setListenerPort(port) + .setLocalAddress(getLocalAddress()) + .setHttpProcessor(httpProcessor); + + for (HandlerTuple tuple : handlers) { + bootstrap.registerHandler(tuple.path, tuple.handler); + } + server = bootstrap.create(); + + try { + server.start(); + } catch (IOException e) { + throw Exceptions.propagate(e); + } + + return this; + } + + public void stop() { + if (null != server) { + server.stop(); + server = null; + } + } + + private void checkNotStarted() { + if (server != null) { + throw new IllegalStateException("Server already started"); + } + } + + private InetAddress getLocalAddress() { + try { + return InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + throw Exceptions.propagate(e); + } + } + + public String getUrl() { + try { + return new URL("http", server.getInetAddress().getHostAddress(), server.getLocalPort(), "").toExternalForm(); + } catch (MalformedURLException e) { + throw Exceptions.propagate(e); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java index 35d8252..0479b79 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java @@ -52,7 +52,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; /** - * Utility methods to aid testing HTTP. + * Utility assertions on HTTP. * * @author aled */ @@ -63,31 +63,26 @@ public class HttpAsserts { private static final Logger LOG = LoggerFactory.getLogger(HttpAsserts.class); + /** + * Assert that a 'successful' (2xx) status code has been provided. + * + * @param code The status code. + */ public static void assertHealthyStatusCode(int code) { if (code>=200 && code<=299) return; Asserts.fail("Wrong status code: " + code); } - public static int getHttpStatusCode(String url) throws Exception { - URLConnection connection = HttpTool.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 - HttpTool.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. + * + * @param url The URL to connect to. */ public static void assertUrlReachable(String url) { try { - getHttpStatusCode(url); + HttpTool.getHttpStatusCode(url); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Interrupted for "+url+" (in assertion that is reachable)", e); @@ -96,9 +91,15 @@ public class HttpAsserts { } } + /** + * Asserts that the URL could not be reached, detected as an IOException. + * + * @param url The URL to connect to. + */ + public static void assertUrlUnreachable(String url) { try { - int statusCode = getHttpStatusCode(url); + int statusCode = HttpTool.getHttpStatusCode(url); Asserts.fail("Expected url " + url + " unreachable, but got status code " + statusCode); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -108,30 +109,49 @@ public class HttpAsserts { if (cause != null) { // success; clean shutdown transitioning from 400 to error } else { - Throwables.propagate(e); + propagateAsAssertionError(e); } } } + /** + * Asserts that the URL becomes unreachable within a default time period. + * + * @param url The URL + */ public static void assertUrlUnreachableEventually(final String url) { assertUrlUnreachableEventually(Maps.newLinkedHashMap(), url); } - + + + /** + * Asserts that the URL becomes unreachable within a configurable time period. + * + * @param flags The flags controlling the timeout. + * For details see {@link org.apache.brooklyn.test.Asserts#succeedsEventually(java.util.Map, java.util.concurrent.Callable)} + * @param url The URL + */ public static void assertUrlUnreachableEventually(Map flags, final String url) { - Asserts.succeedsEventually(flags, new Runnable() { + assertEventually(flags, new Runnable() { public void run() { assertUrlUnreachable(url); } - }); + }); } + /** + * Assert that the status code returned from the URL is in the given codes. + * + * @param url The URL to get. + * @param acceptableReturnCodes The return codes that are expected. + */ 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); + int actualCode = HttpTool.getHttpStatusCode(url); Asserts.assertTrue(acceptableCodes.contains(actualCode), "code=" + actualCode + "; expected=" + acceptableCodes + "; url=" + url); } catch (InterruptedException e) { @@ -147,11 +167,11 @@ public class HttpAsserts { } public static void assertHttpStatusCodeEventuallyEquals(Map flags, final String url, final int expectedCode) { - Asserts.succeedsEventually(flags, new Runnable() { + assertEventually(flags, new Runnable() { public void run() { assertHttpStatusCodeEquals(url, expectedCode); } - }); + }); } public static void assertContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { @@ -165,7 +185,7 @@ public class HttpAsserts { } } } catch (Exception e) { - throw Throwables.propagate(e); + throw propagateAsAssertionError(e); } } @@ -180,7 +200,7 @@ public class HttpAsserts { } } } catch (Exception e) { - throw Throwables.propagate(e); + throw propagateAsAssertionError(e); } } @@ -195,7 +215,7 @@ public class HttpAsserts { } } } catch (Exception e) { - throw Throwables.propagate(e); + throw propagateAsAssertionError(e); } } @@ -211,22 +231,43 @@ public class HttpAsserts { } } } catch (Exception e) { - throw Throwables.propagate(e); + throw propagateAsAssertionError(e); } } - + + private static AssertionError propagateAsAssertionError(Exception e) { + final AssertionError assertionError = new AssertionError("Assertion failed", e); + return assertionError; + } + 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() { + assertEventually(flags, new Runnable() { public void run() { assertContentContainsText(url, phrase, additionalPhrases); } - }); + }); } - + + private static void assertEventually(Map flags, Runnable r) { + try { + Asserts.succeedsEventually(flags, r); + } catch (Exception e) { + throw propagateAsAssertionError(e); + } + } + + private static void assertEventually(Runnable r) { + try { + Asserts.succeedsEventually(r); + } catch (Exception e) { + throw propagateAsAssertionError(e); + } + } + public static void assertContentMatches(String url, String regex) { String contents = HttpTool.getContent(url); Asserts.assertNotNull(contents); @@ -234,7 +275,7 @@ public class HttpAsserts { } public static void assertContentEventuallyMatches(final String url, final String regex) { - Asserts.succeedsEventually(new Runnable() { + assertEventually(new Runnable() { @Override public void run() { assertContentMatches(url, regex); @@ -243,7 +284,7 @@ public class HttpAsserts { } public static void assertContentEventuallyMatches(Map<String,?> flags, final String url, final String regex) { - Asserts.succeedsEventually(flags, new Runnable() { + assertEventually(flags, new Runnable() { @Override public void run() { assertContentMatches(url, regex); @@ -266,6 +307,9 @@ public class HttpAsserts { * if (future.isDone()) future.get(); // get exception if it's Asserts.failed * } * </pre> + * + * NOTE that the exception thrown by future.get() is a java.util.concurrent.ExecutionException, + * not an AssertionError. * * For stopping it, you can either do future.cancel(true), or you can just do executor.shutdownNow(). * http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/885b6ac4/utils/common/src/test/java/org/apache/brooklyn/util/HttpAssertsTest.java ---------------------------------------------------------------------- diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/HttpAssertsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/HttpAssertsTest.java new file mode 100644 index 0000000..3b0c7c1 --- /dev/null +++ b/utils/common/src/test/java/org/apache/brooklyn/util/HttpAssertsTest.java @@ -0,0 +1,293 @@ +/* + * 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.util; + +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import org.apache.brooklyn.test.http.TestHttpRequestHandler; +import org.apache.brooklyn.test.http.TestHttpServer; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.http.HttpAsserts; +import org.apache.brooklyn.util.http.HttpTool; +import org.apache.brooklyn.util.http.HttpToolResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.localserver.RequestBasicAuth; +import org.apache.http.localserver.ResponseBasicUnauthorized; +import org.apache.http.protocol.ResponseServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.*; + +import java.net.URI; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Created by geoff on 03/11/2015. + */ +public class HttpAssertsTest { + + private static final Logger LOG = LoggerFactory.getLogger(HttpAssertsTest.class); + HttpClient httpClient; + URI baseUri; + private TestHttpServer server; + private String baseUrl; + private ScheduledExecutorService executor; + + + @BeforeMethod(alwaysRun = true) + public void setUp() throws Exception { + server = initializeServer(); + baseUrl = server.getUrl(); + httpClient = HttpTool.httpClientBuilder() + .uri(baseUrl) + .build(); + baseUri = URI.create(baseUrl); + executor = Executors.newScheduledThreadPool(3); + TimeUnit.SECONDS.sleep(2); + } + + private TestHttpServer initializeServer() { + return new TestHttpServer() + .interceptor(new ResponseServer()) + .interceptor(new ResponseBasicUnauthorized()) + .interceptor(new RequestBasicAuth()) + .handler("/simple", new TestHttpRequestHandler().response("OK")) + .handler("/empty", new TestHttpRequestHandler().code(HttpStatus.SC_NO_CONTENT)) + .handler("/missing", new TestHttpRequestHandler().code(HttpStatus.SC_NOT_FOUND).response("Missing")) + .handler("/redirect", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/simple")) + .handler("/cycle", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/cycle")) + .handler("/secure", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "https://0.0.0.0/")) + .start(); + } + + + @AfterMethod(alwaysRun = true) + public void tearDown() throws Exception { + if (executor != null) executor.shutdownNow(); + server.stop(); + TimeUnit.SECONDS.sleep(2); + } + + // schedule a stop of server after n seconds + private void stopAfter(int delay) { + executor.schedule(new Runnable() { + @Override + public void run() { + server.stop(); + } + }, delay, TimeUnit.SECONDS); + } + + // stop server and pause to wait for it to finish + private void stopServer() { + server.stop(); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw Exceptions.propagate(e); + } + } + + // schedule a start of server after n seconds + private void startAfter(int delay) { + executor.schedule(new Runnable() { + @Override + public void run() { + server = initializeServer(); + } + }, delay, TimeUnit.SECONDS); + } + + private HttpToolResponse doGet(String str) { + final URI address = baseUri.resolve(str); + return HttpTool.httpGet(httpClient, address, + ImmutableMap.<String, String>of()); + } + + @Test + public void shouldAssertHealthyStatusCode() { + final HttpToolResponse response = doGet("/simple"); + HttpAsserts.assertHealthyStatusCode(response.getResponseCode()); + } + + @Test + public void shouldAssertUrlReachable() { + HttpAsserts.assertUrlReachable(baseUrl); + } + + @Test + public void shouldAssertUrlUnreachable() { + stopServer(); + HttpAsserts.assertUrlUnreachable(testUri("/simple")); + } + + @Test + public void shouldAssertUrlUnreachableEventually() { + HttpAsserts.assertUrlReachable(baseUrl); + stopAfter(1); + HttpAsserts.assertUrlUnreachableEventually(baseUrl); + } + + @Test + public void shouldAssertUrlUnreachableEventuallyWithFlags() throws Exception { + stopAfter(5); + TimeUnit.SECONDS.sleep(3); + HttpAsserts.assertUrlReachable(baseUrl); + HttpAsserts.assertUrlUnreachableEventually(ImmutableMap.of("timeout", "10s"), baseUrl); + } + + @Test(expectedExceptions = AssertionError.class) + public void shouldAssertUrlUnreachableEventuallyWithTimeout() throws Exception { + HttpAsserts.assertUrlReachable(baseUrl); + HttpAsserts.assertUrlUnreachableEventually(ImmutableMap.of("timeout", "3s"), baseUrl); + } + + + @Test + public void shouldAssertHttpStatusCodeEquals() { + HttpAsserts.assertHttpStatusCodeEquals(baseUrl, 500, 501); + HttpAsserts.assertHttpStatusCodeEquals(testUri("/simple"), 201, 200); + HttpAsserts.assertHttpStatusCodeEquals(testUri("/missing"), 400, 404); + } + + @Test + public void shouldAssertHttpStatusCodeEventuallyEquals() throws Exception { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(2); + HttpAsserts.assertHttpStatusCodeEventuallyEquals(simple, 200); + } + + private String testUri(String str) { + return baseUri.resolve(str).toString(); + } + + @Test + public void shouldAssertContentContainsText() { + HttpAsserts.assertContentContainsText(testUri("/simple"), "OK"); + } + + @Test + public void shouldAssertContentNotContainsText() { + HttpAsserts.assertContentNotContainsText(testUri("/simple"), "Bad"); + } + + @Test + public void shouldAssertErrorContentsContainsText() { + HttpAsserts.assertErrorContentContainsText(testUri("/missing"), "Missing"); + } + + @Test + public void shouldAssertErrorContentNotContainsText() { + HttpAsserts.assertErrorContentNotContainsText(testUri("/missing"), "Bogus"); + } + + @Test + public void shouldAssertContentEventuallyContainsText() { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(2); + HttpAsserts.assertContentEventuallyContainsText(simple, "OK"); + } + + @Test + public void shouldAssertContentEventuallyContainsTextWithFlags() { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(2); + HttpAsserts.assertContentEventuallyContainsText(ImmutableMap.of("timeout", "3s"), simple, "OK"); + } + + @Test(expectedExceptions = AssertionError.class) + public void shouldAssertContentEventuallyContainsTextWithTimeout() { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(4); + HttpAsserts.assertContentEventuallyContainsText(ImmutableMap.of("timeout", "3s"), simple, "OK"); + } + + + @Test + public void shouldAssertContentMatches() { + HttpAsserts.assertContentMatches(testUri("/simple"), "[Oo][Kk]"); + } + + @Test + public void shouldAssertContentEventuallyMatches() throws Exception { + stopServer(); + TimeUnit.SECONDS.sleep(2); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + TimeUnit.SECONDS.sleep(2); + startAfter(2); + HttpAsserts.assertContentEventuallyMatches(testUri("/simple"), "[Oo][Kk]"); + } + + @Test + public void shouldAssertContentEventuallyMatchesWithFlags() { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(2); + HttpAsserts.assertContentEventuallyMatches(ImmutableMap.of("timeout", "3s"), testUri("/simple"), "[Oo][Kk]"); + } + + @Test(expectedExceptions = AssertionError.class) + public void shouldAssertContentEventuallyMatchesWithTimeout() { + stopServer(); + final String simple = testUri("/simple"); + HttpAsserts.assertUrlUnreachable(simple); + startAfter(4); + HttpAsserts.assertContentEventuallyMatches(ImmutableMap.of("timeout", "3s"), testUri("/simple"), "[Oo][Kk]"); + } + + @Test + public void shouldAssertAsyncHttpStatusCodeContinuallyEquals() throws Exception { + ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor); + final ListenableFuture<?> future = + HttpAsserts.assertAsyncHttpStatusCodeContinuallyEquals(listeningExecutor, testUri("/simple"), 200); + TimeUnit.SECONDS.sleep(3); + if (future.isDone()) { + future.get(); // should not throw exception + } + future.cancel(true); + } + + @Test(expectedExceptions = ExecutionException.class) + public void shouldAssertAsyncHttpStatusCodeContinuallyEqualsFails() throws Exception { + ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor); + final ListenableFuture<?> future = + HttpAsserts.assertAsyncHttpStatusCodeContinuallyEquals(listeningExecutor, testUri("/missing"), 200); + TimeUnit.SECONDS.sleep(3); + if (future.isDone()) { + future.get(); // should throw exception + } + future.cancel(true); + } +}
