Repository: brooklyn-server Updated Branches: refs/heads/master 84eba7e31 -> 17e3d1fdf
BROOKLYN-421: add tests for catalog library loading Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/0fc7820d Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/0fc7820d Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/0fc7820d Branch: refs/heads/master Commit: 0fc7820dba7ce149fb172527b0bca66d058fe7af Parents: b294f41 Author: Aled Sage <aled.s...@gmail.com> Authored: Thu Dec 22 12:26:33 2016 +0000 Committer: Aled Sage <aled.s...@gmail.com> Committed: Thu Jan 5 16:52:34 2017 +0000 ---------------------------------------------------------------------- .../catalog/CatalogOsgiLibraryTest.java | 285 +++++++++++++++++++ .../TestHttpRecordingRequestInterceptor.java | 55 ++++ .../test/http/TestHttpRequestHandler.java | 6 + .../brooklyn/test/http/TestHttpServer.java | 4 +- 4 files changed, 348 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0fc7820d/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java new file mode 100644 index 0000000..94adcdd --- /dev/null +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java @@ -0,0 +1,285 @@ +/* + * 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.camp.brooklyn.catalog; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Map; + +import org.apache.brooklyn.api.catalog.CatalogItem; +import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest; +import org.apache.brooklyn.core.config.external.AbstractExternalConfigSupplier; +import org.apache.brooklyn.core.mgmt.internal.ExternalConfigSupplierRegistry; +import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; +import org.apache.brooklyn.entity.stock.BasicApplication; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.test.http.TestHttpRecordingRequestInterceptor; +import org.apache.brooklyn.test.http.TestHttpRequestHandler; +import org.apache.brooklyn.test.http.TestHttpServer; +import org.apache.brooklyn.test.support.TestResourceUnavailableException; +import org.apache.brooklyn.util.net.Urls; +import org.apache.brooklyn.util.osgi.OsgiTestResources; +import org.apache.brooklyn.util.stream.Streams; +import org.apache.http.Header; +import org.apache.http.HttpRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.io.BaseEncoding; +import com.google.common.net.UrlEscapers; + +public class CatalogOsgiLibraryTest extends AbstractYamlTest { + + @SuppressWarnings("unused") + private static final Logger log = LoggerFactory.getLogger(CatalogOsgiLibraryTest.class); + + private TestHttpServer webServer; + private TestHttpRecordingRequestInterceptor requestInterceptor; + + private String jarName = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FINAL_PART + ".jar"; + private String malformedJarName = "thisIsNotAJar.jar"; + private String classpathUrl = "classpath:" + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH; + private URL jarUrl; + private URL malformedJarUrl; + + @BeforeMethod(alwaysRun = true) + @Override + public void setUp() throws Exception { + super.setUp(); + + // Load the bytes of the jar + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/brooklyn/osgi/" + jarName); + InputStream resource = getClass().getResourceAsStream("/brooklyn/osgi/" + jarName); + final byte[] jarBytes = Streams.readFullyAndClose(resource); + + // Start a mock web-server that will return the jar + requestInterceptor = new TestHttpRecordingRequestInterceptor(); + webServer = new TestHttpServer() + .handler("/" + jarName, new TestHttpRequestHandler().code(200).response(jarBytes)) + .handler("/" + malformedJarName, new TestHttpRequestHandler().code(200).response("simulating-malformed-jar")) + .interceptor(requestInterceptor) + .start(); + jarUrl = new URL(Urls.mergePaths(webServer.getUrl(), jarName)); + malformedJarUrl = new URL(Urls.mergePaths(webServer.getUrl(), malformedJarName)); + } + + @AfterMethod(alwaysRun = true) + @Override + public void tearDown() throws Exception { + try { + if (webServer != null) webServer.stop(); + } finally { + super.tearDown(); + } + } + + @Override + protected boolean disableOsgi() { + return false; + } + + @Test + public void testLibraryStringWithClasspathUrl() throws Exception { + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - " + classpathUrl, + " item:", + " services:", + " - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication"); + + CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0"); + assertCatalogLibraryUrl(item, classpathUrl); + } + + @Test + public void testLibraryMapWithClasspathUrl() throws Exception { + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - url: " + classpathUrl, + " item:", + " services:", + " - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication"); + + CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0"); + assertCatalogLibraryUrl(item, classpathUrl); + } + + @Test + public void testLibraryHttpUrl() throws Exception { + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - " + jarUrl, + " item:", + " services:", + " - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication"); + + CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0"); + assertCatalogLibraryUrl(item, jarUrl.toString()); + } + + @Test + public void testLibraryUrlDoesNotExist() throws Exception { + String wrongUrl = "classpath:/path/does/not/exist/aefjaifjie3kdd.jar"; + try { + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - " + wrongUrl, + " item:", + " services:", + " - type: " + BasicApplication.class.getName()); + Asserts.shouldHaveFailedPreviously(); + } catch (Exception e) { + if (!e.toString().contains("Bundle from " + wrongUrl + " failed to install")) { + throw e; + } + } + } + + @Test + public void testLibraryMalformed() throws Exception { + try { + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - " + malformedJarUrl, + " item:", + " services:", + " - type: " + BasicApplication.class.getName()); + Asserts.shouldHaveFailedPreviously(); + } catch (Exception e) { + if (!e.toString().contains("not a jar file")) { + throw e; + } + } + } + + @Test + public void testLibraryUrlUsingExternalizedConfig() throws Exception { + // Add an externalized config provider, which will return us the url + Map<String, String> externalConfig = ImmutableMap.of("url", classpathUrl); + ExternalConfigSupplierRegistry externalConfigProviderRegistry = ((ManagementContextInternal)mgmt()).getExternalConfigProviderRegistry(); + externalConfigProviderRegistry.addProvider("myprovider", new MyExternalConfigSupplier(mgmt(), "myprovider", externalConfig)); + + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - $brooklyn:external(\"myprovider\", \"url\")", + " item:", + " services:", + " - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication"); + + CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0"); + assertCatalogLibraryUrl(item, classpathUrl); + } + + // TODO See https://issues.apache.org/jira/browse/BROOKLYN-421 + // Need to somehow escape the username and password (or include them explicitly as a + // "Authorization" header instead of embedding them in the URI). + @Test(groups="Broken") + public void testLibraryUrlUsingExternalizedConfigForCredentials() throws Exception { + String username = "myu...@mydomain.com"; + String password = "Myp4ss@?/:!"; + + // Add an externalized config provider, which will return us a username + password + Map<String, String> externalConfig = ImmutableMap.of("username", username, "password", password); + ExternalConfigSupplierRegistry externalConfigProviderRegistry = ((ManagementContextInternal)mgmt()).getExternalConfigProviderRegistry(); + externalConfigProviderRegistry.addProvider("myprovider", new MyExternalConfigSupplier(mgmt(), "myprovider", externalConfig)); + + addCatalogItems( + "brooklyn.catalog:", + " id: simple-osgi-library", + " version: \"1.0\"", + " itemType: template", + " libraries:", + " - $brooklyn:formatString:", + " - http://%s:%s@" + jarUrl.getHost() + ":" + jarUrl.getPort() + jarUrl.getPath(), + " - $brooklyn:external(\"myprovider\", \"username\")", + " - $brooklyn:external(\"myprovider\", \"password\")", + " item:", + " services:", + " - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication"); + + // Expect basic-auth used when retrieving jar + HttpRequest req = requestInterceptor.getLastRequest(); + Header[] authHeaders = req.getHeaders("Authorization"); + assertEquals(authHeaders.length, 1, "authHeaders=" + Arrays.toString(authHeaders)); + String authHeader = authHeaders[0].getValue(); + String expectedHeader = "Basic " + BaseEncoding.base64().encode((username + ":" + password).getBytes(StandardCharsets.UTF_8)); + assertEquals(authHeader, expectedHeader, "headers=" + Arrays.toString(req.getAllHeaders())); + + // Expect url to have been correctly escaped + String escapedUsername = UrlEscapers.urlFragmentEscaper().escape(username); + String escapedPassword = UrlEscapers.urlFragmentEscaper().escape(password); + String expectedUrl = "http://" + escapedUsername + ":" + escapedPassword+ "@" + jarUrl.getHost() + ":" + jarUrl.getPort() + jarUrl.getPath(); + + CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0"); + assertCatalogLibraryUrl(item, expectedUrl); + } + + public static class MyExternalConfigSupplier extends AbstractExternalConfigSupplier { + private final Map<String, String> conf; + + public MyExternalConfigSupplier(ManagementContext mgmt, String name, Map<String, String> conf) { + super(mgmt, name); + this.conf = conf; + } + + @Override public String get(String key) { + return conf.get(key); + } + } + + protected void assertCatalogLibraryUrl(CatalogItem<?,?> item, String expectedUrl) { + CatalogBundle library = Iterables.getOnlyElement(item.getLibraries()); + assertEquals(library.getUrl(), expectedUrl); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0fc7820d/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRecordingRequestInterceptor.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRecordingRequestInterceptor.java b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRecordingRequestInterceptor.java new file mode 100644 index 0000000..aeba4b7 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/test/http/TestHttpRecordingRequestInterceptor.java @@ -0,0 +1,55 @@ +/* + * 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.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpRequestInterceptor; +import org.apache.http.protocol.HttpContext; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +public class TestHttpRecordingRequestInterceptor implements HttpRequestInterceptor { + + private final List<HttpRequest> requests = Collections.synchronizedList(Lists.<HttpRequest>newArrayList()); + + public List<HttpRequest> getRequests() { + synchronized (requests) { + return ImmutableList.copyOf(requests); + } + } + + public HttpRequest getLastRequest() { + synchronized (requests) { + if (requests.isEmpty()) throw new NoSuchElementException("No http-requests received"); + return requests.get(requests.size()-1); + } + } + + @Override + public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { + requests.add(request); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0fc7820d/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 index 18f5c44..af47c8a 100644 --- 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 @@ -30,6 +30,7 @@ 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.ByteArrayEntity; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; import org.apache.http.protocol.HttpContext; @@ -49,6 +50,11 @@ public class TestHttpRequestHandler implements HttpRequestHandler { return this; } + public TestHttpRequestHandler response(byte[] response) { + this.entity = new ByteArrayEntity(response); + return this; + } + public TestHttpRequestHandler code(int responseCode) { this.responseCode = responseCode; return this; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0fc7820d/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 index b114b0a..3a34deb 100644 --- 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 @@ -59,7 +59,7 @@ public class TestHttpServer { return this; } - public TestHttpServer requestInterceptors(List<HttpResponseInterceptor> interceptors) { + public TestHttpServer responseInterceptors(List<HttpResponseInterceptor> interceptors) { checkNotStarted(); this.responseInterceptors = interceptors; return this; @@ -71,7 +71,7 @@ public class TestHttpServer { return this; } - public TestHttpServer responseInterceptors(List<HttpRequestInterceptor> interceptors) { + public TestHttpServer requestInterceptors(List<HttpRequestInterceptor> interceptors) { checkNotStarted(); this.requestInterceptors = interceptors; return this;