From 6ade662258883c9fbbfb32930c4b02107490830f Mon Sep 17 00:00:00 2001 From: Mykola Date: Fri, 2 Jul 2021 13:22:54 -0500 Subject: [PATCH] in progress --- .../webtau/http/Http.java | 40 ++-- .../webtau/http/HttpResource.java | 200 ++++++++++++++++++ .../webtau/http/HttpResourceResponse.java | 141 ++++++++++++ .../webtau/http/HttpResourceJavaTest.java | 43 ++++ 4 files changed, 410 insertions(+), 14 deletions(-) create mode 100644 webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResource.java create mode 100644 webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResourceResponse.java create mode 100644 webtau-http/src/test/java/org/testingisdocumenting/webtau/http/HttpResourceJavaTest.java diff --git a/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/Http.java b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/Http.java index 6dcf95ad4..a3eff1e18 100644 --- a/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/Http.java +++ b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/Http.java @@ -77,6 +77,8 @@ import sun.net.www.protocol.https.HttpsURLConnectionImpl; public class Http { + protected static final String GET_METHOD = "GET"; + private static final HttpResponseValidatorWithReturn EMPTY_RESPONSE_VALIDATOR = (header, body) -> null; public static final Http http = new Http(); @@ -88,6 +90,10 @@ public class Http { public HttpApplicationMime application = new HttpApplicationMime(); public HttpTextMime text = new HttpTextMime(); + public HttpResource resource(String url) { + return new HttpResource(url); + } + public boolean ping(String url) { return ping(url, HttpQueryParams.EMPTY, HttpHeader.EMPTY); } @@ -129,7 +135,7 @@ public String concatUrl(String baseUrl, String relativeUrl) { } public E get(String url, HttpQueryParams queryParams, HttpHeader header, HttpResponseValidatorWithReturn validator) { - return executeAndValidateHttpCall("GET", queryParams.attachToUrl(url), + return executeAndValidateHttpCall(GET_METHOD, queryParams.attachToUrl(url), this::getToFullUrl, header, null, validator); } @@ -868,7 +874,7 @@ public HttpValidationResult getLastValidationResult() { } public HttpResponse getToFullUrl(String fullUrl, HttpHeader requestHeader) { - return request("GET", fullUrl, requestHeader, EmptyRequestBody.INSTANCE); + return request(GET_METHOD, fullUrl, requestHeader, EmptyRequestBody.INSTANCE); } public HttpResponse deleteToFullUrl(String fullUrl, HttpHeader requestHeader) { @@ -893,15 +899,8 @@ private R executeAndValidateHttpCall(String requestMethod, HttpHeader requestHeader, HttpRequestBody requestBody, HttpResponseValidatorWithReturn validator) { - String fullUrl = HttpConfigurations.fullUrl(url); - HttpHeader fullHeader = HttpConfigurations.fullHeader(fullUrl, url, requestHeader); - - HttpValidationResult validationResult = new HttpValidationResult(Persona.getCurrentPersona().getId(), - requestMethod, url, fullUrl, fullHeader, requestBody); - + HttpValidationResult validationResult = createValidationResult(requestMethod, url, requestHeader, requestBody); WebTauStep step = createHttpStep(validationResult, httpCall, validator); - step.setInput(new HttpStepInput(validationResult)); - step.setOutputSupplier(() -> validationResult); try { return step.execute(StepReportOptions.REPORT_ALL); @@ -910,7 +909,15 @@ private R executeAndValidateHttpCall(String requestMethod, } } - private WebTauStep createHttpStep(HttpValidationResult validationResult, + protected HttpValidationResult createValidationResult(String requestMethod, String url, HttpHeader requestHeader, HttpRequestBody requestBody) { + String fullUrl = HttpConfigurations.fullUrl(url); + HttpHeader fullHeader = HttpConfigurations.fullHeader(fullUrl, url, requestHeader); + + return new HttpValidationResult(Persona.getCurrentPersona().getId(), + requestMethod, url, fullUrl, fullHeader, requestBody); + } + + protected WebTauStep createHttpStep(HttpValidationResult validationResult, HttpCall httpCall, HttpResponseValidatorWithReturn validator) { Supplier httpCallSupplier = () -> { @@ -963,10 +970,15 @@ private WebTauStep createHttpStep(HttpValidationResult validationResult, } }; - return WebTauStep.createStep( + WebTauStep step = WebTauStep.createStep( tokenizedMessage(action("executing HTTP " + validationResult.getRequestMethod()), urlValue(validationResult.getFullUrl())), () -> tokenizedMessage(action("executed HTTP " + validationResult.getRequestMethod()), urlValue(validationResult.getFullUrl())), httpCallSupplier); + + step.setInput(new HttpStepInput(validationResult)); + step.setOutputSupplier(() -> validationResult); + + return step; } private HttpResponse followRedirects(String requestMethod, HttpCall httpCall, HttpHeader fullRequestHeader, HttpResponse response) { @@ -1104,7 +1116,7 @@ private Integer defaultExpectedStatusCodeByRequest(HttpValidationResult validati case "DELETE": case "PATCH": return validationResult.hasResponseContent() ? 200 : 204; - case "GET": + case GET_METHOD: default: return 200; } @@ -1240,7 +1252,7 @@ private Object extractOriginalValue(Object v) { return v; } - private interface HttpCall { + protected interface HttpCall { HttpResponse execute(String fullUrl, HttpHeader fullHeader); } diff --git a/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResource.java b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResource.java new file mode 100644 index 000000000..4a18dd532 --- /dev/null +++ b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResource.java @@ -0,0 +1,200 @@ +/* + * Copyright 2021 webtau maintainers + * + * 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 org.testingisdocumenting.webtau.http; + +import org.testingisdocumenting.webtau.console.ConsoleOutput; +import org.testingisdocumenting.webtau.data.traceable.TraceableValue; +import org.testingisdocumenting.webtau.expectation.ActualPath; +import org.testingisdocumenting.webtau.http.datanode.DataNode; +import org.testingisdocumenting.webtau.http.datanode.DataNodeId; +import org.testingisdocumenting.webtau.http.validation.HttpValidationResult; +import org.testingisdocumenting.webtau.reporter.StepReportOptions; +import org.testingisdocumenting.webtau.reporter.TokenizedMessage; +import org.testingisdocumenting.webtau.reporter.WebTauStep; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; + +import static org.testingisdocumenting.webtau.http.Http.*; + +public class HttpResource implements DataNode { + private final String givenUrl; + private final ThreadLocal lastResponse = ThreadLocal.withInitial(() -> null); + + public HttpResource(String givenUrl) { + this.givenUrl = givenUrl; + } + + @Override + public TokenizedMessage describe() { + updateResponseIfRequired(); + return getLastResponse().describe(); + } + + @Override + public DataNodeId id() { + updateResponseIfRequired(); + return getLastResponse().id(); + } + + @Override + public DataNode get(String pathOrName) { + updateResponseIfRequired(); + return getLastResponse().get(pathOrName); + } + + @Override + public boolean has(String pathOrName) { + updateResponseIfRequired(); + return getLastResponse().has(pathOrName); + } + + @Override + public DataNode get(int idx) { + updateResponseIfRequired(); + return getLastResponse().get(idx); + } + + @Override + public TraceableValue getTraceableValue() { + updateResponseIfRequired(); + return getLastResponse().getTraceableValue(); + } + + @Override + public E get() { + updateResponseIfRequired(); + return getLastResponse().get(); + } + + @Override + public boolean isList() { + updateResponseIfRequired(); + return getLastResponse().isList(); + } + + @Override + public boolean isSingleValue() { + updateResponseIfRequired(); + return getLastResponse().isSingleValue(); + } + + @Override + public List elements() { + updateResponseIfRequired(); + return getLastResponse().elements(); + } + + @Override + public Collection children() { + updateResponseIfRequired(); + return getLastResponse().children(); + } + + @Override + public int numberOfChildren() { + updateResponseIfRequired(); + return getLastResponse().numberOfChildren(); + } + + @Override + public int numberOfElements() { + updateResponseIfRequired(); + return getLastResponse().numberOfElements(); + } + + @Override + public boolean isNull() { + updateResponseIfRequired(); + return getLastResponse().isNull(); + } + + @Override + public boolean isBinary() { + updateResponseIfRequired(); + return getLastResponse().isBinary(); + } + + @Override + public ActualPath actualPath() { + updateResponseIfRequired(); + return getLastResponse().actualPath(); + } + + @Override + public int compareTo(Object rhv) { + updateResponseIfRequired(); + return getLastResponse().compareTo(rhv); + } + + @Override + public void prettyPrint(ConsoleOutput console) { + updateResponseIfRequired(); + getLastResponse().prettyPrint(console); + } + + @Override + public Iterator iterator() { + updateResponseIfRequired(); + return getLastResponse().iterator(); + } + + @Override + public void forEach(Consumer action) { + updateResponseIfRequired(); + getLastResponse().forEach(action); + } + + @Override + public Spliterator spliterator() { + updateResponseIfRequired(); + return getLastResponse().spliterator(); + } + + /** + * issue HTTP get for the resource to get up to date response, + * by default resource is read once and caches the response + * @return this resource + */ + public HttpResource reRead() { + lastResponse.set(read()); + return this; + } + + private DataNode getLastResponse() { + return lastResponse.get(); + } + + private void updateResponseIfRequired() { + if (lastResponse.get() != null) { + return; + } + + reRead(); + } + + private HttpResourceResponse read() { + HttpValidationResult validationResult = http.createValidationResult(GET_METHOD, givenUrl, HttpHeader.EMPTY, null); + WebTauStep step = http.createHttpStep(validationResult, http::getToFullUrl, (header, body) -> null); + + step.execute(StepReportOptions.REPORT_ALL); + return new HttpResourceResponse(givenUrl, GET_METHOD, validationResult.getBodyNode()); + } +} diff --git a/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResourceResponse.java b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResourceResponse.java new file mode 100644 index 000000000..78295c91c --- /dev/null +++ b/webtau-http/src/main/java/org/testingisdocumenting/webtau/http/HttpResourceResponse.java @@ -0,0 +1,141 @@ +/* + * Copyright 2021 webtau maintainers + * + * 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 org.testingisdocumenting.webtau.http; + +import org.testingisdocumenting.webtau.console.ConsoleOutput; +import org.testingisdocumenting.webtau.data.traceable.TraceableValue; +import org.testingisdocumenting.webtau.expectation.ActualPath; +import org.testingisdocumenting.webtau.http.datanode.DataNode; +import org.testingisdocumenting.webtau.http.datanode.DataNodeId; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class HttpResourceResponse implements DataNode { + private final String givenUrl; + private final String method; + private final DataNode lastResponse; + + public HttpResourceResponse(String givenUrl, String method, DataNode lastResponse) { + this.givenUrl = givenUrl; + this.method = method; + this.lastResponse = lastResponse; + } + + @Override + public DataNodeId id() { + return lastResponse.id(); + } + + @Override + public DataNode get(String pathOrName) { + return lastResponse.get(pathOrName); + } + + @Override + public boolean has(String pathOrName) { + return lastResponse.has(pathOrName); + } + + @Override + public DataNode get(int idx) { + return lastResponse.get(idx); + } + + @Override + public TraceableValue getTraceableValue() { + return lastResponse.getTraceableValue(); + } + + @Override + public E get() { + return lastResponse.get(); + } + + @Override + public boolean isList() { + return lastResponse.isList(); + } + + @Override + public boolean isSingleValue() { + return lastResponse.isSingleValue(); + } + + @Override + public List elements() { + return lastResponse.elements(); + } + + @Override + public Collection children() { + return lastResponse.children(); + } + + @Override + public int numberOfChildren() { + return lastResponse.numberOfChildren(); + } + + @Override + public int numberOfElements() { + return lastResponse.numberOfElements(); + } + + @Override + public boolean isNull() { + return lastResponse.isNull(); + } + + @Override + public boolean isBinary() { + return lastResponse.isBinary(); + } + + @Override + public ActualPath actualPath() { + return lastResponse.actualPath(); + } + + @Override + public int compareTo(Object rhv) { + return lastResponse.compareTo(rhv); + } + + @Override + public void prettyPrint(ConsoleOutput console) { + lastResponse.prettyPrint(console); + } + + @Override + public Iterator iterator() { + return lastResponse.iterator(); + } + + @Override + public void forEach(Consumer action) { + lastResponse.forEach(action); + } + + @Override + public Spliterator spliterator() { + return lastResponse.spliterator(); + } +} diff --git a/webtau-http/src/test/java/org/testingisdocumenting/webtau/http/HttpResourceJavaTest.java b/webtau-http/src/test/java/org/testingisdocumenting/webtau/http/HttpResourceJavaTest.java new file mode 100644 index 000000000..457139baa --- /dev/null +++ b/webtau-http/src/test/java/org/testingisdocumenting/webtau/http/HttpResourceJavaTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 webtau maintainers + * + * 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 org.testingisdocumenting.webtau.http; + +import org.junit.Test; + +import static org.testingisdocumenting.webtau.Matchers.*; +import static org.testingisdocumenting.webtau.http.Http.*; + +public class HttpResourceJavaTest extends HttpTestBase { + @Test + public void shouldReadResource() { + HttpResource resource = http.resource("/end-point-simple-object"); + + resource.get("id").should(equal("id1")); + resource.get("k1").should(equal("v1")); + resource.reRead().get("k2").should(equal("v2")); + } + + @Test + public void shouldWaitOnResourceValue() { + HttpResource resource = http.resource("/end-point-simple-object"); + + resource.get("id").waitTo(equal("id2")); + resource.get("k2").should(equal("v2")); + } + + // TODO implicit statusCode check may not make sense here +} \ No newline at end of file