diff --git a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
index cfc8cf1051..22d902b6be 100644
--- a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
+++ b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
@@ -23,11 +23,11 @@ import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.jclouds.rest.RestContextFactory.createContext;
-import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
+import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
@@ -58,7 +58,9 @@ import org.testng.annotations.Test;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
+import com.google.common.base.Functions;
import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
@@ -70,6 +72,24 @@ import com.google.inject.name.Names;
*
* Allows us to test a client via its side effects.
*
+ *
+ * Example usage:
+ *
+ *
+ *
+ * HttpRequest bucketFooExists = HttpRequest.builder().method("HEAD").endpoint(
+ * URI.create("https://foo.s3.amazonaws.com/?max-keys=0")).headers(
+ * ImmutableMultimap.<String, String> builder().put("Host", "foo.s3.amazonaws.com").put("Date", CONSTANT_DATE)
+ * .put("Authorization", "AWS identity:86P4BBb7xT+gBqq7jxM8Tc28ktY=").build()).build();
+ *
+ * S3Client clientWhenBucketExists = requestSendsResponse(bucketFooExists, HttpResponse.builder().statusCode(200).build());
+ * assert clientWhenBucketExists.bucketExists("foo");
+ *
+ * S3Client clientWhenBucketDoesntExist = requestSendsResponse(bucketFooExists, HttpResponse.builder().statusCode(404)
+ * .build());
+ * assert !clientWhenBucketDoesntExist.bucketExists("foo");
+ *
+ *
* @author Adrian Cole
*/
@Test(groups = "unit")
@@ -88,6 +108,12 @@ public abstract class BaseRestClientExpectTest {
protected String provider = "mock";
+ /**
+ * Override this to supply alternative bindings for use in the test. This is commonly used to
+ * override suppliers of dates so that the test results are predicatable.
+ *
+ * @return optional guice module which can override bindings
+ */
protected Module createModule() {
return new Module() {
@@ -98,11 +124,28 @@ public abstract class BaseRestClientExpectTest {
};
}
-
- protected Payload payloadFromResource(String resource) {
+
+ /**
+ * Convenience method used when creating a response that includes an http payload.
+ *
+ *
+ * ex.
+ *
+ *
+ * HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_get_details.json")).build()
+ *
+ *
+ * @param resource
+ * resource file such as {@code /serverlist.json}
+ * @return payload for use in http responses.
+ */
+ public Payload payloadFromResource(String resource) {
return Payloads.newInputStreamPayload(getClass().getResourceAsStream(resource));
}
+ /**
+ * Mock executor service which uses the supplied function to return http responses.
+ */
@SingleThreaded
@Singleton
public static class ExpectHttpCommandExecutorService extends BaseHttpCommandExecutorService {
@@ -119,18 +162,18 @@ public abstract class BaseRestClientExpectTest {
}
@Override
- protected void cleanup(HttpRequest nativeResponse) {
+ public void cleanup(HttpRequest nativeResponse) {
if (nativeResponse.getPayload() != null)
nativeResponse.getPayload().release();
}
@Override
- protected HttpRequest convert(HttpRequest request) throws IOException, InterruptedException {
+ public HttpRequest convert(HttpRequest request) throws IOException, InterruptedException {
return request;
}
@Override
- protected HttpResponse invoke(HttpRequest nativeRequest) throws IOException, InterruptedException {
+ public HttpResponse invoke(HttpRequest nativeRequest) throws IOException, InterruptedException {
return fn.apply(nativeRequest);
}
}
@@ -145,7 +188,7 @@ public abstract class BaseRestClientExpectTest {
}
@Override
- protected void configure() {
+ public void configure() {
bind(ExecutorService.class).annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).toInstance(
MoreExecutors.sameThreadExecutor());
bind(ExecutorService.class).annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).toInstance(
@@ -156,18 +199,72 @@ public abstract class BaseRestClientExpectTest {
}
}
- protected S requestSendsResponse(final HttpRequest fn, final HttpResponse out) {
- return createClient(new Function() {
-
- @Override
- public HttpResponse apply(HttpRequest command) {
- assertEquals(renderRequest(command), renderRequest(fn));
- return out;
- }
- });
+ /**
+ * creates a client for a mock server which only responds to a single http request
+ *
+ * @param request
+ * the http request the mock server responds to
+ * @param response
+ * the response the mock server returns for the request
+ * @return a client configured with this behavior
+ */
+ public S requestSendsResponse(HttpRequest request, HttpResponse response) {
+ return requestsSendsResponses(ImmutableMap.of(request, response));
}
- private String renderRequest(HttpRequest request) {
+ /**
+ * creates a client for a mock server which only responds to two types of requests
+ *
+ * @param requestA
+ * an http request the mock server responds to
+ * @param responseA
+ * the response for {@code requestA}
+ * @param requestB
+ * another http request the mock server responds to
+ * @param responseB
+ * the response for {@code requestB}
+ * @return a client configured with this behavior
+ */
+ public S requestsSendsResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
+ HttpResponse responseB) {
+ return requestsSendsResponses(ImmutableMap.of(requestA, responseA, requestB, responseB));
+ }
+
+ /**
+ * creates a client for a mock server which only responds to three types of requests
+ *
+ * @param requestA
+ * an http request the mock server responds to
+ * @param responseA
+ * the response for {@code requestA}
+ * @param requestB
+ * another http request the mock server responds to
+ * @param responseB
+ * the response for {@code requestB}
+ * @param requestC
+ * another http request the mock server responds to
+ * @param responseC
+ * the response for {@code requestC}
+ * @return a client configured with this behavior
+ */
+ public S requestsSendsResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
+ HttpResponse responseB, HttpRequest requestC, HttpResponse responseC) {
+ return requestsSendsResponses(ImmutableMap.of(requestA, responseA, requestB, responseB, requestC, responseC));
+ }
+
+ /**
+ * creates a client for a mock server which returns responses for requests based on the supplied
+ * Map parameter.
+ *
+ * @param requestToResponse
+ * valid requests and responses for the mock to respond to
+ * @return a client configured with this behavior
+ */
+ public S requestsSendsResponses(Map requestToResponse) {
+ return createClient(Functions.forMap(requestToResponse));
+ }
+
+ public String renderRequest(HttpRequest request) {
StringBuilder builder = new StringBuilder().append(request.getRequestLine()).append('\n');
for (Entry header : request.getHeaders().entries()) {
builder.append(header.getKey()).append(": ").append(header.getValue()).append('\n');
@@ -189,21 +286,21 @@ public abstract class BaseRestClientExpectTest {
return builder.toString();
}
- protected S createClient(Function fn) {
+ public S createClient(Function fn) {
return createClient(fn, createModule(), setupProperties());
}
- protected S createClient(Function fn, Module module) {
+ public S createClient(Function fn, Module module) {
return createClient(fn, module, setupProperties());
}
- protected S createClient(Function fn, Properties props) {
+ public S createClient(Function fn, Properties props) {
return createClient(fn, createModule(), props);
}
- protected S createClient(Function fn, Module module, Properties props) {
+ public S createClient(Function fn, Module module, Properties props) {
RestContextSpec contextSpec = makeContextSpec();
return createContext(contextSpec,
@@ -221,11 +318,17 @@ public abstract class BaseRestClientExpectTest {
new Properties());
}
-
+ /**
+ * override this when the provider or api is not located in rest.properties and you are not using
+ * the {@link RegisterContext} annotation on your tests.
+ */
protected Properties setupRestProperties() {
return RestContextFactory.getPropertiesFromResource("/rest.properties");
}
+ /**
+ * override this to supply context-specific parameters during tests.
+ */
protected Properties setupProperties() {
return new Properties();
}