From 83e77d2309a5f660e0c9eccfe0fef6e55c92c7b9 Mon Sep 17 00:00:00 2001 From: Zack Shoylev Date: Thu, 21 Nov 2013 21:27:34 -0600 Subject: [PATCH] Adds some easy-of-use for openstack mock tests --- .../v2_0/internal/BaseOpenStackMockTest.java | 130 ++++++++++++++++-- 1 file changed, 118 insertions(+), 12 deletions(-) diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/internal/BaseOpenStackMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/internal/BaseOpenStackMockTest.java index 3646bda75f..ecc8b2b4d3 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/internal/BaseOpenStackMockTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/internal/BaseOpenStackMockTest.java @@ -16,15 +16,10 @@ */ package org.jclouds.openstack.v2_0.internal; -import com.google.common.collect.ImmutableSet; -import com.google.common.reflect.TypeToken; -import com.google.inject.Module; -import com.squareup.okhttp.mockwebserver.MockResponse; -import com.squareup.okhttp.mockwebserver.MockWebServer; -import com.squareup.okhttp.mockwebserver.QueueDispatcher; -import com.squareup.okhttp.mockwebserver.RecordedRequest; -import org.jclouds.ContextBuilder; -import org.jclouds.concurrent.config.ExecutorServiceModule; +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import java.io.Closeable; import java.io.IOException; @@ -34,19 +29,38 @@ import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; -import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; +import org.jclouds.ContextBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.util.Strings2; + +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.inject.Module; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.QueueDispatcher; +import com.squareup.okhttp.mockwebserver.RecordedRequest; /** * @author Jeremy Daggett + * @author Zack Shoylev */ public class BaseOpenStackMockTest { - public static final String accessRackspace = "{\"access\":{\"token\":{\"id\":\"b84f4a37-5126-4603-9521-ccd0665fbde1\",\"expires\":\"2013-04-13T16:49:57.000-05:00\",\"tenant\":{\"id\":\"123123\",\"name\":\"123123\"}},\"serviceCatalog\":[{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudMonitoring\",\"type\":\"rax:monitor\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFilesCDN\",\"type\":\"rax:object-cdn\"},{\"endpoints\":[{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudLoadBalancers\",\"type\":\"rax:load-balancer\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDatabases\",\"type\":\"rax:database\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFiles\",\"type\":\"object-store\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\",\"versionInfo\":\"URL/v1.0\",\"versionList\":\"URL/\",\"versionId\":\"1.0\"}],\"name\":\"cloudServers\",\"type\":\"compute\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"}],\"name\":\"cloudServersOpenStack\",\"type\":\"compute\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDNS\",\"type\":\"rax:dns\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudBackup\",\"type\":\"rax:backup\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"}],\"name\":\"cloudBlockStorage\",\"type\":\"volume\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"}],\"name\":\"marconi\",\"type\":\"queuing\"}],\"user\":{\"id\":\"1234\",\"roles\":[{\"id\":\"3\",\"description\":\"User Admin Role.\",\"name\":\"identity:user-admin\"}],\"name\":\"jclouds-joe\",\"RAX-AUTH:defaultRegion\":\"DFW\"}}}"; + /** + * Needed for backwards-compatibility. This variable might not be up-to-date + * with current services available. + * */ + @Deprecated + public static final String accessRackspace = "{\"access\":{\"token\":{\"id\":\"b84f4a37-5126-4603-9521-ccd0665fbde1\",\"expires\":\"2013-04-13T16:49:57.000-05:00\",\"tenant\":{\"id\":\"123123\",\"name\":\"123123\"}},\"serviceCatalog\":[{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudMonitoring\",\"type\":\"rax:monitor\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFilesCDN\",\"type\":\"rax:object-cdn\"},{\"endpoints\":[{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudLoadBalancers\",\"type\":\"rax:load-balancer\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDatabases\",\"type\":\"rax:database\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFiles\",\"type\":\"object-store\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\",\"versionInfo\":\"URL/v1.0\",\"versionList\":\"URL/\",\"versionId\":\"1.0\"}],\"name\":\"cloudServers\",\"type\":\"compute\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"}],\"name\":\"cloudServersOpenStack\",\"type\":\"compute\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDNS\",\"type\":\"rax:dns\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudBackup\",\"type\":\"rax:backup\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"}],\"name\":\"cloudBlockStorage\",\"type\":\"volume\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"}],\"name\":\"marconi\",\"type\":\"queuing\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\",\"internalURL\":\"URL/v1/123123\"}],\"name\":\"autoscale\",\"type\":\"rax:autoscale\"}],\"user\":{\"id\":\"1234\",\"roles\":[{\"id\":\"3\",\"description\":\"User Admin Role.\",\"name\":\"identity:user-admin\"}],\"name\":\"jclouds-joe\",\"RAX-AUTH:defaultRegion\":\"DFW\"}}}"; private final Set modules = ImmutableSet. of( new ExecutorServiceModule(sameThreadExecutor(), sameThreadExecutor())); + @SuppressWarnings("serial") public A api(String uri, String provider, Properties overrides) { overrides.setProperty(PROPERTY_MAX_RETRIES, "1"); @@ -82,6 +96,11 @@ public class BaseOpenStackMockTest { public MockResponse dispatch(RecordedRequest request) throws InterruptedException { MockResponse response = responseQueue.take(); if (response.getBody() != null) { + /* + * "URL" must be used in the service catalog sample (such as + * access.json or accessRackspace) for the declared service + * endpoints. + */ String newBody = new String(response.getBody()).replace(":\"URL", ":\"" + url.toString()); response = response.setBody(newBody); } @@ -96,4 +115,91 @@ public class BaseOpenStackMockTest { return dispatcher; } + + /** + * Ensure json headers are included + * */ + public MockResponse addCommonHeaders(MockResponse mockResponse) { + mockResponse.addHeader("Accept:", "application/json").addHeader("Content-type", "application-json"); + return mockResponse; + } + + /** + * Get a string from a resource + * + * @param resourceName + * The name of the resource. + * @return The content of the resource + */ + public String stringFromResource(String resourceName) { + try { + return Strings2.toStringAndClose(getClass().getResourceAsStream(resourceName)); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + /** + * Ensures server received authentication request. + */ + public void assertAuthentication(MockWebServer server) { + assertTrue(server.getRequestCount() >= 1); + try { + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + } catch (InterruptedException e) { + Throwables.propagate(e); + } + } + + /** + * Ensures the request has a json header. + * + * @param request + * @see RecordedRequest + */ + private void assertContentTypeIsJSON(RecordedRequest request) { + assertTrue(request.getHeaders().contains("Content-Type: application/json")); + } + + /** + * Ensures the request has a json header for the proper REST methods. + * + * @param request + * @param method + * The request method (such as GET). + * @param path + * The path requested for this REST call. + * @see RecordedRequest + */ + public void assertRequest(RecordedRequest request, String method, String path) { + assertEquals(request.getMethod(), method); + assertEquals(request.getPath(), path); + } + + /** + * Ensures the request is json and has the same contents as the resource + * file provided. + * + * @param request + * @param method + * The request method (such as GET). + * @param resourceLocation + * The location of the resource file. Contents will be compared to + * the request body as JSON. + * @see RecordedRequest + */ + public void assertRequest(RecordedRequest request, String method, String path, String resourceLocation) { + assertRequest(request, method, path); + assertContentTypeIsJSON(request); + JsonParser parser = new JsonParser(); + JsonElement requestJson = null; // to be compared + JsonElement resourceJson; // to be compared + try { + requestJson = parser.parse(new String(request.getBody(), "UTF-8")); + } catch (Exception e) { + Throwables.propagate(e); + } + resourceJson = parser.parse(stringFromResource(resourceLocation)); + assertEquals(requestJson, resourceJson); // Compare as JSON + } }