From dfc1c1507b4ea9ce89f9d2a5d00de09b80bcc034 Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Sat, 29 Jun 2024 22:54:12 +1200 Subject: [PATCH 1/2] Update rest driver flow --- .../samples/github/GithubRepoPage.java | 7 +- .../github/GithubRepoPullRequestPage.java | 6 +- .../samples/mozilla/MozillaHomepage.java | 4 +- .../samples/mozilla/MozillaManifestopage.java | 4 +- .../melinoe/samples/standard/ApiTest.java | 43 ++++- .../samples/standard/FailingTests.java | 3 +- .../melinoe/samples/standard/MozillaTest.java | 5 +- .../melinoe/framework/api/Validator.java | 11 ++ .../framework/api/rest/HttpRequest.java | 30 +++- .../framework/api/rest/HttpResult.java | 6 - .../api/rest/validation/RestValidator.java | 3 +- .../api/web/validation/TitleValidator.java | 38 ----- .../api/web/validation/WebValidator.java | 26 ++- .../framework/internal/Configuration.java | 33 +++- .../internal/rest/HttpRequestImpl.java | 155 +++++++++++------- .../internal/rest/HttpResultImpl.java | 100 +++-------- .../internal/verify/VerificationUtils.java | 45 +++++ .../framework/internal/web/WebDriverImpl.java | 31 +--- 18 files changed, 297 insertions(+), 253 deletions(-) create mode 100644 framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/Validator.java delete mode 100644 framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/TitleValidator.java diff --git a/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPage.java b/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPage.java index 6d5f9af..6e6a209 100644 --- a/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPage.java +++ b/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPage.java @@ -2,14 +2,13 @@ import nz.geek.goodwin.melinoe.framework.api.Session; import nz.geek.goodwin.melinoe.framework.api.web.BasePage; -import nz.geek.goodwin.melinoe.framework.api.web.By; import nz.geek.goodwin.melinoe.framework.api.web.FindElement; import nz.geek.goodwin.melinoe.framework.api.web.WebElement; -import nz.geek.goodwin.melinoe.framework.api.web.validation.TitleValidator; -import nz.geek.goodwin.melinoe.framework.api.web.validation.WebElementText; +import nz.geek.goodwin.melinoe.framework.api.web.validation.WebValidator; import java.util.List; import java.util.stream.Collectors; + public class GithubRepoPage extends BasePage { @FindElement(linkText = "Pull requests") private WebElement pullRequestLink; @@ -19,7 +18,7 @@ public class GithubRepoPage extends BasePage { public GithubRepoPage(final Session session) { super(session, - TitleValidator.equals("GitHub - Goodie01/Melinoe: Melinoe is named for the greek mythological figure who is known as a \"bringer of nightmares and madness\", this seems apt for a automated testing framework")); + WebValidator.titleEquals("GitHub - Goodie01/Melinoe: Melinoe is named for the greek mythological figure who is known as a \"bringer of nightmares and madness\", this seems apt for a automated testing framework")); // } diff --git a/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPullRequestPage.java b/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPullRequestPage.java index 7eacad8..e6eb232 100644 --- a/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPullRequestPage.java +++ b/examples/src/main/java/org/goodiemania/melinoe/samples/github/GithubRepoPullRequestPage.java @@ -1,11 +1,11 @@ package org.goodiemania.melinoe.samples.github; -import nz.geek.goodwin.melinoe.framework.api.web.BasePage; import nz.geek.goodwin.melinoe.framework.api.Session; -import nz.geek.goodwin.melinoe.framework.api.web.validation.TitleValidator; +import nz.geek.goodwin.melinoe.framework.api.web.BasePage; +import nz.geek.goodwin.melinoe.framework.api.web.validation.WebValidator; public class GithubRepoPullRequestPage extends BasePage { public GithubRepoPullRequestPage(final Session session) { - super(session, TitleValidator.equals("Pull requests · Goodie01/Melinoe · GitHub")); + super(session, WebValidator.titleEquals("Pull requests · Goodie01/Melinoe · GitHub")); } } diff --git a/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaHomepage.java b/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaHomepage.java index 0360f34..da496cb 100644 --- a/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaHomepage.java +++ b/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaHomepage.java @@ -4,7 +4,7 @@ import nz.geek.goodwin.melinoe.framework.api.web.BasePage; import nz.geek.goodwin.melinoe.framework.api.web.FindElement; import nz.geek.goodwin.melinoe.framework.api.web.WebElement; -import nz.geek.goodwin.melinoe.framework.api.web.validation.TitleValidator; +import nz.geek.goodwin.melinoe.framework.api.web.validation.WebValidator; /** * @author Goodie @@ -14,7 +14,7 @@ public class MozillaHomepage extends BasePage { private WebElement manifestoLink; public MozillaHomepage(Session session) { - super(session, TitleValidator.equals("Internet for people, not profit — Mozilla (US)")); + super(session, WebValidator.titleEquals("Internet for people, not profit — Mozilla (US)")); } public void clickManifestoLink() { diff --git a/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaManifestopage.java b/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaManifestopage.java index fc35b0e..3ba95fa 100644 --- a/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaManifestopage.java +++ b/examples/src/main/java/org/goodiemania/melinoe/samples/mozilla/MozillaManifestopage.java @@ -5,8 +5,8 @@ import nz.geek.goodwin.melinoe.framework.api.web.By; import nz.geek.goodwin.melinoe.framework.api.web.FindElement; import nz.geek.goodwin.melinoe.framework.api.web.WebElement; -import nz.geek.goodwin.melinoe.framework.api.web.validation.TitleValidator; import nz.geek.goodwin.melinoe.framework.api.web.validation.WebElementText; +import nz.geek.goodwin.melinoe.framework.api.web.validation.WebValidator; /** * @author Goodie @@ -16,7 +16,7 @@ public class MozillaManifestopage extends BasePage { private WebElement manifestoSubTitle; public MozillaManifestopage(Session session) { - super(session, TitleValidator.equals("The Mozilla Manifesto"), + super(session, WebValidator.titleEquals("The Mozilla Manifesto"), WebElementText.equals(By.cssSelector(".addendum-subtitle"), "Pledge for a Healthy Internet")); } diff --git a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/ApiTest.java b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/ApiTest.java index 2880f43..08f98bc 100644 --- a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/ApiTest.java +++ b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/ApiTest.java @@ -1,9 +1,9 @@ package org.goodiemania.melinoe.samples.standard; +import com.fasterxml.jackson.annotation.JsonProperty; import nz.geek.goodwin.melinoe.framework.api.Session; import nz.geek.goodwin.melinoe.framework.api.rest.validation.RestValidator; import nz.geek.goodwin.melinoe.framework.internal.MelinoeExtension; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -20,7 +20,44 @@ public void run() { session = Session.create(); session.rest().get("https://1.1.1.1/dns-query?name=cloudflare.com") .header("accept", "application/dns-json") - .result() - .verify(List.of(RestValidator.statusCodeEquals(200))); + .verifyAsString(List.of(RestValidator.statusCodeEquals(200))); + + session.rest().get("https://1.1.1.1/dns-query?name=cloudflare.com") + .header("accept", "application/dns-json") + .verify(Root.class, List.of(RestValidator.statusCodeEquals(200))); + + } + + public static class Answer { + public String name; + public int type; + @JsonProperty("TTL") + public int tTL; + public String data; } + + public static class Question { + public String name; + public int type; + } + + public static class Root { + @JsonProperty("Status") + public int status; + @JsonProperty("TC") + public boolean tC; + @JsonProperty("RD") + public boolean rD; + @JsonProperty("RA") + public boolean rA; + @JsonProperty("AD") + public boolean aD; + @JsonProperty("CD") + public boolean cD; + @JsonProperty("Question") + public List question; + @JsonProperty("Answer") + public List answer; + } + } diff --git a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/FailingTests.java b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/FailingTests.java index 092d4b3..c212277 100644 --- a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/FailingTests.java +++ b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/FailingTests.java @@ -14,6 +14,7 @@ public class FailingTests { private Session session; private MozillaHomepage mozillaHomepage; + @Test @DisplayName("Run, checking for a page and being on the wrong page") public void runWithBadTitle() { @@ -26,6 +27,7 @@ public void runWithBadTitle() { mozillaHomepage.checkPage(); } + @Test @DisplayName("Run, dont't validate page") public void runWithOutChecking() { @@ -49,7 +51,6 @@ public void run() { session = Session.create(); session.rest().get("https://1.1.1.1/dns-query?name=cloudflare.com") .header("accept", "application/dns-json") - .result() .verify(List.of(RestValidator.statusCodeEquals(201))); } } diff --git a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/MozillaTest.java b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/MozillaTest.java index 5f57918..9fff004 100644 --- a/examples/src/test/java/org/goodiemania/melinoe/samples/standard/MozillaTest.java +++ b/examples/src/test/java/org/goodiemania/melinoe/samples/standard/MozillaTest.java @@ -4,10 +4,6 @@ import nz.geek.goodwin.melinoe.framework.internal.MelinoeExtension; import org.goodiemania.melinoe.samples.mozilla.MozillaHomepage; import org.goodiemania.melinoe.samples.mozilla.MozillaManifestopage; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,6 +14,7 @@ public class MozillaTest { private MozillaHomepage mozillaHomepage; private MozillaManifestopage mozillaManifestopage; + @Test @DisplayName("Run") public void run() { diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/Validator.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/Validator.java new file mode 100644 index 0000000..36d0fb7 --- /dev/null +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/Validator.java @@ -0,0 +1,11 @@ +package nz.geek.goodwin.melinoe.framework.api; + +import nz.geek.goodwin.melinoe.framework.api.rest.HttpResult; +import nz.geek.goodwin.melinoe.framework.api.web.validation.ValidationResult; + +/** + * @author Goodie + */ +public interface Validator { + ValidationResult validate(final T result); +} diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpRequest.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpRequest.java index 7424b8c..bbee091 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpRequest.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpRequest.java @@ -2,6 +2,11 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import nz.geek.goodwin.melinoe.framework.api.rest.validation.RestValidator; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; /** * @author Goodie @@ -14,12 +19,21 @@ public interface HttpRequest { HttpRequest body(Object objectBody); HttpRequest body(String body); - - HttpResult resultAsString(); - - HttpResult result(); - - HttpResult result(Class tClass); - - HttpResult result(TypeReference typeReference); + HttpResult verifyAsString(List> validators); + HttpResult verify(List> validators); + HttpResult verify(TypeReference tClass, List> validators); + HttpResult verify(Class tClass, List> validators); + + default HttpResult verifyAsString(RestValidator... validators) { + return verifyAsString(List.of(validators)); + } + default HttpResult verify(RestValidator... validators) { + return verify(List.of(validators)); + } + default HttpResult verify(TypeReference tClass, RestValidator... validators) { + return verify(tClass, List.of(validators)); + } + default HttpResult verify(Class tClass, RestValidator... validators) { + return verify(tClass, List.of(validators)); + } } diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpResult.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpResult.java index 5c3baf3..70c4c7c 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpResult.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/HttpResult.java @@ -28,10 +28,4 @@ public interface HttpResult { Map> respHeaders(); T respBody(); - - default HttpResult verify(final RestValidator... validators) { - return verify(Arrays.asList(validators)); - } - - HttpResult verify(List> validators); } diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/validation/RestValidator.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/validation/RestValidator.java index e18dbe8..95f2787 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/validation/RestValidator.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/rest/validation/RestValidator.java @@ -1,12 +1,13 @@ package nz.geek.goodwin.melinoe.framework.api.rest.validation; +import nz.geek.goodwin.melinoe.framework.api.Validator; import nz.geek.goodwin.melinoe.framework.api.rest.HttpResult; import nz.geek.goodwin.melinoe.framework.api.web.validation.ValidationResult; /** * @author Goodie */ -public interface RestValidator { +public interface RestValidator extends Validator> { ValidationResult validate(final HttpResult result); static RestValidator statusCodeEquals(int statusCode) { diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/TitleValidator.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/TitleValidator.java deleted file mode 100644 index 078fec3..0000000 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/TitleValidator.java +++ /dev/null @@ -1,38 +0,0 @@ -package nz.geek.goodwin.melinoe.framework.api.web.validation; - -import nz.geek.goodwin.melinoe.framework.api.web.WebDriver; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.function.ToBooleanBiFunction; - -/** - * Created on 28/06/2019. - */ -public class TitleValidator implements WebValidator { - private final String expectedTitle; - private final ToBooleanBiFunction comparisonType; - - private TitleValidator(final String expectedTitle, ToBooleanBiFunction comparisonType) { - this.expectedTitle = expectedTitle; - this.comparisonType = comparisonType; - } - - public static TitleValidator contains(final String searchText) { - return new TitleValidator(searchText, StringUtils::contains); - } - - public static TitleValidator equals(final String searchText) { - return new TitleValidator(searchText, StringUtils::equals); - } - - @Override - public ValidationResult validate(final WebDriver webDriver) { - String actualTitle = webDriver.getTitle(); - if (comparisonType.applyAsBoolean(actualTitle, expectedTitle)) { - return ValidationResult.passed("Found expected title: " + expectedTitle); - } else { - return ValidationResult.failed("Title is not as expected", - String.format("Expected title: \"%s\"", expectedTitle), - String.format("Actual title: \"%s\"", actualTitle)); - } - } -} diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/WebValidator.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/WebValidator.java index 32c7a6b..f5fa7e2 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/WebValidator.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/api/web/validation/WebValidator.java @@ -1,10 +1,34 @@ package nz.geek.goodwin.melinoe.framework.api.web.validation; +import nz.geek.goodwin.melinoe.framework.api.Validator; import nz.geek.goodwin.melinoe.framework.api.web.WebDriver; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.function.ToBooleanBiFunction; /** * @author Goodie */ -public interface WebValidator { +public interface WebValidator extends Validator { ValidationResult validate(final WebDriver webDriver); + + static WebValidator titleEquals(String title) { + return titleImpl(StringUtils::equals, title); + } + + static WebValidator titleContains(String title) { + return titleImpl(StringUtils::contains, title); + } + + private static WebValidator titleImpl(ToBooleanBiFunction comparisonType, String expectedTitle) { + return webDriver -> { + String actualTitle = webDriver.getTitle(); + if (comparisonType.applyAsBoolean(actualTitle, expectedTitle)) { + return ValidationResult.passed("Found expected title: " + expectedTitle); + } else { + return ValidationResult.failed("Title is not as expected", + String.format("Expected title: \"%s\"", expectedTitle), + String.format("Actual title: \"%s\"", actualTitle)); + } + }; + } } diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/Configuration.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/Configuration.java index 3ffefbf..8251ca2 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/Configuration.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/Configuration.java @@ -11,10 +11,22 @@ public enum Configuration { BROWSER, BROWSER_EXE_LOCATION, - RETRY_COUNT, - RETRY_SLEEP_TIME_MS, + RETRY_COUNT("5"), + RETRY_SLEEP_TIME_MS("100"), ; + private static Properties PROPERTIES; + + private final String defaultValue; + + Configuration() { + this.defaultValue = null; + } + + Configuration(String defaultValue) { + this.defaultValue = defaultValue; + } + private Object valueOf() { String propertyName = this.toString(); String propertyFromSystem = System.getenv(propertyName); @@ -23,15 +35,18 @@ private Object valueOf() { return propertyFromSystem; } - Properties properties = new Properties(); - String propertyFile = System.getProperty("props", "default.properties"); + if(PROPERTIES == null) { + PROPERTIES = new Properties(); + String propertyFile = System.getProperty("props", "default.properties"); - try (FileReader propertiesFileReader = new FileReader(propertyFile)) { - properties.load(propertiesFileReader); - } catch (IOException | NullPointerException e) { - throw new IllegalStateException("Unable to load properties file", e); + try (FileReader propertiesFileReader = new FileReader(propertyFile)) { + PROPERTIES.load(propertiesFileReader); + } catch (IOException | NullPointerException e) { + throw new IllegalStateException("Unable to load properties file", e); + } } - return properties.get(propertyName); + + return PROPERTIES.getProperty(propertyName, defaultValue); } public String val() { return valueOf().toString(); diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpRequestImpl.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpRequestImpl.java index 5bc0e0c..ad77048 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpRequestImpl.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpRequestImpl.java @@ -5,22 +5,26 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import nz.geek.goodwin.melinoe.framework.api.MelinoeException; +import nz.geek.goodwin.melinoe.framework.api.log.LogMessage; import nz.geek.goodwin.melinoe.framework.api.log.Logger; import nz.geek.goodwin.melinoe.framework.api.rest.HttpRequest; import nz.geek.goodwin.melinoe.framework.api.rest.HttpResult; +import nz.geek.goodwin.melinoe.framework.api.rest.validation.RestValidator; +import nz.geek.goodwin.melinoe.framework.internal.verify.VerificationUtils; +import org.apache.commons.lang3.StringUtils; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpResponse; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Flow; import static java.net.URI.create; @@ -92,56 +96,88 @@ public HttpRequest body(String body) { } @Override - public HttpResult resultAsString() { - try { - java.net.http.HttpRequest req = buildHttpRequest(); - HttpResponse resp = client.send(req, HttpResponse.BodyHandlers.ofString()); - - return new HttpResultImpl<>(req, resp, logger); - } catch (Exception e) { - throw new MelinoeException(e); - } + public HttpResult verifyAsString(List> validators) { + return gettHttpResult(s -> s, validators); } @Override - public HttpResult result() { - try { - java.net.http.HttpRequest req = buildHttpRequest(); - HttpResponse resp = client.send(req, new JsonBodyHandler<>(objectMapper::readTree)); + public HttpResult verify(List> validators) { + return gettHttpResult(objectMapper::readTree, validators); + } - return new HttpResultImpl<>(req, resp, logger); - } catch (Exception e) { - throw new MelinoeException(e); - } + @Override + public HttpResult verify(TypeReference typeReference, List> validators) { + return gettHttpResult(s -> objectMapper.readValue(s, typeReference), validators); } @Override - public HttpResult result(Class tClass) { - try { - java.net.http.HttpRequest req = buildHttpRequest(); - HttpResponse resp = client.send(req, new JsonBodyHandler<>(inputStream -> objectMapper.readValue(inputStream, tClass))); + public HttpResult verify(Class tClass, final List> validators) { + return gettHttpResult(s -> objectMapper.readValue(s, tClass), validators); + } - return new HttpResultImpl<>(req, resp, logger); - } catch (Exception e) { - throw new MelinoeException(e); - } + private HttpResult gettHttpResult(Function tSupplier, List> validators) { + java.net.http.HttpRequest req = buildHttpRequest(); + Logger requestSublogger = logger.createSublogger(req.method() + " " + req.uri().getHost() + req.uri().getPath()); + + return VerificationUtils.validate(validators, requestSublogger, () -> { + try { + HttpResponse resp = client.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + T t = tSupplier.apply(resp.body()); + HttpResultImpl result = new HttpResultImpl<>(req, resp, t, logger); + log(requestSublogger, req, resp); + + return result; + } catch (Exception e) { + throw new MelinoeException(e); + } + }); } - @Override - public HttpResult result(TypeReference typeReference) { - try { - java.net.http.HttpRequest req = buildHttpRequest(); - HttpResponse resp = client.send(req, new JsonBodyHandler<>(inputStream -> objectMapper.readValue(inputStream, typeReference))); - return new HttpResultImpl(req, resp, logger); - } catch (Exception e) { - throw new MelinoeException(e); + private String reqBody(java.net.http.HttpRequest req) { + return req.bodyPublisher().map(p -> { + var bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8); + var flowSubscriber = new StringSubscriber(bodySubscriber); + p.subscribe(flowSubscriber); + return bodySubscriber.getBody().toCompletableFuture().join(); + }).orElseThrow(); + } + + private void log(Logger logger, java.net.http.HttpRequest req, HttpResponse resp) { + logger.add().withMessage("Making request"); + LogMessage request = logger.add() + .withMessage("> " + req.method() + " " + req.uri()) + .withMessage("> " + req.version().map(Enum::toString).orElse("Unspecified version")); + + req.headers().map().forEach((name, values) -> values.forEach(value -> { + request.withMessage("> " + name + ": " + value); + })); + + String jsonReq = reqBody(req); + if (StringUtils.isNotBlank(jsonReq)) { + logger.add().withMessage(Prettifier.prettify(jsonReq)); + } + + LogMessage response = logger.add() + .withMessage("< " + resp.version().toString() + " " + resp.statusCode()) + .withMessage("< " + resp.uri()); + + resp.headers().map().forEach((name, values) -> values.forEach(value -> { + response.withMessage("< " + name + ": " + value); + })); + + String jsonResp = StringUtils.trim(resp.body());//TODO handle bodies other than strings better + + if (StringUtils.startsWith(jsonResp, "{")) { + logger.add().withMessage(Prettifier.prettify(jsonResp)); + } else { + logger.add().withMessage(jsonResp); } } private java.net.http.HttpRequest buildHttpRequest() { URI requestUrl = create(url); java.net.http.HttpRequest.BodyPublisher bodyPublisher; - if(body == null) { + if (body == null) { bodyPublisher = java.net.http.HttpRequest.BodyPublishers.noBody(); } else { bodyPublisher = java.net.http.HttpRequest.BodyPublishers.ofString(body); @@ -158,38 +194,35 @@ private java.net.http.HttpRequest buildHttpRequest() { return req.build(); } - //https://stackoverflow.com/questions/57629401/deserializing-json-using-java-11-httpclient-and-custom-bodyhandler-with-jackson - private class JsonBodyHandler implements HttpResponse.BodyHandler { + private static final class StringSubscriber implements Flow.Subscriber { + final HttpResponse.BodySubscriber wrapped; - private final Function function; + StringSubscriber(HttpResponse.BodySubscriber wrapped) { + this.wrapped = wrapped; + } - public JsonBodyHandler(Function function) { - this.function = function; + @Override + public void onSubscribe(Flow.Subscription subscription) { + wrapped.onSubscribe(subscription); } @Override - public HttpResponse.BodySubscriber apply(HttpResponse.ResponseInfo responseInfo) { - return HttpResponse.BodySubscribers.mapping( - HttpResponse.BodySubscribers.ofInputStream(), - inputStream -> { - try (InputStream stream = inputStream) { - return function.apply(stream); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); + public void onNext(ByteBuffer item) { + wrapped.onNext(List.of(item)); } - } + @Override + public void onError(Throwable throwable) { + wrapped.onError(throwable); + } - private interface Function { + @Override + public void onComplete() { + wrapped.onComplete(); + } + } + public interface Function { - /** - * Applies this function to the given argument. - * - * @param t the function argument - * @return the function result - */ - R apply(InputStream t) throws IOException; + R apply(T t) throws Exception; } } diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpResultImpl.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpResultImpl.java index 2038850..6c3087f 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpResultImpl.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/rest/HttpResultImpl.java @@ -25,43 +25,14 @@ public class HttpResultImpl implements HttpResult { private final Logger logger; private final HttpRequest req; - private final HttpResponse resp; - private boolean checked = false; + private final HttpResponse resp; + private final T body; - public HttpResultImpl(HttpRequest req, HttpResponse resp, Logger logger) { + public HttpResultImpl(HttpRequest req, HttpResponse resp, T t, Logger logger) { this.req = req; this.resp = resp; + this.body = t; this.logger = logger; - - Logger requestSublogger = logger.createSublogger(reqMethod() + " " + reqUri().getHost() + reqUri().getPath()); - LogMessage request = requestSublogger.add() - .withMessage("> " + reqMethod() + " " + reqUri()) - .withMessage("> " + req.version().map(Enum::toString).orElse("Unspecified version")); - - reqHeaders().forEach((name, values) -> values.forEach(value -> { - request.withMessage("> " + name + ": " + value); - })); - - String jsonReq = reqBody(); - if(StringUtils.isNotBlank(jsonReq)) { - requestSublogger.add().withMessage(Prettifier.prettify(jsonReq)); - } - - LogMessage response = requestSublogger.add() - .withMessage("< " + resp.version().toString() + " " + respStatus()) - .withMessage("< " + respUri()); - - respHeaders().forEach((name, values) -> values.forEach(value -> { - response.withMessage("< " + name + ": " + value); - })); - - String jsonResp = StringUtils.trim(String.valueOf(getBody()));//TODO handle bodies other than strings better - - if(StringUtils.isNotBlank(jsonResp) && jsonResp.charAt(0) == '{') { - requestSublogger.add().withMessage(Prettifier.prettify(jsonResp)); - } else { - requestSublogger.add().withMessage(jsonResp); - } } @Override @@ -75,8 +46,19 @@ public String reqMethod() { } @Override - public Map> respHeaders() { - return this.resp.headers().map(); + public Map> reqHeaders() { + return this.req.headers().map(); + } + + + @Override + public String reqBody() { + return req.bodyPublisher().map(p -> { + var bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8); + var flowSubscriber = new HttpResultImpl.StringSubscriber(bodySubscriber); + p.subscribe(flowSubscriber); + return bodySubscriber.getBody().toCompletableFuture().join(); + }).orElseThrow(); } @Override @@ -90,55 +72,13 @@ public int respStatus() { } @Override - public Map> reqHeaders() { - return this.req.headers().map(); + public Map> respHeaders() { + return this.resp.headers().map(); } @Override public T respBody() { - if (!checked) { - throw new MelinoeException("Please check run at least one validator before interacting with a Http Result."); - } - return getBody(); - } - - private T getBody() { - return this.resp.body(); - } - - @Override - public HttpResult verify(List> validators) { - Logger verifyingLogger; - if (!checked) { - verifyingLogger = logger.createSublogger("Verifying response"); - } else { - verifyingLogger = logger; - } - - checked = true; - List list = validators.stream() - .map(webValidator -> webValidator.validate(this)) - .toList(); - - list.forEach(validationResult -> { - String messages = validationResult.messages().stream().collect(Collectors.joining(System.lineSeparator())); - verifyingLogger.add().withMessage(messages).withSuccess(validationResult.valid()); - }); - - VerificationUtils.checkVerificationResults(list); - - return this; - } - - - @Override - public String reqBody() { - return req.bodyPublisher().map(p -> { - var bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8); - var flowSubscriber = new HttpResultImpl.StringSubscriber(bodySubscriber); - p.subscribe(flowSubscriber); - return bodySubscriber.getBody().toCompletableFuture().join(); - }).orElseThrow(); + return body; } private static final class StringSubscriber implements Flow.Subscriber { diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/verify/VerificationUtils.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/verify/VerificationUtils.java index ad95220..9289e40 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/verify/VerificationUtils.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/verify/VerificationUtils.java @@ -1,9 +1,15 @@ package nz.geek.goodwin.melinoe.framework.internal.verify; import nz.geek.goodwin.melinoe.framework.api.MelinoeException; +import nz.geek.goodwin.melinoe.framework.api.Validator; +import nz.geek.goodwin.melinoe.framework.api.log.Logger; import nz.geek.goodwin.melinoe.framework.api.web.validation.ValidationResult; +import nz.geek.goodwin.melinoe.framework.internal.Configuration; +import nz.geek.goodwin.melinoe.framework.internal.misc.Sleeper; +import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -13,6 +19,45 @@ public final class VerificationUtils { private VerificationUtils() { } + public static T validate(List> validators, Logger logger, Supplier thingSupplier) { + List results; + int retryCount = 0; + T thing; + + do { + if (retryCount != 0) { + Sleeper.sleep(Configuration.RETRY_SLEEP_TIME_MS.intVal()); + } + + retryCount++; + thing = thingSupplier.get(); + List list = new ArrayList<>(); + for (Validator webValidator : validators) { + list.add(webValidator.validate(thing)); + } + results = list; + } while (results.stream().anyMatch(validationResult -> !validationResult.valid()) && retryCount < Configuration.RETRY_COUNT.intVal()); + + final int tryCount = retryCount; + + results.forEach(validationResult -> { + String messages = validationResult.messages().stream().collect(Collectors.joining(System.lineSeparator())); + logger.add().withMessage(messages).withSuccess(validationResult.valid()); + }); + + if(results.stream().anyMatch(validationResult -> !validationResult.valid())) { + throw new MelinoeException("Verification failed after " + tryCount + " attempts"); + } else if (tryCount != 1){ + logger.add().withMessage("Verification successful after " + tryCount + "attempts"); + } else { + logger.add().withMessage("Verification successful"); + + } + + VerificationUtils.checkVerificationResults(results); + return thing; + } + public static void checkVerificationResults(List list) { if(list.stream().anyMatch(validationResult -> !validationResult.valid())) { var failedVerificationMessages = list.stream() diff --git a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/web/WebDriverImpl.java b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/web/WebDriverImpl.java index 99814dc..c40039d 100644 --- a/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/web/WebDriverImpl.java +++ b/framework/src/main/java/nz/geek/goodwin/melinoe/framework/internal/web/WebDriverImpl.java @@ -152,37 +152,8 @@ public Map cookies() { @Override public void verify(List validators) { - Logger verifyingLogger; - if(!pageCheckStatus.check()) { - verifyingLogger = logger.createSublogger("Verifying page - " + getTitle(), screenshotTaker.takeScreenshot()); - } else { - verifyingLogger = logger; - } - waitFor(webDriver -> remoteWebDriver.executeScript("return document.readyState").equals("complete")); - - List list; - int retryCount = 0; - - do { - retryCount++; - list = validators.stream() - .map(webValidator -> webValidator.validate(this)) - .toList(); - Sleeper.sleep(Configuration.RETRY_SLEEP_TIME_MS.intVal()); - } while (list.stream().anyMatch(validationResult -> !validationResult.valid()) && retryCount < Configuration.RETRY_COUNT.intVal()); - - final int tryCount = retryCount; - - list.forEach(validationResult -> { - String messages = validationResult.messages().stream().collect(Collectors.joining(System.lineSeparator())); - if(tryCount != 1) { - messages = messages + System.lineSeparator() + "Took " + tryCount + " attempts to achieve result"; - } - verifyingLogger.add().withMessage(messages).withSuccess(validationResult.valid()); - }); - - VerificationUtils.checkVerificationResults(list); + VerificationUtils.validate(validators, logger.createSublogger("Verifying page - " + getTitle(), screenshotTaker.takeScreenshot()), () -> this); pageCheckStatus.set(); } } From ae2132ab08d13fd9af155e63d6bce6bd4958c310 Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Sat, 29 Jun 2024 22:54:48 +1200 Subject: [PATCH 2/2] Update version for breaking change --- examples/pom.xml | 4 ++-- framework/pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 6a04a58..7d10656 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ nz.geek.goodwin.melinoe examples - 0.3.4-SNAPSHOT + 0.4.0-SNAPSHOT 21 @@ -35,7 +35,7 @@ nz.geek.goodwin.melinoe framework - 0.3.4-SNAPSHOT + 0.4.0-SNAPSHOT org.junit.jupiter diff --git a/framework/pom.xml b/framework/pom.xml index 9e8622e..e5350dd 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -4,7 +4,7 @@ nz.geek.goodwin.melinoe framework - 0.3.4-SNAPSHOT + 0.4.0-SNAPSHOT 21