diff --git a/README.md b/README.md index f135d0e..fd12acd 100644 --- a/README.md +++ b/README.md @@ -732,6 +732,54 @@ This provides complete transparency into test flow and helps debug failures quic --- +## HTTP Request Reporting + +The Testomat HTTP filter integrates with RestAssured and automatically reports HTTP requests as test steps. + +Each request is displayed as a parent step with detailed substeps containing: + +- HTTP method +- URL +- Status code +- Request duration +- Request headers +- Response headers +- Request body +- Response body + +### Basic usage + +```java +given() + .filter(TestomatHttpFilter.create()) + .when() + .get("/users"); +``` + +### Custom configuration + +```java +given() + .filter( + TestomatHttpFilter.builder() + .headers(false) + .requestBody(false) + .onlyFailures(true) + .build() + ); +``` + +### Available options + +| Option | Description | Default | +| -------------- | ------------------------------------------------- | ------- | +| `headers` | Include request and response headers | `true` | +| `requestBody` | Include request body | `true` | +| `responseBody` | Include response body | `true` | +| `onlyFailures` | Report only requests with HTTP status code >= 400 | `false` | + +--- + ## Test Filtering by ID **JUnit & TestNG only** diff --git a/java-reporter-core/dependency-reduced-pom.xml b/java-reporter-core/dependency-reduced-pom.xml index c04e42d..d848085 100644 --- a/java-reporter-core/dependency-reduced-pom.xml +++ b/java-reporter-core/dependency-reduced-pom.xml @@ -1,10 +1,10 @@ 4.0.0 - coretest + io.testomat java-reporter-core Testomat.io Reporter Core - coretest + 0.13.1 Core functionality for Testomat.io Java test reporting library https://github.com/testomatio/java-reporter @@ -271,6 +271,12 @@ + + io.rest-assured + rest-assured + 5.5.7 + provided + diff --git a/java-reporter-core/pom.xml b/java-reporter-core/pom.xml index e1e1bcd..6205781 100644 --- a/java-reporter-core/pom.xml +++ b/java-reporter-core/pom.xml @@ -7,7 +7,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 jar Testomat.io Reporter Core @@ -110,6 +110,12 @@ 2.22.0 compile + + io.rest-assured + rest-assured + 5.5.7 + provided + diff --git a/java-reporter-core/src/main/java/io/testomat/core/constants/CommonConstants.java b/java-reporter-core/src/main/java/io/testomat/core/constants/CommonConstants.java index 95b07d1..912ba3c 100644 --- a/java-reporter-core/src/main/java/io/testomat/core/constants/CommonConstants.java +++ b/java-reporter-core/src/main/java/io/testomat/core/constants/CommonConstants.java @@ -1,7 +1,7 @@ package io.testomat.core.constants; public class CommonConstants { - public static final String REPORTER_VERSION = "0.15.0"; + public static final String REPORTER_VERSION = "0.16.0"; public static final String TESTS_STRING = "tests"; public static final String API_KEY_STRING = "api_key"; diff --git a/java-reporter-core/src/main/java/io/testomat/core/facade/Testomatio.java b/java-reporter-core/src/main/java/io/testomat/core/facade/Testomatio.java index 9a3b76b..357b909 100644 --- a/java-reporter-core/src/main/java/io/testomat/core/facade/Testomatio.java +++ b/java-reporter-core/src/main/java/io/testomat/core/facade/Testomatio.java @@ -79,6 +79,10 @@ public static void step(String stepName, Runnable action) { } } + static void step(String stepName, String passedLog, Runnable action) { + + } + public static void meta(String key, String value) { MetaStorage.TEMP_META_STORAGE.get().put(key, value); } diff --git a/java-reporter-core/src/main/java/io/testomat/core/facade/methods/artifact/client/AwsService.java b/java-reporter-core/src/main/java/io/testomat/core/facade/methods/artifact/client/AwsService.java index 9907a8c..75bba1b 100644 --- a/java-reporter-core/src/main/java/io/testomat/core/facade/methods/artifact/client/AwsService.java +++ b/java-reporter-core/src/main/java/io/testomat/core/facade/methods/artifact/client/AwsService.java @@ -18,6 +18,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -74,7 +75,11 @@ public AwsService(ArtifactKeyGenerator keyGenerator, AwsClient awsClient, public void uploadAllArtifactsForTest(String testName, String rid, String testId) { List artifactDirectories = TempArtifactDirectoriesStorage.DIRECTORIES.get(); - Map stepArtifactDirectories = TempArtifactDirectoriesStorage.STEP_DATA.get(Thread.currentThread().getId()); + Map stepArtifactDirectories = + TempArtifactDirectoriesStorage.STEP_DATA.getOrDefault( + Thread.currentThread().getId(), + Collections.emptyMap()) + ; if (artifactDirectories.isEmpty() && stepArtifactDirectories.isEmpty()) { log.debug("Artifact list is empty for test: {}", testName); diff --git a/java-reporter-core/src/main/java/io/testomat/core/restassured/TestomatHttpFilter.java b/java-reporter-core/src/main/java/io/testomat/core/restassured/TestomatHttpFilter.java new file mode 100644 index 0000000..88b3cdd --- /dev/null +++ b/java-reporter-core/src/main/java/io/testomat/core/restassured/TestomatHttpFilter.java @@ -0,0 +1,166 @@ +package io.testomat.core.restassured; + +import io.restassured.filter.Filter; +import io.restassured.filter.FilterContext; +import io.restassured.response.Response; +import io.restassured.specification.FilterableRequestSpecification; +import io.restassured.specification.FilterableResponseSpecification; +import io.testomat.core.facade.Testomatio; +import io.testomat.core.step.StepLifecycle; +import io.testomat.core.step.TestStep; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestomatHttpFilter implements Filter { + private static final Logger log = LoggerFactory.getLogger(TestomatHttpFilter.class); + + private final boolean requestBody; + private final boolean responseBody; + private final boolean headers; + private final boolean onlyFailures; + + /** + * Creates filter with default settings. + */ + public static TestomatHttpFilter create() { + return new Builder().build(); + } + + /** + * Creates builder for custom configuration. + */ + public static Builder builder() { + return new Builder(); + } + + private TestomatHttpFilter(Builder builder) { + this.requestBody = builder.requestBody; + this.responseBody = builder.responseBody; + this.headers = builder.headers; + this.onlyFailures = builder.onlyFailures; + } + + @Override + public Response filter( + FilterableRequestSpecification request, + FilterableResponseSpecification responseSpec, + FilterContext ctx) { + + long startTime = System.currentTimeMillis(); + + Response response = ctx.next(request, responseSpec); + + long duration = System.currentTimeMillis() - startTime; + + if (onlyFailures && response.statusCode() < 400) { + return response; + } + + TestStep testStep = new TestStep(); + testStep.setCategory("user"); + StepLifecycle.start(testStep); + + String summary = buildSummary( + request, + response, + duration + ); + + reportHttpData("Method: " + request.getMethod(), null); + reportHttpData("URL: " + request.getURI(), null); + reportHttpData("Status: " + response.statusCode(), null); + reportHttpData("Duration: " + duration + " ms", null); + + if (headers) { + reportHttpData("Request headers", request.getHeaders().toString()); + reportHttpData("Response headers", response.getHeaders().toString()); + } + + if (requestBody) { + reportHttpData("Request body", + request.getBody() == null ? "" : request.getBody().toString()); + } + + if (responseBody) { + reportHttpData("Response body", response.getBody().asPrettyString()); + } + + testStep.setStepTitle(summary); + StepLifecycle.finish(); + + return response; + } + + private String buildSummary(FilterableRequestSpecification request, Response response, long duration) { + String path = URI.create(request.getURI()).getPath(); + + return String.format("%s %s → %d (%d ms)", + request.getMethod(), + path, + response.statusCode(), + duration + ); + } + + public static final class Builder { + + private boolean requestBody = true; + private boolean responseBody = true; + private boolean headers = true; + private boolean onlyFailures = false; + + private Builder() { + } + + public Builder requestBody(boolean requestBody) { + this.requestBody = requestBody; + return this; + } + + public Builder responseBody(boolean responseBody) { + this.responseBody = responseBody; + return this; + } + + public Builder headers(boolean headers) { + this.headers = headers; + return this; + } + + public Builder onlyFailures(boolean onlyFailures) { + this.onlyFailures = onlyFailures; + return this; + } + + public TestomatHttpFilter build() { + return new TestomatHttpFilter(this); + } + } + + private void reportHttpData(String summary, String details) { + TestStep testStep = new TestStep(); + testStep.setCategory("user"); + StepLifecycle.start(testStep); + testStep.setStepTitle(summary); + + try { + if (details != null && !details.isBlank()) { + Path dir = Paths.get("target", "testomat", "http"); + Files.createDirectories(dir); + Path json = Files.createTempFile(dir, "http-", ".json"); + Files.writeString(json, details, StandardCharsets.UTF_8); + Testomatio.stepArtifact(json.toString()); + } + } catch (IOException e) { + log.error("Failed to create HTTP attachment", e); + } finally { + StepLifecycle.finish(); + } + } +} \ No newline at end of file diff --git a/java-reporter-cucumber/pom.xml b/java-reporter-cucumber/pom.xml index 024e447..8102bcb 100644 --- a/java-reporter-cucumber/pom.xml +++ b/java-reporter-cucumber/pom.xml @@ -6,7 +6,7 @@ io.testomat java-reporter-cucumber - 0.8.0 + 0.8.1 jar Testomat.io Java Reporter Cucumber @@ -51,7 +51,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 org.slf4j diff --git a/java-reporter-junit/pom.xml b/java-reporter-junit/pom.xml index 85ffad2..fa8b659 100644 --- a/java-reporter-junit/pom.xml +++ b/java-reporter-junit/pom.xml @@ -6,7 +6,7 @@ io.testomat java-reporter-junit - 0.9.0 + 0.9.1 jar Testomat.io Java Reporter JUnit @@ -51,7 +51,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 org.slf4j diff --git a/java-reporter-karate/pom.xml b/java-reporter-karate/pom.xml index 3d145ae..07d8d84 100644 --- a/java-reporter-karate/pom.xml +++ b/java-reporter-karate/pom.xml @@ -6,7 +6,7 @@ io.testomat java-reporter-karate - 0.3.0 + 0.3.1 jar Testomat.io Java Reporter Karate @@ -52,7 +52,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 io.karatelabs diff --git a/java-reporter-testng/pom.xml b/java-reporter-testng/pom.xml index 9fb9d6d..e5b9055 100644 --- a/java-reporter-testng/pom.xml +++ b/java-reporter-testng/pom.xml @@ -6,7 +6,7 @@ io.testomat java-reporter-testng - 0.8.0 + 0.8.1 jar Testomat.io Java Reporter TestNG @@ -47,7 +47,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 org.slf4j diff --git a/testomat-allure-adapter/pom.xml b/testomat-allure-adapter/pom.xml index 036aca9..bf8672d 100644 --- a/testomat-allure-adapter/pom.xml +++ b/testomat-allure-adapter/pom.xml @@ -6,7 +6,7 @@ io.testomat testomat-allure-adapter - 0.1.1 + 0.1.2 jar Testomat.io Testomat Allure adapter @@ -67,7 +67,7 @@ io.testomat java-reporter-core - 0.15.0 + 0.16.0 io.qameta.allure