package com.github.dreamhead.moco; import com.fasterxml.jackson.core.type.TypeReference; import com.github.dreamhead.moco.util.Jsons; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.io.Files; import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.Charset; import java.util.List; import static com.github.dreamhead.moco.Moco.by; import static com.github.dreamhead.moco.Moco.context; import static com.github.dreamhead.moco.Moco.eq; import static com.github.dreamhead.moco.Moco.header; import static com.github.dreamhead.moco.Moco.log; import static com.github.dreamhead.moco.Moco.query; import static com.github.dreamhead.moco.Moco.status; import static com.github.dreamhead.moco.Moco.text; import static com.github.dreamhead.moco.Moco.toJson; import static com.github.dreamhead.moco.Moco.uri; import static com.github.dreamhead.moco.Moco.with; import static com.github.dreamhead.moco.MocoRequestHit.requestHit; import static com.github.dreamhead.moco.MocoRequestHit.times; import static com.github.dreamhead.moco.MocoRest.anyId; import static com.github.dreamhead.moco.MocoRest.delete; import static com.github.dreamhead.moco.MocoRest.get; import static com.github.dreamhead.moco.MocoRest.head; import static com.github.dreamhead.moco.MocoRest.id; import static com.github.dreamhead.moco.MocoRest.patch; import static com.github.dreamhead.moco.MocoRest.post; import static com.github.dreamhead.moco.MocoRest.put; import static com.github.dreamhead.moco.MocoRest.restServer; import static com.github.dreamhead.moco.Runner.running; import static com.github.dreamhead.moco.helper.RemoteTestUtils.port; import static com.github.dreamhead.moco.helper.RemoteTestUtils.remoteUrl; import static com.google.common.collect.ImmutableMultimap.of; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; public class MocoRestTest extends BaseMocoHttpTest<RestServer> { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Override protected RestServer createServer(final int port) { return restServer(port, log()); } @Test public void should_get_resource_by_id() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); } }); } @Test public void should_get_all_resources() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get().response(toJson(ImmutableList.of(resource1, resource2))) ); running(server, new Runnable() { @Override public void run() throws Exception { String uri = "/targets"; List<Plain> plains = getResources(uri); assertThat(plains.size(), is(2)); } }); } @Test public void should_get_all_resources_by_default() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); running(server, new Runnable() { @Override public void run() throws Exception { List<Plain> plains = getResources("/targets"); assertThat(plains.size(), is(2)); } }); } @Test public void should_reply_404_for_unknown_resource() throws Exception { server.resource("targets", get("2").response(with(text("hello")))); running(server, new Runnable() { @Override public void run() throws Exception { org.apache.http.HttpResponse response = helper.getResponse(remoteUrl("/targets/1")); assertThat(response.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_request_server_by_moco_config() throws Exception { RestServer server = restServer(12306, context("/rest"), Moco.response(header("foo", "bar"))); Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/rest/targets/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/rest/targets/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); org.apache.http.HttpResponse response = helper.getResponse(remoteUrl("/rest/targets/1")); assertThat(response.getHeaders("foo")[0].getValue(), is("bar")); } }); } @Test public void should_log_request_and_response() throws Exception { RestServer server = restServer(port(), log()); Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "0XCAFE"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "0XBABE"; server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); File file = folder.newFile(); System.setOut(new PrintStream(new FileOutputStream(file))); running(server, new Runnable() { @Override public void run() throws Exception { helper.get(remoteUrl("/targets")); } }); String actual = Files.toString(file, Charset.defaultCharset()); assertThat(actual, containsString("0XCAFE")); assertThat(actual, containsString("0XBABE")); } @Test public void should_get_resource_by_id_with_request_config() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get("1").request(eq(header(HttpHeaders.CONTENT_TYPE), "application/json")).response(toJson(resource1)), get("2").request(eq(header(HttpHeaders.CONTENT_TYPE), "application/json")).response(toJson(resource2)) ); running(server, new Runnable() { @Override public void run() throws Exception { org.apache.http.HttpResponse response = helper.getResponseWithHeader(remoteUrl("/targets/1"), of(HttpHeaders.CONTENT_TYPE, "application/json")); Plain response1 = asPlain(response); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); org.apache.http.HttpResponse otherResponse = helper.getResponseWithHeader(remoteUrl("/targets/2"), of(HttpHeaders.CONTENT_TYPE, "application/json")); Plain response2 = asPlain(otherResponse); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); org.apache.http.HttpResponse notFoundResponse = helper.getResponse(remoteUrl("/targets/1")); assertThat(notFoundResponse.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_query_with_condition() throws Exception { RestServer server = restServer(12306); Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get().request(eq(query("foo"), "bar")).response(toJson(ImmutableList.of(resource1, resource2))) ); running(server, new Runnable() { @Override public void run() throws Exception { List<Plain> plains = Jsons.toObject(helper.get(remoteUrl("/targets?foo=bar")), new TypeReference<List<Plain>>() { }); assertThat(plains.size(), is(2)); HttpResponse response = helper.getResponse(remoteUrl("/targets")); assertThat(response.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_get_resource_by_any_id() throws Exception { Plain resource = new Plain(); resource.code = 1; resource.message = "hello"; server.resource("targets", get(anyId()).response(toJson(resource)) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/2"); assertThat(response2.code, is(1)); assertThat(response2.message, is("hello")); } }); } @Test public void should_post() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", post().response(status(201), header("Location", "/targets/123")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.postForResponse(remoteUrl("/targets"), Jsons.toJson(resource1)); assertThat(httpResponse.getStatusLine().getStatusCode(), is(201)); assertThat(httpResponse.getFirstHeader("Location").getValue(), is("/targets/123")); } }); } @Test public void should_post_with_header() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", post().request(eq(header(HttpHeaders.CONTENT_TYPE), "application/json")) .response(status(201), header("Location", "/targets/123")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.postForResponse(remoteUrl("/targets"), Jsons.toJson(resource1), "application/json"); assertThat(httpResponse.getStatusLine().getStatusCode(), is(201)); assertThat(httpResponse.getFirstHeader("Location").getValue(), is("/targets/123")); HttpResponse badRequest = helper.postForResponse(remoteUrl("/targets"), Jsons.toJson(resource1)); assertThat(badRequest.getStatusLine().getStatusCode(), is(400)); } }); } @Test public void should_return_404_for_post_with_id_by_default() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", post().response(status(201), header("Location", "/targets/123")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.postForResponse(remoteUrl("/targets/1"), Jsons.toJson(resource1)); assertThat(httpResponse.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_put() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", put("1").response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.putForResponse(remoteUrl("/targets/1"), Jsons.toJson(resource1)); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_not_put_with_unknown_id() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", put("1").response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.putForResponse(remoteUrl("/targets/2"), Jsons.toJson(resource1)); assertThat(httpResponse.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_put_with_response_handler() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", put("1").response(status(409)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.putForResponse(remoteUrl("/targets/1"), Jsons.toJson(resource1)); assertThat(httpResponse.getStatusLine().getStatusCode(), is(409)); } }); } @Test public void should_put_with_matcher() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", put("1").request(eq(header(HttpHeaders.IF_MATCH), "moco")).response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.putForResponseWithHeaders(remoteUrl("/targets/1"), Jsons.toJson(resource1), of(HttpHeaders.IF_MATCH, "moco")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_put_with_any_id() throws Exception { RestServer server = restServer(12306); final Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; server.resource("targets", put(anyId()).response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse1 = helper.putForResponse(remoteUrl("/targets/1"), Jsons.toJson(resource1)); assertThat(httpResponse1.getStatusLine().getStatusCode(), is(200)); HttpResponse httpResponse2 = helper.putForResponse(remoteUrl("/targets/2"), Jsons.toJson(resource1)); assertThat(httpResponse2.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_not_delete_with_unknown_id() throws Exception { server.resource("targets", delete("1").response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.deleteForResponse(remoteUrl("/targets/2")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_delete() throws Exception { server.resource("targets", delete("1").response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.deleteForResponse(remoteUrl("/targets/1")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_delete_with_matcher() throws Exception { server.resource("targets", delete("1").request(eq(header(HttpHeaders.IF_MATCH), "moco")).response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.deleteForResponseWithHeaders(remoteUrl("/targets/1"), ImmutableMultimap.of(HttpHeaders.IF_MATCH, "moco")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_delete_with_response() throws Exception { server.resource("targets", delete("1").response(status(409)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.deleteForResponse(remoteUrl("/targets/1")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(409)); } }); } @Test public void should_delete_with_any_id() throws Exception { server.resource("targets", delete(anyId()).response(status(200)) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse1 = helper.deleteForResponse(remoteUrl("/targets/1")); assertThat(httpResponse1.getStatusLine().getStatusCode(), is(200)); HttpResponse httpResponse2 = helper.deleteForResponse(remoteUrl("/targets/2")); assertThat(httpResponse2.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_head_with_all() throws Exception { server.resource("targets", head().response(header("ETag", "Moco")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.headForResponse(remoteUrl("/targets")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); assertThat(httpResponse.getHeaders("ETag")[0].getValue(), is("Moco")); } }); } @Test public void should_head() throws Exception { server.resource("targets", head("1").response(header("ETag", "Moco")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.headForResponse(remoteUrl("/targets/1")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_not_head_with_unknown_id() throws Exception { server.resource("targets", head("1").response(header("ETag", "Moco")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.headForResponse(remoteUrl("/targets/2")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(404)); } }); } @Test public void should_head_with_matcher() throws Exception { server.resource("targets", head("1").request(eq(query("name"), "foo")).response(header("ETag", "Moco")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse = helper.headForResponse(remoteUrl("/targets/1?name=foo")); assertThat(httpResponse.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_head_with_any_id() throws Exception { server.resource("targets", head(anyId()).response(header("ETag", "Moco")) ); running(server, new Runnable() { @Override public void run() throws Exception { HttpResponse httpResponse1 = helper.headForResponse(remoteUrl("/targets/1")); assertThat(httpResponse1.getStatusLine().getStatusCode(), is(200)); HttpResponse httpResponse2 = helper.headForResponse(remoteUrl("/targets/2")); assertThat(httpResponse2.getStatusLine().getStatusCode(), is(200)); } }); } @Test public void should_patch() throws Exception { server.resource("targets", patch("1").response(with(text("patch result"))) ); running(server, new Runnable() { @Override public void run() throws Exception { assertThat(helper.patchForResponse(remoteUrl("/targets/1"), "result"), is("patch result")); } }); } @Test public void should_patch_with_any_id() throws Exception { server.resource("targets", patch(anyId()).response(with(text("patch result"))) ); running(server, new Runnable() { @Override public void run() throws Exception { assertThat(helper.patchForResponse(remoteUrl("/targets/1"), "result"), is("patch result")); } }); } @Test(expected = IllegalArgumentException.class) public void should_throw_exception_for_get_id_with_slash() throws Exception { get("1/1").response(status(200)); } @Test(expected = IllegalArgumentException.class) public void should_throw_exception_for_get_id_with_space() { get("1 1").response(status(200)); } @Test(expected = IllegalArgumentException.class) public void should_throw_exception_for_resource_name_with_slash() { server.resource("hello/world", get().response("hello")); } @Test(expected = IllegalArgumentException.class) public void should_throw_exception_for_resource_name_with_space() { server.resource("hello world", get().response("hello")); } @Test public void should_get_sub_resource() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", id("1").name("sub").settings( get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1/sub/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/1/sub/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); } }); } @Test public void should_get_sub_resource_with_any_id() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", id(anyId()).name("sub").settings( get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1/sub/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/2/sub/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); } }); } @Test(expected = IllegalArgumentException.class) public void should_throw_exception_for_invalid_sub_resource_name() { id(anyId()).name("hello world"); } @Test public void should_work_with_other_http_configuration() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); server.response("hello"); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); assertThat(helper.get(remoteUrl("/hello")), is("hello")); } }); } @Test public void should_verify_expected_request_and_log_at_same_time() throws Exception { Plain resource1 = new Plain(); resource1.code = 1; resource1.message = "hello"; Plain resource2 = new Plain(); resource2.code = 2; resource2.message = "world"; final RequestHit hit = requestHit(); final RestServer server = restServer(port(), hit, log()); server.resource("targets", get("1").response(toJson(resource1)), get("2").response(toJson(resource2)) ); running(server, new Runnable() { @Override public void run() throws Exception { Plain response1 = getResource("/targets/1"); assertThat(response1.code, is(1)); assertThat(response1.message, is("hello")); Plain response2 = getResource("/targets/2"); assertThat(response2.code, is(2)); assertThat(response2.message, is("world")); } }); hit.verify(by(uri("/targets/1")), times(1)); hit.verify(by(uri("/targets/2")), times(1)); } private Plain getResource(String uri) throws IOException { org.apache.http.HttpResponse response = helper.getResponse(remoteUrl(uri)); return asPlain(response); } private Plain asPlain(final HttpResponse response) throws IOException { HttpEntity entity = checkJsonResponse(response); return Jsons.toObject(entity.getContent(), Plain.class); } private List<Plain> getResources(final String uri) throws IOException { HttpResponse response = helper.getResponse(remoteUrl(uri)); return asPlains(response); } private List<Plain> asPlains(final HttpResponse response) throws IOException { HttpEntity entity = checkJsonResponse(response); return Jsons.toObject(entity.getContent(), new TypeReference<List<Plain>>() { }); } private HttpEntity checkJsonResponse(final HttpResponse response) { assertThat(response.getStatusLine().getStatusCode(), is(200)); HttpEntity entity = response.getEntity(); MediaType mediaType = MediaType.parse(entity.getContentType().getValue()); assertThat(mediaType.type(), is("application")); assertThat(mediaType.subtype(), is("json")); return entity; } private static class Plain { public int code; public String message; } }