diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /jaxrs_client_utils/src/test |
Publish
Diffstat (limited to 'jaxrs_client_utils/src/test')
3 files changed, 325 insertions, 0 deletions
diff --git a/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/HttpPatchTest.java b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/HttpPatchTest.java new file mode 100644 index 00000000000..ae8f55af551 --- /dev/null +++ b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/HttpPatchTest.java @@ -0,0 +1,109 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.jaxrs.client; + +import com.yahoo.vespa.applicationmodel.HostName; +import com.yahoo.vespa.jaxrs.annotation.PATCH; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.HttpUrlConnectorProvider; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author bakksjo + */ +public class HttpPatchTest extends JerseyTest { + private final TestResource testResourceSingleton = new TestResource(); + + @Override + protected Application configure() { + return new Application() { + @Override + public Set<Class<?>> getClasses() { + return Collections.emptySet(); + } + + @Override + public Set<Object> getSingletons() { + return new HashSet<>(Arrays.asList(testResourceSingleton)); + } + }; + } + + @Override + protected void configureClient(final ClientConfig config) { + config.getConfiguration().property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); + } + + private static final String REQUEST_BODY = "Hello there"; + + @Test + public void clientPatchRequest() throws Exception { + final Response response = target(TestResourceApi.PATH) + .request() + .method("PATCH", Entity.text(REQUEST_BODY)); + assertThat(testResourceSingleton.invocation.get(60, TimeUnit.SECONDS), is(REQUEST_BODY)); + assertThat(response.readEntity(String.class), is(REQUEST_BODY)); + } + + @Test + public void clientPatchRequestUsingProxyClass() throws Exception { + final URI targetUri = target(TestResourceApi.PATH).getUri(); + final HostName apiHost = new HostName(targetUri.getHost()); + final int apiPort = targetUri.getPort(); + final String apiPath = targetUri.getPath(); + + final JaxRsClientFactory jaxRsClientFactory = new JerseyJaxRsClientFactory(); + final JaxRsStrategyFactory factory = new JaxRsStrategyFactory( + Collections.singleton(apiHost), apiPort, jaxRsClientFactory); + final JaxRsStrategy<TestResourceApi> client = factory.apiNoRetries(TestResourceApi.class, apiPath); + + final String responseBody; + responseBody = client.apply(api -> + api.doPatch(REQUEST_BODY)); + + assertThat(testResourceSingleton.invocation.get(60, TimeUnit.SECONDS), is(REQUEST_BODY)); + assertThat(responseBody, is(REQUEST_BODY)); + } + + public interface TestResourceApi { + String PATH = "test"; + + @GET + String getHello(); + + @PATCH + String doPatch(final String body); + } + + @Path(TestResourceApi.PATH) + public static class TestResource implements TestResourceApi { + public final CompletableFuture<String> invocation = new CompletableFuture<>(); + + @GET + public String getHello() { + return "Hello World!"; + } + + @PATCH + public String doPatch(final String body) { + invocation.complete(body); + return body; + } + } +} diff --git a/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/NoRetryJaxRsStrategyTest.java b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/NoRetryJaxRsStrategyTest.java new file mode 100644 index 00000000000..a03ada20fc5 --- /dev/null +++ b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/NoRetryJaxRsStrategyTest.java @@ -0,0 +1,74 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.jaxrs.client; + +import com.yahoo.vespa.applicationmodel.HostName; +import com.yahoo.vespa.defaults.Defaults; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.ProcessingException; +import java.io.IOException; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class NoRetryJaxRsStrategyTest { + private static final String API_PATH = "/foo/bar"; + + @Path(API_PATH) + private interface TestJaxRsApi { + @GET + @Path("/foo/bar") + String doSomething(); + } + + private static final HostName SERVER_HOST = new HostName("host-1"); + private static final int REST_PORT = Defaults.getDefaults().vespaWebServicePort(); + + private final JaxRsClientFactory jaxRsClientFactory = mock(JaxRsClientFactory.class); + private final TestJaxRsApi mockApi = mock(TestJaxRsApi.class); + private final JaxRsStrategy<TestJaxRsApi> jaxRsStrategy = new NoRetryJaxRsStrategy<>( + SERVER_HOST, REST_PORT, jaxRsClientFactory, TestJaxRsApi.class, API_PATH); + + @Before + public void setup() { + when(jaxRsClientFactory.createClient(eq(TestJaxRsApi.class), any(HostName.class), anyInt(), anyString())) + .thenReturn(mockApi); + } + + @Test + public void noRetryIfNoFailure() throws Exception { + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + + verify(mockApi, times(1)).doSomething(); + + verify(jaxRsClientFactory, times(1)) + .createClient(eq(TestJaxRsApi.class), eq(SERVER_HOST), eq(REST_PORT), eq(API_PATH)); + } + + @Test + public void testNoRetryAfterFailure() throws Exception { + // Make the first call fail. + when(mockApi.doSomething()) + .thenThrow(new ProcessingException("Fake timeout induced by test")) + .thenReturn("a response"); + + try { + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + fail("The above statement should throw"); + } catch (IOException e) { + // As expected. + } + + // Check that there was no second attempt. + verify(mockApi, times(1)).doSomething(); + } +} diff --git a/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/RetryingJaxRsStrategyTest.java b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/RetryingJaxRsStrategyTest.java new file mode 100644 index 00000000000..1002ecc996c --- /dev/null +++ b/jaxrs_client_utils/src/test/java/com/yahoo/vespa/jaxrs/client/RetryingJaxRsStrategyTest.java @@ -0,0 +1,142 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.jaxrs.client; + +import com.yahoo.vespa.applicationmodel.HostName; +import com.yahoo.vespa.defaults.Defaults; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.ProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class RetryingJaxRsStrategyTest { + private static final String API_PATH = "/"; + + @Path(API_PATH) + private interface TestJaxRsApi { + @GET + @Path("/foo/bar") + String doSomething(); + } + + private static final Set<HostName> SERVER_HOSTS = new HashSet<>(Arrays.asList( + new HostName("host-1"), + new HostName("host-2"), + new HostName("host-3"))); + private static final int REST_PORT = Defaults.getDefaults().vespaWebServicePort(); + + private final JaxRsClientFactory jaxRsClientFactory = mock(JaxRsClientFactory.class); + private final TestJaxRsApi mockApi = mock(TestJaxRsApi.class); + private final JaxRsStrategy<TestJaxRsApi> jaxRsStrategy = new RetryingJaxRsStrategy<>( + SERVER_HOSTS, REST_PORT, jaxRsClientFactory, TestJaxRsApi.class, API_PATH); + + @Before + public void setup() { + when(jaxRsClientFactory.createClient(eq(TestJaxRsApi.class), any(HostName.class), anyInt(), anyString())) + .thenReturn(mockApi); + } + + @Test + public void noRetryIfNoFailure() throws Exception { + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + + verify(mockApi, times(1)).doSomething(); + + // Check that one of the supplied hosts is contacted. + final ArgumentCaptor<HostName> hostNameCaptor = ArgumentCaptor.forClass(HostName.class); + verify(jaxRsClientFactory, times(1)) + .createClient(eq(TestJaxRsApi.class), hostNameCaptor.capture(), eq(REST_PORT), eq(API_PATH)); + assertThat(SERVER_HOSTS.contains(hostNameCaptor.getValue()), is(true)); + } + + @Test + public void testRetryAfterSingleFailure() throws Exception { + // Make the first attempt fail. + when(mockApi.doSomething()) + .thenThrow(new ProcessingException("Fake timeout induced by test")) + .thenReturn("a response"); + + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + + // Check that there was a second attempt. + verify(mockApi, times(2)).doSomething(); + } + + @Test + public void testRetryUsesAllAvailableServers() throws Exception { + when(mockApi.doSomething()) + .thenThrow(new ProcessingException("Fake timeout 1 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 2 induced by test")) + .thenReturn("a response"); + + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + + verify(mockApi, times(3)).doSomething(); + verifyAllServersContacted(jaxRsClientFactory); + } + + @Test + public void testRetryLoopsOverAvailableServers() throws Exception { + when(mockApi.doSomething()) + .thenThrow(new ProcessingException("Fake timeout 1 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 2 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 3 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 4 induced by test")) + .thenReturn("a response"); + + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + + verify(mockApi, times(5)).doSomething(); + verifyAllServersContacted(jaxRsClientFactory); + } + + @Test + public void testRetryGivesUpAfterTwoLoopsOverAvailableServers() throws Exception { + when(mockApi.doSomething()) + .thenThrow(new ProcessingException("Fake timeout 1 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 2 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 3 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 4 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 5 induced by test")) + .thenThrow(new ProcessingException("Fake timeout 6 induced by test")); + + try { + jaxRsStrategy.apply(TestJaxRsApi::doSomething); + fail("Exception should be thrown from above statement"); + } catch (IOException e) { + // As expected. + } + + verify(mockApi, times(6)).doSomething(); + verifyAllServersContacted(jaxRsClientFactory); + } + + private static void verifyAllServersContacted( + final JaxRsClientFactory jaxRsClientFactory) { + final ArgumentCaptor<HostName> hostNameCaptor = ArgumentCaptor.forClass(HostName.class); + verify(jaxRsClientFactory, atLeast(SERVER_HOSTS.size())) + .createClient(eq(TestJaxRsApi.class), hostNameCaptor.capture(), eq(REST_PORT), eq(API_PATH)); + final Set<HostName> actualServerHostsContacted = new HashSet<>(hostNameCaptor.getAllValues()); + assertThat(actualServerHostsContacted, equalTo(SERVER_HOSTS)); + } +} |