package oncue.tests.clients; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import oncue.client.Client; import oncue.client.ClientException; import oncue.client.HttpClient; import oncue.common.messages.Job; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.api.client.http.LowLevelHttpRequest; import com.google.api.client.http.LowLevelHttpResponse; import com.google.api.client.json.Json; import com.google.api.client.testing.http.MockHttpTransport; import com.google.api.client.testing.http.MockLowLevelHttpRequest; import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.client.util.StreamingContent; public class HttpClientTest { private static String samplePostJobsResponse = "{\"enqueued_at\" : \"2013-03-23T12:13:14+00:00\",\"worker_type\" : \"com.example.ExampleWorker\",\"id\" : 2,\"params\" : {\"key1\" : \"Value 1\",\"key2\" : \"Value 2\"},\"progress\" : 0.5}"; private static String sampleGetJobsResponse = "[{\"enqueued_at\" : \"2013-03-23T12:13:14+00:00\",\"worker_type\" : \"com.example.ExampleWorker\",\"id\" : 2,\"params\" : {\"key1\" : \"Value 1\",\"key2\" : \"Value 2\"},\"progress\" : 0.5 }]"; @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void clientPostsToConfiguredUrl() throws ClientException { ClientMockTransport transport = new ClientMockTransport(200, samplePostJobsResponse); Client client = new HttpClient(transport); client.enqueueJob("com.example.SubmittedJob"); Assert.assertEquals("http://localhost:9000/api/jobs", transport.getUrl()); } @Test public void clientPostsWorkerNameInRequestBody() throws ClientException, IOException { ClientMockTransport transport = new ClientMockTransport(200, samplePostJobsResponse); Client client = new HttpClient(transport); client.enqueueJob("com.example.SubmittedJob"); Map<String, Object> requestMap = transport.getRequestContentAsMap(); Assert.assertEquals("com.example.SubmittedJob", requestMap.get("worker_type")); } @SuppressWarnings("rawtypes") @Test public void clientPostsEmptyParamsInBody() throws ClientException, IOException { ClientMockTransport transport = new ClientMockTransport(200, samplePostJobsResponse); Client client = new HttpClient(transport); client.enqueueJob("com.example.SubmittedJob"); Map<String, Object> requestMap = transport.getRequestContentAsMap(); assertNotNull(requestMap.get("params")); assertTrue(requestMap.get("params") instanceof Map); assertTrue(((Map) requestMap.get("params")).isEmpty()); } @Test public void clientPostsNonEmptyParamsInBody() throws ClientException, IOException { ClientMockTransport transport = new ClientMockTransport(200, samplePostJobsResponse); Client client = new HttpClient(transport); Map<String, String> params = new HashMap<>(); params.put("key1", "value1"); params.put("key2", "value2"); client.enqueueJob("com.example.SubmittedJob", params); Map<String, Object> requestMap = transport.getRequestContentAsMap(); assertNotNull(requestMap.get("params")); assertTrue(requestMap.get("params") instanceof Map); @SuppressWarnings("unchecked") Map<String, String> bodyParams = (Map<String, String>) requestMap.get("params"); assertEquals(params, bodyParams); } @Test public void clientParsesValidResponseIntoJob() throws ClientException { ClientMockTransport transport = new ClientMockTransport(200, samplePostJobsResponse); Client client = new HttpClient(transport); Job job = client.enqueueJob("com.example.SubmittedJob"); assertNotNull(job); assertEquals(2, job.getId()); assertTrue(new DateTime(2013, 3, 23, 12, 13, 14, DateTimeZone.forID("+00:00")).compareTo(job.getEnqueuedAt()) == 0); assertEquals(0.5, job.getProgress(), 0); assertEquals("com.example.ExampleWorker", job.getWorkerType()); assertNotNull(job.getParams()); assertEquals(2, job.getParams().size()); assertEquals("Value 1", job.getParams().get("key1")); assertEquals("Value 2", job.getParams().get("key2")); } @Test public void clientThrowsExceptionWhenInvalidResponseBodyReturned() throws ClientException { ClientMockTransport transport = new ClientMockTransport(200, "nonsense"); Client client = new HttpClient(transport); expectedException.expect(ClientException.class); client.enqueueJob("com.example.SubmittedJob"); } @Test public void clientThrowsExceptionWhenNon200ResponseCodeReturned() throws ClientException { ClientMockTransport transport = new ClientMockTransport(404, samplePostJobsResponse); Client client = new HttpClient(transport); expectedException.expect(ClientException.class); client.enqueueJob("com.example.SubmittedJob"); } @Test public void getJobsParsesValidResponseIntoCollectionOfJobs() throws ClientException { ClientMockTransport transport = new ClientMockTransport(200, sampleGetJobsResponse); Client client = new HttpClient(transport); Collection<Job> jobs = client.getJobs(); assertNotNull(jobs); assertEquals(1, jobs.size()); Iterator<Job> jobsIterator = jobs.iterator(); assertNotNull(jobsIterator); assertTrue(jobsIterator.hasNext()); Job job = jobsIterator.next(); assertEquals(2, job.getId()); assertTrue(new DateTime(2013, 3, 23, 12, 13, 14, DateTimeZone.forID("+00:00")).compareTo(job.getEnqueuedAt()) == 0); assertEquals(0.5, job.getProgress(), 0); assertEquals("com.example.ExampleWorker", job.getWorkerType()); assertNotNull(job.getParams()); assertEquals(2, job.getParams().size()); assertEquals("Value 1", job.getParams().get("key1")); assertEquals("Value 2", job.getParams().get("key2")); assertFalse(jobsIterator.hasNext()); } @Test public void getJobsThrowsExceptionWhenInvalidResponseBodyReturned() throws ClientException { ClientMockTransport transport = new ClientMockTransport(200, "nonsense"); Client client = new HttpClient(transport); expectedException.expect(ClientException.class); client.getJobs(); } @Test public void getJobsThrowsExceptionWhenNon200ResponseCodeReturned() throws ClientException { ClientMockTransport transport = new ClientMockTransport(404, sampleGetJobsResponse); Client client = new HttpClient(transport); expectedException.expect(ClientException.class); client.getJobs(); } public class ClientMockTransport extends MockHttpTransport { private int responseCode; private String responseBody; private String method; private String url; private MockLowLevelHttpRequest request; ClientMockTransport(int responseCode, String responseBody) { this.responseCode = responseCode; this.responseBody = responseBody; } @Override public LowLevelHttpRequest buildRequest(String method, String url) { this.method = method; this.url = url; request = new MockLowLevelHttpRequest() { @Override public LowLevelHttpResponse execute() { MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); response.setStatusCode(responseCode); response.setContentType(Json.MEDIA_TYPE); response.setContent(responseBody); return response; } }; return request; } public String getMethod() { return method; } public String getUrl() { return url; } public String getRequestContent() throws IOException { StreamingContent streamingContent = request.getStreamingContent(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); streamingContent.writeTo(stream); return new String(stream.toByteArray()); } public Map<String, Object> getRequestContentAsMap() throws JsonParseException, JsonMappingException, IOException { JsonFactory factory = new JsonFactory(); ObjectMapper mapper = new ObjectMapper(factory); TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() { }; return mapper.readValue(getRequestContent(), typeRef); } } }