Java tutorial
/* * Copyright 2015 SirWellington Tech. * * Licensed 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 tech.sirwellington.alchemy.http; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonParser; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import sir.wellington.alchemy.collections.lists.Lists; import tech.sirwellington.alchemy.http.exceptions.AlchemyHttpException; import tech.sirwellington.alchemy.http.exceptions.JsonException; import tech.sirwellington.alchemy.test.junit.runners.AlchemyTestRunner; import tech.sirwellington.alchemy.test.junit.runners.DontRepeat; import tech.sirwellington.alchemy.test.junit.runners.Repeat; import static java.lang.System.currentTimeMillis; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static tech.sirwellington.alchemy.generator.AlchemyGenerator.one; import static tech.sirwellington.alchemy.generator.CollectionGenerators.listOf; import static tech.sirwellington.alchemy.generator.CollectionGenerators.mapOf; import static tech.sirwellington.alchemy.generator.NumberGenerators.integers; import static tech.sirwellington.alchemy.generator.StringGenerators.alphabeticString; import static tech.sirwellington.alchemy.generator.StringGenerators.alphanumericString; import static tech.sirwellington.alchemy.generator.StringGenerators.hexadecimalString; import static tech.sirwellington.alchemy.http.Generators.jsonElements; import static tech.sirwellington.alchemy.http.Generators.jsonObjects; import static tech.sirwellington.alchemy.test.junit.ThrowableAssertion.assertThrows; /** * * @author SirWellington */ @RunWith(AlchemyTestRunner.class) @Repeat(100) public class HttpVerbImplTest { @Mock private AlchemyRequestMapper requestMapper; @Mock private HttpClient apacheClient; @Mock private HttpRequest request; @Mock private HttpUriRequest apacheRequest; @Mock private CloseableHttpResponse apacheResponse; @Mock private StatusLine statusLine; private HttpEntity entity; private JsonElement responseBody; private Map<String, String> responseHeaders; private HttpVerb instance; private final Gson gson = Constants.getDefaultGson(); @Before public void setUp() throws IOException { instance = new HttpVerbImpl(requestMapper); verifyZeroInteractions(requestMapper); when(requestMapper.convertToApacheRequest(request)).thenReturn(apacheRequest); responseBody = one(jsonElements()); entity = new StringEntity(responseBody.toString(), ContentType.APPLICATION_JSON); setupResponse(); } public void setupResponse() throws IOException { when(apacheResponse.getEntity()).thenReturn(entity); when(apacheResponse.getStatusLine()).thenReturn(statusLine); when(statusLine.getStatusCode()).thenReturn(one(integers(200, 209))); when(apacheClient.execute(apacheRequest)).thenReturn(apacheResponse); setupResponseHeaders(); } public void setupResponseHeaders() { responseHeaders = mapOf(alphabeticString(), hexadecimalString(10), 15); List<Header> headers = Lists.create(); responseHeaders.forEach((k, v) -> headers.add(new BasicHeader(k, v))); Header[] headerArray = headers.toArray(new Header[headers.size()]); when(apacheResponse.getAllHeaders()).thenReturn(headerArray); } @Test public void testUsing() { HttpVerbImpl result = HttpVerbImpl.using(requestMapper); assertThat(result, notNullValue()); assertThrows(() -> HttpVerbImpl.using(null)).isInstanceOf(IllegalArgumentException.class); } @Test public void testExecute() throws IOException { HttpResponse response = instance.execute(apacheClient, request); assertThat(response, notNullValue()); assertThat(response.statusCode(), is(statusLine.getStatusCode())); assertThat(response.isOk(), is(true)); assertThat(response.body(), is(responseBody)); assertThat(response.responseHeaders(), is(responseHeaders)); assertThat(response.bodyAsString(), is(responseBody.toString())); verify(apacheResponse).close(); } //Edge Cases @DontRepeat @Test public void testExecuteWithBadArgs() { assertThrows(() -> instance.execute(null, null)).isInstanceOf(IllegalArgumentException.class); assertThrows(() -> instance.execute(null, request)).isInstanceOf(IllegalArgumentException.class); assertThrows(() -> instance.execute(apacheClient, null)).isInstanceOf(IllegalArgumentException.class); } @Test public void testExecuteWhenRequestMapperReturnsNull() { when(requestMapper.convertToApacheRequest(request)).thenReturn(null); assertThrows(() -> instance.execute(apacheClient, request)).isInstanceOf(AlchemyHttpException.class); } @Test public void testExecuteWhenApacheClientThrows() throws IOException { when(apacheClient.execute(apacheRequest)).thenThrow(new IOException()); assertThrows(() -> instance.execute(apacheClient, request)).isInstanceOf(AlchemyHttpException.class); } @DontRepeat @Test public void testExecuteWhenResponseIsNull() throws IOException { when(apacheClient.execute(apacheRequest)).thenReturn(null); assertThrows(() -> instance.execute(apacheClient, request)).isInstanceOf(AlchemyHttpException.class); } @DontRepeat @Test public void testExecuteWhenEntityIsNull() { when(apacheResponse.getEntity()).thenReturn(null); HttpResponse result = instance.execute(apacheClient, request); assertThat(result, notNullValue()); assertThat(result.body(), is(JsonNull.INSTANCE)); } @DontRepeat @Test public void testExecuteWhenReadingEntityFails() throws IOException { HttpEntity badEntity = mock(HttpEntity.class); when(apacheResponse.getEntity()).thenReturn(badEntity); when(badEntity.getContent()).thenThrow(new IOException()); assertThrows(() -> instance.execute(apacheClient, request)).isInstanceOf(AlchemyHttpException.class); } @DontRepeat @Test public void testExecuteWhenBodyIsEmpty() throws Exception { entity = new StringEntity(""); when(apacheResponse.getEntity()).thenReturn(entity); HttpResponse result = instance.execute(apacheClient, request); assertThat(result.body(), instanceOf(JsonNull.class)); } /* * We are no longer sure if an invalid content type should constitute a failure. * */ @Test public void testExecuteWhenContentTypeInvalid() throws IOException { List<ContentType> invalidContentTypes = Arrays.asList(ContentType.APPLICATION_ATOM_XML, ContentType.TEXT_HTML, ContentType.TEXT_XML, ContentType.APPLICATION_XML, ContentType.APPLICATION_OCTET_STREAM, ContentType.create(one(alphabeticString()))); ContentType invalidContentType = Lists.oneOf(invalidContentTypes); String string = one(alphanumericString()); entity = new StringEntity(string, invalidContentType); when(apacheResponse.getEntity()).thenReturn(entity); HttpResponse result = instance.execute(apacheClient, request); assertThat(result.bodyAsString(), is(string)); verify(apacheResponse).close(); } @DontRepeat @Test public void testExecuteWhenNoResponseHeaders() throws Exception { when(apacheResponse.getAllHeaders()).thenReturn(null); HttpResponse result = instance.execute(apacheClient, request); assertThat(result.responseHeaders(), notNullValue()); assertThat(result.responseHeaders().isEmpty(), is(true)); } @Test public void testExecuteWhenEntityIsNotJson() { String html = String.format("<%s>%s</%s>", "someTag", one(hexadecimalString(100)), "someTag"); entity = new StringEntity(html, ContentType.APPLICATION_JSON); when(apacheResponse.getEntity()).thenReturn(entity); assertThrows(() -> instance.execute(apacheClient, request)).isInstanceOf(JsonException.class); } @Test public void testExecuteWhenEntityIsText() { String text = one(alphabeticString()); entity = new StringEntity(text, ContentType.TEXT_PLAIN); when(apacheResponse.getEntity()).thenReturn(entity); HttpResponse result = instance.execute(apacheClient, request); assertThat(result, notNullValue()); assertThat(result.bodyAsString(), is(text)); JsonElement asJSON = result.body(); assertThat(asJSON.isJsonPrimitive(), is(true)); assertThat(asJSON.getAsJsonPrimitive().isString(), is(true)); } @Test public void testWhenDuplicateValuesInAHeader() { String headerName = one(alphabeticString()); List<String> headerValues = listOf(alphabeticString(), 5); List<Header> headers = Lists.create(); for (String value : headerValues) { headers.add(new BasicHeader(headerName, value)); } Header[] headerArray = headers.toArray(new Header[0]); when(apacheResponse.getAllHeaders()).thenReturn(headerArray); HttpResponse response = instance.execute(apacheClient, request); Map<String, String> responseHeaders = response.responseHeaders(); assertThat(responseHeaders, notNullValue()); assertThat(responseHeaders.containsKey(headerName), is(true)); String resultValue = responseHeaders.get(headerName); headerValues.forEach(value -> assertThat(resultValue, containsString(value))); } @DontRepeat @Test public void testPerformance() { JsonParser parser = new JsonParser(); System.out.println("performance test"); String body = one(jsonObjects()).toString(); long time = time(() -> parser.parse(body)); System.out.println("Parser took " + time); time = time(() -> gson.fromJson(body, JsonElement.class)); System.out.println("Gson took " + time); int iterations = 100; Runnable task; task = () -> { for (int i = 0; i < iterations; ++i) { parser.parse(body); } }; time = time(task); System.out.printf("Parser took %dms accross %d runs\n", time, iterations); task = () -> { for (int i = 0; i < iterations; ++i) { gson.fromJson(body, JsonElement.class); } }; time = time(task); System.out.printf("Gson took %dms accross %d runs\n", time, iterations); } @DontRepeat @Test public void compareGsonMethods() { responseBody = one(jsonObjects()); String text = responseBody.toString(); JsonElement fromJson = gson.fromJson(text, JsonElement.class); JsonElement toJsonTree = gson.toJsonTree(text); boolean equals = fromJson.equals(toJsonTree); System.out.println("Equal? " + equals); } private static long time(Runnable task) { long start = currentTimeMillis(); task.run(); long end = currentTimeMillis(); return end - start; } }