diff --git a/unirest-bdd-tests/src/test/java/BehaviorTests/AsPagedTest.java b/unirest-bdd-tests/src/test/java/BehaviorTests/AsPagedTest.java index b0b84191..14fc3f66 100644 --- a/unirest-bdd-tests/src/test/java/BehaviorTests/AsPagedTest.java +++ b/unirest-bdd-tests/src/test/java/BehaviorTests/AsPagedTest.java @@ -1,8 +1,8 @@ /** * The MIT License - * + *

* Copyright for portions of unirest-java are held by Kong Inc (c) 2013. - * + *

* Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -10,10 +10,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + *

* The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -41,38 +41,63 @@ class AsPagedTest extends BddTest { void canFollowPaging() { MockServer.expectedPages(10); - PagedList result = Unirest.get(MockServer.PAGED) + PagedList result = Unirest.get(MockServer.PAGED) + .header("x-header", "h-value") .asPaged( r -> r.asObject(RequestCapture.class), r -> r.getHeaders().getFirst("nextPage") ); - assertEquals(10, result.size()); + assertThat(result) + .hasSize(10) + .allMatch(r -> { + r.getBody().assertHeader("x-header", "h-value"); + return true; + }); + } + + @Test + void canFollowPagingForPost() { + MockServer.expectedPages(10); + + PagedList result = Unirest.post(MockServer.PAGED) + .body("Hi Mom") + .asPaged( + r -> r.asObject(RequestCapture.class), + r -> r.getHeaders().getFirst("nextPage") + ); + + assertThat(result) + .hasSize(10) + .allMatch(r -> { + r.getBody().assertBody("Hi Mom"); + return true; + }); } @Test void canCapturePagesAsStrings() { MockServer.expectedPages(10); - PagedList result = Unirest.get(MockServer.PAGED) + PagedList result = Unirest.get(MockServer.PAGED) .asPaged( r -> r.asString(), r -> r.getHeaders().getFirst("nextPage") ); - assertEquals(10, result.size()); + assertThat(result).hasSize(10); + } @Test void willReturnOnePageIfthereWasNoPaging() { - - PagedList result = Unirest.get(MockServer.PAGED) + PagedList result = Unirest.get(MockServer.PAGED) .asPaged( r -> r.asObject(RequestCapture.class), r -> null ); - assertEquals(1, result.size()); + assertThat(result).hasSize(1); } @Test @@ -82,8 +107,8 @@ void asPagedWithRedirects() { var responses = Unirest.get(MockServer.REDIRECT) .asPaged(HttpRequest::asString, response -> List.of(301, 302).contains(response.getStatus()) - ? "http://localhost:4567/" + response.getHeaders().getFirst("Location") - : null); + ? "http://localhost:4567/" + response.getHeaders().getFirst("Location") + : null); assertThat(responses).hasSize(2); diff --git a/unirest-bdd-tests/src/test/java/BehaviorTests/MockServer.java b/unirest-bdd-tests/src/test/java/BehaviorTests/MockServer.java index 2a9dd196..211273c2 100644 --- a/unirest-bdd-tests/src/test/java/BehaviorTests/MockServer.java +++ b/unirest-bdd-tests/src/test/java/BehaviorTests/MockServer.java @@ -130,6 +130,7 @@ public static void reset() { app.get("/proxy", MockServer::proxiedResponse); app.get("/binary", MockServer::file); app.get("/paged", MockServer::paged); + app.post("/paged", MockServer::paged); app.post("/raw", MockServer::echo); app.get("/error", MockServer::error); app.get("/hello", MockServer::helloWOrld); diff --git a/unirest/src/main/java/kong/unirest/core/BaseRequest.java b/unirest/src/main/java/kong/unirest/core/BaseRequest.java index fd449711..ed59b3ee 100644 --- a/unirest/src/main/java/kong/unirest/core/BaseRequest.java +++ b/unirest/src/main/java/kong/unirest/core/BaseRequest.java @@ -62,6 +62,7 @@ abstract class BaseRequest implements HttpRequest { this.connectTimeout = httpRequest.connectTimeout; this.objectMapper = httpRequest.objectMapper; this.version = httpRequest.version; + this.downloadMonitor = httpRequest.downloadMonitor; } BaseRequest(Config config, HttpMethod method, String url) { @@ -180,6 +181,10 @@ public R downloadMonitor(ProgressMonitor monitor) { return (R) this; } + public ProgressMonitor getDownloadMonitor(){ + return this.downloadMonitor; + } + @Override public R version(HttpClient.Version value) { this.version = value; @@ -339,13 +344,15 @@ public PagedList asPaged(Function mappingFunct String nextLink = this.getUrl(); do { this.url = new Path(nextLink, config.getDefaultBaseUrl()); - HttpResponse next = mappingFunction.apply(this); + BaseRequest t = RequestFactory.copy(this); + HttpResponse next = mappingFunction.apply(t); all.add(next); nextLink = linkExtractor.apply(next); } while (!Util.isNullOrEmpty(nextLink)); return all; } + private HttpResponse request(Function> transformer, Class resultType){ HttpResponse response = config.getClient().request(this, transformer, resultType); diff --git a/unirest/src/main/java/kong/unirest/core/HttpRequestBody.java b/unirest/src/main/java/kong/unirest/core/HttpRequestBody.java index 879f4264..f956322f 100644 --- a/unirest/src/main/java/kong/unirest/core/HttpRequestBody.java +++ b/unirest/src/main/java/kong/unirest/core/HttpRequestBody.java @@ -43,6 +43,11 @@ public HttpRequestBody(Config config, HttpMethod method, String url) { super(config, method, url); } + public HttpRequestBody(HttpRequestBody baseRequest) { + super(baseRequest); + this.charSet = baseRequest.getCharset(); + } + @Override public MultipartBody field(String name, Collection value) { return new HttpRequestMultiPart(this).field(name, value); diff --git a/unirest/src/main/java/kong/unirest/core/HttpRequestMultiPart.java b/unirest/src/main/java/kong/unirest/core/HttpRequestMultiPart.java index bb70f2f7..d8387e7e 100644 --- a/unirest/src/main/java/kong/unirest/core/HttpRequestMultiPart.java +++ b/unirest/src/main/java/kong/unirest/core/HttpRequestMultiPart.java @@ -44,6 +44,15 @@ class HttpRequestMultiPart extends BaseRequest implements Multipa this.charSet = httpRequest.getCharset(); } + HttpRequestMultiPart(HttpRequestMultiPart httpRequest) { + super(httpRequest); + this.charSet = httpRequest.getCharset(); + this.parameters = httpRequest.parameters; + this.forceMulti = httpRequest.forceMulti; + this.monitor = httpRequest.monitor; + this.boundary = httpRequest.boundary; + } + @Override public MultipartBody field(String name, String value) { addPart(new ParamPart(name, value)); diff --git a/unirest/src/main/java/kong/unirest/core/HttpRequestNoBody.java b/unirest/src/main/java/kong/unirest/core/HttpRequestNoBody.java index f9c29bad..0f5f75cf 100644 --- a/unirest/src/main/java/kong/unirest/core/HttpRequestNoBody.java +++ b/unirest/src/main/java/kong/unirest/core/HttpRequestNoBody.java @@ -32,6 +32,10 @@ class HttpRequestNoBody extends BaseRequest implements GetRequest { super(config, method, url); } + HttpRequestNoBody(HttpRequestNoBody baseRequest) { + super(baseRequest); + } + @Override public Optional getBody() { return Optional.empty(); diff --git a/unirest/src/main/java/kong/unirest/core/HttpRequestUniBody.java b/unirest/src/main/java/kong/unirest/core/HttpRequestUniBody.java index ea747c7a..eb2237a3 100644 --- a/unirest/src/main/java/kong/unirest/core/HttpRequestUniBody.java +++ b/unirest/src/main/java/kong/unirest/core/HttpRequestUniBody.java @@ -42,6 +42,13 @@ class HttpRequestUniBody extends BaseRequest implements Reque this.charSet = httpRequest.getCharset(); } + HttpRequestUniBody(HttpRequestUniBody httpRequest) { + super(httpRequest); + this.charSet = httpRequest.getCharset(); + this.body = httpRequest.body; + this.monitor = httpRequest.monitor; + } + @Override public RequestBodyEntity body(JsonNode jsonBody) { return body(jsonBody.toString()); diff --git a/unirest/src/main/java/kong/unirest/core/RequestFactory.java b/unirest/src/main/java/kong/unirest/core/RequestFactory.java new file mode 100644 index 00000000..190f7b29 --- /dev/null +++ b/unirest/src/main/java/kong/unirest/core/RequestFactory.java @@ -0,0 +1,20 @@ +package kong.unirest.core; + +class RequestFactory { + public static R copy(HttpRequest baseRequest) { + if(baseRequest instanceof HttpRequestNoBody){ + return (R) new HttpRequestNoBody((HttpRequestNoBody)baseRequest); + } + if(baseRequest instanceof HttpRequestBody){ + return (R) new HttpRequestBody((HttpRequestBody)baseRequest); + } + if(baseRequest instanceof HttpRequestUniBody){ + return (R) new HttpRequestUniBody((HttpRequestUniBody)baseRequest); + } + if(baseRequest instanceof HttpRequestMultiPart) { + return (R) new HttpRequestMultiPart((HttpRequestMultiPart)baseRequest); + } + + throw new UnirestException("Cannot find matching type: " + baseRequest.getClass()); + } +} diff --git a/unirest/src/test/java/kong/unirest/core/RequestFactoryTest.java b/unirest/src/test/java/kong/unirest/core/RequestFactoryTest.java new file mode 100644 index 00000000..1f129513 --- /dev/null +++ b/unirest/src/test/java/kong/unirest/core/RequestFactoryTest.java @@ -0,0 +1,244 @@ +package kong.unirest.core; + +import org.assertj.core.api.AbstractAssert; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import static kong.unirest.core.RequestFactoryTest.RequestAsserts.assertRequest; +import static kong.unirest.core.Util.tryCast; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class RequestFactoryTest { + + private final String url = "http://foo"; + private final String headerKey = "header-key"; + private final String headerValue = "header-value"; + private final String queryKey = "query-key"; + private final String queryValue = "query-value"; + private final String urlWithQuery = url + "?" + queryKey + "=" + queryValue; + private final ProgressMonitor downloadMonitor = mock(ProgressMonitor.class); + private final ProgressMonitor uploadMonitor = mock(ProgressMonitor.class); + private final ObjectMapper om = mock(ObjectMapper.class); + + @Test + void copy_get() { + var req = Unirest.get(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .downloadMonitor(downloadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestNoBody.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.GET, urlWithQuery) + .assertDownloadMonitorIs(downloadMonitor) + .assertObjectMapperIs(om); + } + + @Test + void copy_head() { + var req = Unirest.head(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .downloadMonitor(downloadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestNoBody.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.HEAD, urlWithQuery) + .assertDownloadMonitorIs(downloadMonitor) + .assertObjectMapperIs(om); + } + + @Test + void copy_delete() { + var req = Unirest.delete(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .charset(StandardCharsets.ISO_8859_1) + .downloadMonitor(downloadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestBody.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.DELETE, urlWithQuery) + .assertDownloadMonitorIs(downloadMonitor) + .assertObjectMapperIs(om); + } + + @Test + void copy_put_unibody() { + var req = Unirest.put(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .charset(StandardCharsets.ISO_8859_1) + .body("hi mom") + .downloadMonitor(downloadMonitor) + .uploadMonitor(uploadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestUniBody.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.PUT, urlWithQuery) + .assertCharset(StandardCharsets.ISO_8859_1) + .assertBody("hi mom") + .assertDownloadMonitorIs(downloadMonitor) + .asserrUploadMonitorIs(uploadMonitor) + .assertObjectMapperIs(om); + } + + @Test + void copy_post_unibody() { + var req = Unirest.post(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .charset(StandardCharsets.ISO_8859_1) + .body("hi mom") + .downloadMonitor(downloadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestUniBody.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.POST, urlWithQuery) + .assertCharset(StandardCharsets.ISO_8859_1) + .assertBody("hi mom") + .assertDownloadMonitorIs(downloadMonitor) + .assertObjectMapperIs(om); + } + + @Test + void copy_post_formBody() { + var req = Unirest.post(url) + .header(headerKey, headerValue) + .queryString(queryKey, queryValue) + .field("foo", "bar") + .field("file", new File("./myfile.xml")) + .boundary("my-boundary") + .downloadMonitor(downloadMonitor) + .uploadMonitor(uploadMonitor) + .withObjectMapper(om); + + var copy = RequestFactory.copy(req); + + assertRequest(copy) + .isInstanceOf(HttpRequestMultiPart.class) + .assertHeader(headerKey, headerValue) + .assertRoute(HttpMethod.POST, urlWithQuery) + .assertField("foo", "bar") + .assertBoundary("my-boundary") + .assertDownloadMonitorIs(downloadMonitor) + .asserrUploadMonitorIs(uploadMonitor) + .assertObjectMapperIs(om); + } + + + + static class RequestAsserts extends AbstractAssert { + + public static RequestAsserts assertRequest(HttpRequest request){ + return new RequestAsserts(request); + } + + RequestAsserts(HttpRequest httpRequest) { + super(httpRequest, RequestAsserts.class); + } + + public RequestAsserts assertHeader(String headerKey, String headerValue) { + assertTrue(actual.getHeaders().containsKey(headerKey), "Missing Header Key " + headerKey); + assertEquals(headerValue, actual.getHeaders().getFirst(headerKey)); + return this; + } + + public RequestAsserts assertRoute(HttpMethod get, String url) { + assertEquals(get, actual.getHttpMethod()); + assertEquals(url, actual.getUrl()); + return this; + } + + public RequestAsserts assertCharset(Charset expected) { + Body o = getBody(); + assertEquals(expected, o.getCharset(), "Mismatched charset on body content"); + return this; + } + + public RequestAsserts assertBody(String expected) { + Body o = getBody(); + assertEquals(expected, o.uniPart().getValue()); + return this; + } + + private Body getBody() { + var b = tryAs(HttpRequest.class); + Body o = (Body)b.getBody().get(); + return o; + } + + private T tryAs(Class clss) { + return tryCast(actual, clss) + .orElseThrow(() -> err("Could not cast subject (%s) to (%s)", actual.getClass(), clss)); + } + + private AssertionError err(String mssg, Object... args){ + return new AssertionError(String.format(mssg, args)); + } + + public RequestAsserts assertField(String key, String value) { + var body = tryAs(HttpRequestMultiPart.class) + .getBody() + .orElseThrow(() -> new AssertionError("No body found!")); + for (BodyPart part : body.multiParts()){ + if(part.getName().equals(key) && part.getValue().equals(value)){ + return this; + } + } + throw err("Cannot find field: %s: %s", key, value); + } + + public RequestAsserts assertBoundary(String boundary) { + assertEquals(boundary, tryAs(HttpRequestMultiPart.class).getBoundary(), "Wrong Boundary!"); + return this; + } + + public RequestAsserts assertDownloadMonitorIs(ProgressMonitor expected) { + assertSame(expected, tryAs(BaseRequest.class).getDownloadMonitor()); + return this; + } + + public RequestAsserts asserrUploadMonitorIs(ProgressMonitor uploadMonitor) { + assertSame(uploadMonitor, getUploadMonitor()); + return this; + } + + private ProgressMonitor getUploadMonitor() { + try { + return tryAs(HttpRequestUniBody.class).getMonitor(); + }catch (AssertionError e){ + return tryAs(HttpRequestMultiPart.class).getMonitor(); + } + } + + public RequestAsserts assertObjectMapperIs(ObjectMapper om) { + assertSame(om, tryAs(BaseRequest.class).getObjectMapper()); + return this; + } + } +} \ No newline at end of file