Issue 799:simplify http test creation: take 1

This commit is contained in:
Adrian Cole 2012-01-02 18:25:01 -08:00
parent 9c97f2b6a3
commit 08355a92a1
11 changed files with 384 additions and 86 deletions

View File

@ -22,6 +22,7 @@ import java.util.concurrent.Future;
import com.google.common.base.Function;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ImplementedBy;
/**
* Executor which will invoke and transform the response of an {@code EndpointCommand} into generic
@ -29,6 +30,7 @@ import com.google.common.util.concurrent.ListenableFuture;
*
* @author Adrian Cole
*/
@ImplementedBy(TransformingHttpCommandExecutorServiceImpl.class)
public interface TransformingHttpCommandExecutorService {
/**
*

View File

@ -29,6 +29,7 @@ import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.util.concurrent.ListenableFuture;
/**
@ -144,6 +145,20 @@ public class TransformingHttpCommandImpl<T> implements TransformingHttpCommand<T
this.request = request;
}
@Override
public int hashCode() {
return Objects.hashCode(request);
}
@Override
public boolean equals(Object that) {
if (that == null)
return false;
if (!(that instanceof HttpCommand))
return false;
return Objects.equal(this.request, HttpCommand.class.cast(that).getCurrentRequest());
}
@Override
public String toString() {
if (request instanceof GeneratedHttpRequest<?>)

View File

@ -71,20 +71,13 @@ public class RestContextSpec<S, A> {
(Class) RestContextBuilder.class, EMPTY_LIST);
}
/**
* this uses the inefficient {@link Objects} implementation as the object count will be
* relatively small and therefore efficiency is not a concern.
*/
@Override
public int hashCode() {
return Objects.hashCode(provider, endpoint, apiVersion, iso3166Codes, identity, credential, sync, async,
propertiesBuilderClass, contextBuilderClass, modules);
}
/**
* this uses the inefficient {@link Objects} implementation as the object count will be
* relatively small and therefore efficiency is not a concern.
*/
@Override
public boolean equals(Object that) {
if (that == null)
@ -92,10 +85,6 @@ public class RestContextSpec<S, A> {
return Objects.equal(this.toString(), that.toString());
}
/**
* this uses the inefficient {@link Objects} implementation as the object count will be
* relatively small and therefore efficiency is not a concern.
*/
@Override
public String toString() {
return Objects.toStringHelper(this).add("provider", provider).add("endpoint", endpoint).add("apiVersion",

View File

@ -80,12 +80,15 @@ public class Throwables2 {
return (Exception) throwable;
}
}
for (Class<Exception> propagatableExceptionType : new Class[] { IllegalStateException.class,
for (Class<Exception> propagatableExceptionType : new Class[] { IllegalStateException.class, AssertionError.class,
UnsupportedOperationException.class, IllegalArgumentException.class, AuthorizationException.class,
ResourceNotFoundException.class, InsufficientResourcesException.class, HttpResponseException.class }) {
Throwable throwable = getFirstThrowableOfType(exception, propagatableExceptionType);
if (throwable != null) {
throw (Exception) throwable;
if (throwable instanceof AssertionError)
throw (AssertionError) throwable;
else
throw (Exception) throwable;
}
}
Throwables.propagateIfPossible(exception.getCause(), Exception.class);

View File

@ -48,6 +48,7 @@ import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.binders.BindMapToMatrixParams;
import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.binders.BindToStringPayload;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.util.Strings2;
import com.google.common.base.Function;
@ -73,6 +74,7 @@ public interface IntegrationTestAsyncClient {
@HEAD
@Path("/objects/{id}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> exists(@PathParam("id") String path);
@GET

View File

@ -0,0 +1,57 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.http;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.rest.BaseRestClientExpectTest;
import org.jclouds.rest.BaseRestClientExpectTest.RegisterContext;
import org.testng.annotations.Test;
/**
*
* Allows us to test a client via its side effects.
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "IntegrationTestClientExpectTest")
// only needed as IntegrationTestClient is not registered in rest.properties
@RegisterContext(sync = IntegrationTestClient.class, async = IntegrationTestAsyncClient.class)
public class IntegrationTestClientExpectTest extends BaseRestClientExpectTest<IntegrationTestClient> {
public void testWhenResponseIs2xxExistsReturnsTrue() {
IntegrationTestClient client = requestSendsResponse(HttpRequest.builder().method("HEAD").endpoint(
URI.create("http://mock/objects/rabbit")).build(), HttpResponse.builder().statusCode(200).build());
assertEquals(client.exists("rabbit"), true);
}
public void testWhenResponseIs404ExistsReturnsFalse() {
IntegrationTestClient client = requestSendsResponse(HttpRequest.builder().method("HEAD").endpoint(
URI.create("http://mock/objects/rabbit")).build(), HttpResponse.builder().statusCode(404).build());
assertEquals(client.exists("rabbit"), false);
}
}

View File

@ -0,0 +1,232 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except fn 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 fn 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.jclouds.rest;
import static com.google.common.base.Preconditions.checkNotNull;
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.Properties;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.IOExceptionRetryHandler;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.internal.BaseHttpCommandExecutorService;
import org.jclouds.http.internal.HttpWire;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
/**
*
* Allows us to test a client via its side effects.
*
* @author Adrian Cole
*/
@Test(groups = "unit")
@Beta
public abstract class BaseRestClientExpectTest<S> {
/**
* only needed when the client is simple and not registered fn rest.properties
*/
@Target(TYPE)
@Retention(RUNTIME)
public static @interface RegisterContext {
Class<?> sync();
Class<?> async();
}
protected String provider = "mock";
protected Module createModule() {
return new Module() {
@Override
public void configure(Binder binder) {
}
};
}
protected Payload payloadFromResource(String resource) {
return Payloads.newInputStreamPayload(getClass().getResourceAsStream(resource));
}
@SingleThreaded
@Singleton
public static class ExpectHttpCommandExecutorService extends BaseHttpCommandExecutorService<HttpRequest> {
private final Function<HttpRequest, HttpResponse> fn;
@Inject
public ExpectHttpCommandExecutorService(Function<HttpRequest, HttpResponse> fn, HttpUtils utils,
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioExecutor,
IOExceptionRetryHandler ioRetryHandler, DelegatingRetryHandler retryHandler,
DelegatingErrorHandler errorHandler, HttpWire wire) {
super(utils, ioExecutor, retryHandler, ioRetryHandler, errorHandler, wire);
this.fn = checkNotNull(fn, "fn");
}
@Override
protected void cleanup(HttpRequest nativeResponse) {
if (nativeResponse.getPayload() != null)
nativeResponse.getPayload().release();
}
@Override
protected HttpRequest convert(HttpRequest request) throws IOException, InterruptedException {
return request;
}
@Override
protected HttpResponse invoke(HttpRequest nativeRequest) throws IOException, InterruptedException {
return fn.apply(nativeRequest);
}
}
@ConfiguresHttpCommandExecutorService
@ConfiguresExecutorService
public static class ExpectModule extends AbstractModule {
private final Function<HttpRequest, HttpResponse> fn;
public ExpectModule(Function<HttpRequest, HttpResponse> fn) {
this.fn = checkNotNull(fn, "fn");
}
@Override
protected 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(
MoreExecutors.sameThreadExecutor());
bind(new TypeLiteral<Function<HttpRequest, HttpResponse>>() {
}).toInstance(fn);
bind(HttpCommandExecutorService.class).to(ExpectHttpCommandExecutorService.class);
}
}
protected S requestSendsResponse(final HttpRequest fn, final HttpResponse out) {
return createClient(new Function<HttpRequest, HttpResponse>() {
@Override
public HttpResponse apply(HttpRequest command) {
assertEquals(renderRequest(command), renderRequest(fn));
return out;
}
});
}
private String renderRequest(HttpRequest request) {
StringBuilder builder = new StringBuilder().append(request.getRequestLine()).append('\n');
for (Entry<String, String> header : request.getHeaders().entries()) {
builder.append(header.getKey()).append(": ").append(header.getValue()).append('\n');
}
if (request.getPayload() != null) {
for (Entry<String, String> header : HttpUtils.getContentHeadersFromMetadata(
request.getPayload().getContentMetadata()).entries()) {
builder.append(header.getKey()).append(": ").append(header.getValue()).append('\n');
}
try {
builder.append('\n').append(Strings2.toStringAndClose(request.getPayload().getInput()));
} catch (IOException e) {
throw Throwables.propagate(e);
}
} else {
builder.append('\n');
}
return builder.toString();
}
protected S createClient(Function<HttpRequest, HttpResponse> fn) {
return createClient(fn, createModule(), setupProperties());
}
protected S createClient(Function<HttpRequest, HttpResponse> fn, Module module) {
return createClient(fn, module, setupProperties());
}
protected S createClient(Function<HttpRequest, HttpResponse> fn, Properties props) {
return createClient(fn, createModule(), props);
}
protected S createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
RestContextSpec<S, ?> contextSpec = makeContextSpec();
return createContext(contextSpec,
ImmutableSet.<Module> of(new ExpectModule(fn), new NullLoggingModule(), module), props).getApi();
}
@SuppressWarnings("unchecked")
private RestContextSpec<S, ?> makeContextSpec() {
if (getClass().isAnnotationPresent(RegisterContext.class))
return (RestContextSpec<S, ?>) contextSpec(provider, "http://mock", "1", "", "userfoo", null, getClass()
.getAnnotation(RegisterContext.class).sync(),
getClass().getAnnotation(RegisterContext.class).async(), ImmutableSet.<Module> of());
else
return new RestContextFactory(setupRestProperties()).createContextSpec(provider, "identity", "credential",
new Properties());
}
protected Properties setupRestProperties() {
return RestContextFactory.getPropertiesFromResource("/rest.properties");
}
protected Properties setupProperties() {
return new Properties();
}
}

View File

@ -35,8 +35,8 @@ import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.TransformingHttpCommandExecutorService;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.io.MutableContentMetadata;
@ -65,13 +65,13 @@ public abstract class BaseRestClientTest {
@ConfiguresHttpCommandExecutorService
@ConfiguresExecutorService
public static class MockModule extends AbstractModule {
private final TransformingHttpCommandExecutorService mock;
private final HttpCommandExecutorService mock;
public MockModule() {
this(createMock(TransformingHttpCommandExecutorService.class));
this(createMock(HttpCommandExecutorService.class));
}
public MockModule(TransformingHttpCommandExecutorService mock) {
public MockModule(HttpCommandExecutorService mock) {
this.mock = mock;
}
@ -81,7 +81,7 @@ public abstract class BaseRestClientTest {
MoreExecutors.sameThreadExecutor());
bind(ExecutorService.class).annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).toInstance(
MoreExecutors.sameThreadExecutor());
bind(TransformingHttpCommandExecutorService.class).toInstance(mock);
bind(HttpCommandExecutorService.class).toInstance(mock);
}
}

View File

@ -65,6 +65,7 @@ public abstract class RestClientTest<T> extends BaseRestClientTest {
@BeforeClass
protected void setupFactory() throws IOException {
RestContextSpec<?, ?> contextSpec = createContextSpec();
injector = createContextBuilder(contextSpec,
ImmutableSet.of(new MockModule(), new NullLoggingModule(), createModule()), getProperties())
.buildInjector();

View File

@ -20,12 +20,6 @@ package org.jclouds.rest.internal;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.io.Payloads.calculateMD5;
import static org.jclouds.io.Payloads.newInputStreamPayload;
import static org.jclouds.io.Payloads.newStringPayload;
@ -53,6 +47,7 @@ import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
@ -75,26 +70,24 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.xml.bind.annotation.XmlRootElement;
import org.easymock.IArgumentMatcher;
import org.eclipse.jetty.http.HttpHeaders;
import org.jclouds.concurrent.Timeout;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.IOExceptionRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.TransformingHttpCommandExecutorService;
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
import org.jclouds.http.functions.ParseXMLWithJAXB;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.http.functions.ReturnInputStream;
import org.jclouds.http.functions.ReturnStringIf2xx;
import org.jclouds.http.functions.ReturnTrueIf2xx;
@ -180,8 +173,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@RequiresHttp
@ConfiguresRestClient
protected static class CallerCalleeModule extends RestClientModule<Caller, AsyncCaller> {
CallerCalleeModule() {
protected static class CallerModule extends RestClientModule<Caller, AsyncCaller> {
CallerModule() {
super(Caller.class, AsyncCaller.class, ImmutableMap.<Class<?>, Class<?>> of(Callee.class, AsyncCallee.class));
}
@ -227,13 +220,17 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public AsyncCallee getCallee(@EndpointParam URI endpoint);
}
@SuppressWarnings("unchecked")
public void testDelegateAsyncIncludesVersion() throws SecurityException, NoSuchMethodException,
InterruptedException, ExecutionException {
Injector child = injectorForClient();
TransformingHttpCommandExecutorService mock = child.getInstance(TransformingHttpCommandExecutorService.class);
public void testAsyncDelegateIsLazyLoadedAndRequestIncludesVersionAndPath() throws InterruptedException, ExecutionException {
Injector child = injectorForCaller(new HttpCommandExecutorService() {
ReleasePayloadAndReturn function = child.getInstance(ReleasePayloadAndReturn.class);
@Override
public Future<HttpResponse> submit(HttpCommand command) {
assertEquals(command.getCurrentRequest().getRequestLine(),
"GET http://localhost:9999/client/1/foo HTTP/1.1");
return Futures.immediateFuture(HttpResponse.builder().build());
}
});
try {
child.getInstance(AsyncCallee.class);
@ -242,42 +239,21 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
AsyncCaller caller = child.getInstance(AsyncCaller.class);
expect(mock.submit(requestLineEquals("GET http://localhost:9999/client/1/foo HTTP/1.1"), eq(function)))
.andReturn(createNiceMock(ListenableFuture.class)).atLeastOnce();
replay(mock);
caller.getCallee().onePath("foo");
verify(mock);
child.getInstance(AsyncCaller.class).getCallee().onePath("foo").get();
}
public static HttpCommand requestLineEquals(final String requestLine) {
reportMatcher(new IArgumentMatcher() {
public void testDelegateIsLazyLoadedAndRequestIncludesVersionAndPath() throws InterruptedException, ExecutionException {
Injector child = injectorForCaller(new HttpCommandExecutorService() {
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("requestLineEquals(");
buffer.append(requestLine);
buffer.append(")");
}
@Override
public boolean matches(Object arg) {
return ((HttpCommand) arg).getCurrentRequest().getRequestLine().equals(requestLine);
public Future<HttpResponse> submit(HttpCommand command) {
assertEquals(command.getCurrentRequest().getRequestLine(),
"GET http://localhost:1111/client/1/foo HTTP/1.1");
return Futures.immediateFuture(HttpResponse.builder().build());
}
});
return null;
}
public void testDelegateWithOverridingEndpoint() throws SecurityException, NoSuchMethodException,
InterruptedException, ExecutionException {
Injector child = injectorForClient();
TransformingHttpCommandExecutorService mock = child.getInstance(TransformingHttpCommandExecutorService.class);
ReleasePayloadAndReturn function = child.getInstance(ReleasePayloadAndReturn.class);
try {
child.getInstance(Callee.class);
@ -286,23 +262,45 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
Caller caller = child.getInstance(Caller.class);
expect(mock.submit(requestLineEquals("GET http://localhost:1111/client/1/foo HTTP/1.1"), eq(function)))
.andReturn(Futures.<Void> immediateFuture(null)).atLeastOnce();
replay(mock);
caller.getCallee().onePath("foo");
verify(mock);
child.getInstance(Caller.class).getCallee().onePath("foo");
}
public void testDelegateWithOverridingEndpointOnMethod() throws SecurityException, NoSuchMethodException,
InterruptedException, ExecutionException {
Injector child = injectorForClient();
TransformingHttpCommandExecutorService mock = child.getInstance(TransformingHttpCommandExecutorService.class);
ReleasePayloadAndReturn function = child.getInstance(ReleasePayloadAndReturn.class);
public void testAsyncDelegateIsLazyLoadedAndRequestIncludesEndpointVersionAndPath() throws InterruptedException, ExecutionException {
Injector child = injectorForCaller(new HttpCommandExecutorService() {
@Override
public Future<HttpResponse> submit(HttpCommand command) {
assertEquals(command.getCurrentRequest().getRequestLine(),
"GET http://howdyboys/client/1/foo HTTP/1.1");
return Futures.immediateFuture(HttpResponse.builder().build());
}
});
try {
child.getInstance(AsyncCallee.class);
assert false : "Callee shouldn't be bound yet";
} catch (ConfigurationException e) {
}
child.getInstance(AsyncCaller.class).getCallee(URI.create("http://howdyboys")).onePath("foo").get();
}
public void testDelegateIsLazyLoadedAndRequestIncludesEndpointVersionAndPath() throws InterruptedException, ExecutionException {
Injector child = injectorForCaller(new HttpCommandExecutorService() {
@Override
public Future<HttpResponse> submit(HttpCommand command) {
assertEquals(command.getCurrentRequest().getRequestLine(),
"GET http://howdyboys/client/1/foo HTTP/1.1");
return Futures.immediateFuture(HttpResponse.builder().build());
}
});
try {
child.getInstance(Callee.class);
@ -311,22 +309,15 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
Caller caller = child.getInstance(Caller.class);
expect(mock.submit(requestLineEquals("GET http://howdyboys/client/1/foo HTTP/1.1"), eq(function))).andReturn(
Futures.<Void> immediateFuture(null)).atLeastOnce();
replay(mock);
caller.getCallee(URI.create("http://howdyboys")).onePath("foo");
verify(mock);
child.getInstance(Caller.class).getCallee(URI.create("http://howdyboys")).onePath("foo");
}
private Injector injectorForClient() {
private Injector injectorForCaller(HttpCommandExecutorService service) {
RestContextSpec<Caller, AsyncCaller> contextSpec = contextSpec("test", "http://localhost:9999", "1", "",
"userfoo", null, Caller.class, AsyncCaller.class,
ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule(), new CallerCalleeModule()));
ImmutableSet.<Module> of(new MockModule(service), new NullLoggingModule(), new CallerModule()));
return createContextBuilder(contextSpec).buildInjector();

View File

@ -116,6 +116,12 @@ public class Throwables2Test {
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(new Class[] {}, new RuntimeException(e));
}
@Test(expectedExceptions = AssertionError.class)
public void testPropagateStandardExceptionAssertionError() throws Exception {
AssertionError e = new AssertionError();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(new Class[] {}, new RuntimeException(e));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testPropagateStandardExceptionAuthorizationException() throws Exception {
Exception e = new AuthorizationException();