From c2e55d30c84a6b99b3155ee8e4dfb365debd6b64 Mon Sep 17 00:00:00 2001 From: Nassim Boutekedjiret Date: Tue, 14 Oct 2025 23:18:30 +0200 Subject: [PATCH 1/4] Add integration tests and remove redundant unit tests for HttpClient - Add GitHub Actions workflow for integration tests - Configure Maven Failsafe Plugin for integration tests - Add integration test profile in `pom.xml` - Implement `HttpClientIT` with various test cases - Use `httpbin` service for testing HTTP client behavior - Update parent POM version to 4 for compatibility - Remove `HttpClientTest` class from the test suite - Remove redundant tests for HTTP methods and status codes - Remove tests for authentication, headers, and encoding handling - Simplify test structure by consolidating integration tests --- .github/workflows/integration-tests.yml | 56 ++++++ pom.xml | 55 +++++- .../org/metricshub/http/HttpClientIT.java} | 162 ++++-------------- 3 files changed, 147 insertions(+), 126 deletions(-) create mode 100644 .github/workflows/integration-tests.yml rename src/{test/java/org/metricshub/http/HttpClientTest.java => it/java/org/metricshub/http/HttpClientIT.java} (69%) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..382bb23 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,56 @@ +name: Integration Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + integration-tests: + name: Run Integration Tests + runs-on: ubuntu-latest + services: + httpbin: + image: kennethreitz/httpbin + ports: + - 31888:80 + options: >- + --health-cmd "curl --fail http://localhost:80/get || exit 1" + --health-interval 5s + --health-retries 5 + --health-timeout 5s + + steps: + + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: "17" + distribution: temurin + cache: maven + + - name: Set up Maven settings.xml + uses: s4u/maven-settings-action@v3.1.0 + with: + sonatypeSnapshots: true + repositories: >- + [ + { + "id": "central-snapshots", + "name": "Maven Repository Switchboard", + "url": "https://central.sonatype.com/repository/maven-snapshots", + "snapshots": { "enabled": true }, + "releases": { "enabled": false } + } + ] + + - name: Run Integration Tests + env: + HTTPBIN_BASE_URL: http://localhost:31888 + run: | + mvn -B verify -Pintegration-tests \ + -Dhttpbin.url=$HTTPBIN_BASE_URL diff --git a/pom.xml b/pom.xml index c0f115b..1efa54d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.metricshub oss-parent - 2 + 4 simple-http-java @@ -218,4 +218,57 @@ + + + integration-tests + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-test-source + generate-test-sources + + add-test-source + + + + src/it/java + + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + integration-test + + integration-test + verify + + + + + 1 + false + + **/*IT.java + + ${project.build.outputDirectory} + false + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/metricshub/http/HttpClientTest.java b/src/it/java/org/metricshub/http/HttpClientIT.java similarity index 69% rename from src/test/java/org/metricshub/http/HttpClientTest.java rename to src/it/java/org/metricshub/http/HttpClientIT.java index e4c68a1..132250f 100644 --- a/src/test/java/org/metricshub/http/HttpClientTest.java +++ b/src/it/java/org/metricshub/http/HttpClientIT.java @@ -16,50 +16,21 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -class HttpClientTest { +class HttpClientIT { /** - * By default, HTTPBIN_URL points to the public instance of httpbin: - * http://httpbin.org - *

- * When running tests, you can set the HTTPBIN_URL environment variable - * to specify another address where httpbin is running. - *

- *

- * Example: - *

- * HTTPBIN_URL=http://httpbin.example.org:8080 + * Get the HTTPBIN_BASE_URL provided by the system property. This must be set + * before running the tests, for example: + * -DHTTPBIN_BASE_URL=https://httpbin.org */ - private static final String HTTPBIN_URL; + private static final String HTTPBIN_BASE_URL; static { - String url = System.getenv("HTTPBIN_URL"); + String url = System.getProperty("HTTPBIN_BASE_URL"); if (url == null || url.isEmpty()) { - url = "http://httpbin.org"; + throw new IllegalStateException("HTTPBIN_BASE_URL system property must be set"); } - HTTPBIN_URL = url; - } - - /** - * By default, HTTPBIN_SSL_URL points to the public instance of httpbin: - * https://httpbin.org - *

- * When running tests, you can set the HTTPBIN_SSL_URL environment variable - * to specify another address where httpbin is running. - *

- *

- * Example: - *

- * HTTPBIN_URL=https://httpbin.example.org:8082 - */ - private static final String HTTPBIN_SSL_URL; - - static { - String url = System.getenv("HTTPBIN_SSL_URL"); - if (url == null || url.isEmpty()) { - url = "https://httpbin.org"; - } - HTTPBIN_SSL_URL = url; + HTTPBIN_BASE_URL = url; } @ParameterizedTest @@ -111,9 +82,9 @@ class HttpClientTest { 524 } ) - void statusCode(int status) throws Exception { + void testStatusCode(int status) throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/status/" + status, + HTTPBIN_BASE_URL + "/status/" + status, "GET", null, null, @@ -132,70 +103,11 @@ void statusCode(int status) throws Exception { assertEquals(status, r.getStatusCode(), "Must return status " + status); } - @Test - void https() throws Exception { - HttpResponse r = HttpClient.sendRequest( - HTTPBIN_SSL_URL + "/status/200", - "GET", - null, - null, - null, - null, - 0, - null, - null, - null, - null, - null, - 30, - null - ); - assertEquals(200, r.getStatusCode(), "Default https must work"); - - r = - HttpClient.sendRequest( - HTTPBIN_SSL_URL + "/status/200", - "GET", - new String[] { "TLSv1.2" }, - null, - null, - null, - 0, - null, - null, - null, - null, - null, - 30, - null - ); - assertEquals(200, r.getStatusCode(), "TLSv1.2 only must work"); - - r = - HttpClient.sendRequest( - HTTPBIN_SSL_URL + "/status/200", - "GET", - new String[] { "SSLv2Hello" }, - null, - null, - null, - 0, - null, - null, - null, - null, - null, - 30, - null - ); - assertEquals(200, r.getStatusCode(), "Specifying SSLv2Hello must not break communication"); - } - @ParameterizedTest @ValueSource(strings = { "GET", "DELETE", "POST", "PUT" }) - void method(String method) throws Exception { + void testMethod(String method) throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/" + method.toLowerCase(), + HTTPBIN_BASE_URL + "/" + method.toLowerCase(), method, null, null, @@ -215,9 +127,9 @@ void method(String method) throws Exception { } @Test - void basicAuth() throws Exception { + void testBasicAuth() throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/basic-auth/mypasswordis/password", + HTTPBIN_BASE_URL + "/basic-auth/mypasswordis/password", "GET", null, "mypasswordis", @@ -236,9 +148,9 @@ void basicAuth() throws Exception { } @Test - void basicAuthFail() throws Exception { + void testBasicAuthFail() throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/basic-auth/mypasswordis/notpassword", + HTTPBIN_BASE_URL + "/basic-auth/mypasswordis/notpassword", "GET", null, "mypasswordis", @@ -257,9 +169,9 @@ void basicAuthFail() throws Exception { } @Test - void digestAuth() throws Exception { + void testDigestAuth() throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/digest-auth/auth/mypasswordis/password", + HTTPBIN_BASE_URL + "/digest-auth/auth/mypasswordis/password", "GET", null, "mypasswordis", @@ -278,9 +190,9 @@ void digestAuth() throws Exception { } @Test - void userAgent() throws Exception { + void testUserAgent() throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/user-agent", + HTTPBIN_BASE_URL + "/user-agent", "GET", null, null, @@ -299,9 +211,9 @@ void userAgent() throws Exception { } @Test - void userAgentDefault() throws Exception { + void testUserAgentDefault() throws Exception { HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/user-agent", + HTTPBIN_BASE_URL + "/user-agent", "GET", null, null, @@ -320,12 +232,12 @@ void userAgentDefault() throws Exception { } @Test - void headers() throws Exception { + void testHeaders() throws Exception { Map headers = new HashMap(); headers.put("first", "1"); headers.put("second", "1 + 1"); HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/headers", + HTTPBIN_BASE_URL + "/headers", "GET", null, null, @@ -345,11 +257,11 @@ void headers() throws Exception { } @Test - void deflate() throws Exception { + void testDeflate() throws Exception { Map headers = new HashMap(); headers.put("Accept-Encoding", "deflate"); HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/deflate", + HTTPBIN_BASE_URL + "/deflate", "GET", null, null, @@ -372,11 +284,11 @@ void deflate() throws Exception { } @Test - void gzip() throws Exception { + void testGzip() throws Exception { Map headers = new HashMap(); headers.put("Accept-Encoding", "gzip"); HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/gzip", + HTTPBIN_BASE_URL + "/gzip", "GET", null, null, @@ -399,11 +311,11 @@ void gzip() throws Exception { } @Test - void postBody() throws Exception { + void testPostBody() throws Exception { Map headers = new HashMap(); headers.put("Content-type", "text/plain"); HttpResponse r = HttpClient.sendRequest( - HTTPBIN_URL + "/anything", + HTTPBIN_BASE_URL + "/anything", "POST", null, null, @@ -422,12 +334,12 @@ void postBody() throws Exception { } @Test - void timeoutException() throws Exception { + void testTimeoutException() throws Exception { assertThrows( IOException.class, () -> HttpClient.sendRequest( - HTTPBIN_URL + "/delay/9", + HTTPBIN_BASE_URL + "/delay/9", "GET", null, null, @@ -447,13 +359,13 @@ void timeoutException() throws Exception { } @Test - void timeout() throws Exception { + void testTimeout() throws Exception { assertTimeout( Duration.ofSeconds(5), () -> { try { HttpClient.sendRequest( - HTTPBIN_URL + "/delay/9", + HTTPBIN_BASE_URL + "/delay/9", "GET", null, null, @@ -475,7 +387,7 @@ void timeout() throws Exception { } @Test - void utf8() throws Exception { + void testUtf8() throws Exception { HttpResponse r = HttpClient.sendRequest( "https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt", "GET", @@ -496,7 +408,7 @@ void utf8() throws Exception { } @Test - void downloadTo() throws Exception { + void testDownloadTo() throws Exception { Path tempPath = Files.createTempFile("test-download", ".txt"); tempPath.toFile().deleteOnExit(); HttpResponse r = HttpClient.sendRequest( @@ -521,7 +433,7 @@ void downloadTo() throws Exception { } @Test - void downloadToDirectory() throws Exception { + void testDownloadToDirectory() throws Exception { Path tempDirPath = Files.createTempDirectory("testDownloadToDirectory"); tempDirPath.toFile().deleteOnExit(); HttpResponse r = HttpClient.sendRequest( From eba416dff61934bc4da45a127e77407a1c507b7a Mon Sep 17 00:00:00 2001 From: Nassim Boutekedjiret Date: Tue, 14 Oct 2025 23:24:30 +0200 Subject: [PATCH 2/4] Replace Docker health checks with a custom readiness check for httpbin - Removed Docker health check options for httpbin service - Added a script to wait for httpbin readiness using curl - Retries readiness check up to 10 times with a 3-second interval - Outputs readiness status or failure message to stderr - Ensures httpbin is ready before proceeding with tests --- .github/workflows/integration-tests.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 382bb23..3de19d6 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -15,14 +15,21 @@ jobs: image: kennethreitz/httpbin ports: - 31888:80 - options: >- - --health-cmd "curl --fail http://localhost:80/get || exit 1" - --health-interval 5s - --health-retries 5 - --health-timeout 5s - steps: + - name: Wait for httpbin to be ready + run: | + for i in {1..10}; do + if curl -sSf http://localhost:31888/get >/dev/null; then + echo "httpbin is ready!" + exit 0 + fi + echo "Waiting for httpbin..." + sleep 3 + done + echo "httpbin did not start in time" >&2 + exit 1 + - name: Checkout Repository uses: actions/checkout@v4 From db907c58e549b87bed66dbcf31a2658646fe6754 Mon Sep 17 00:00:00 2001 From: Nassim Boutekedjiret Date: Tue, 14 Oct 2025 23:27:02 +0200 Subject: [PATCH 3/4] Update system property key for HTTPBIN_BASE_URL to `httpbin.url` - Renamed system property `HTTPBIN_BASE_URL` to `httpbin.url` - Updated example usage in the class documentation - Adjusted error message to reflect the new property name - Ensured backward-incompatible change is documented in code --- src/it/java/org/metricshub/http/HttpClientIT.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/it/java/org/metricshub/http/HttpClientIT.java b/src/it/java/org/metricshub/http/HttpClientIT.java index 132250f..10d9792 100644 --- a/src/it/java/org/metricshub/http/HttpClientIT.java +++ b/src/it/java/org/metricshub/http/HttpClientIT.java @@ -21,14 +21,14 @@ class HttpClientIT { /** * Get the HTTPBIN_BASE_URL provided by the system property. This must be set * before running the tests, for example: - * -DHTTPBIN_BASE_URL=https://httpbin.org + * -Dhttpbin.url=https://httpbin.org */ private static final String HTTPBIN_BASE_URL; static { - String url = System.getProperty("HTTPBIN_BASE_URL"); + String url = System.getProperty("httpbin.url"); if (url == null || url.isEmpty()) { - throw new IllegalStateException("HTTPBIN_BASE_URL system property must be set"); + throw new IllegalStateException("httpbin.url system property must be set"); } HTTPBIN_BASE_URL = url; } From 944d12ee7f1c2ded56e0b598703c56c3d489b29d Mon Sep 17 00:00:00 2001 From: Nassim Boutekedjiret Date: Tue, 14 Oct 2025 23:34:30 +0200 Subject: [PATCH 4/4] Add JVM arguments to export internal Java modules for plugin compatibility - Updated `pom.xml` to include `argLine` configuration - Exported `java.base/sun.net.www.protocol.http` module - Exported `java.base/sun.security.ssl` module - Ensured compatibility with internal Java modules - Aimed to resolve runtime issues with specific plugins --- .github/workflows/integration-tests.yml | 2 +- pom.xml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 3de19d6..7c1ad6b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -59,5 +59,5 @@ jobs: env: HTTPBIN_BASE_URL: http://localhost:31888 run: | - mvn -B verify -Pintegration-tests \ + mvn clean -B verify -Pintegration-tests \ -Dhttpbin.url=$HTTPBIN_BASE_URL diff --git a/pom.xml b/pom.xml index 1efa54d..83935b8 100644 --- a/pom.xml +++ b/pom.xml @@ -264,6 +264,10 @@ ${project.build.outputDirectory} false + + --add-exports java.base/sun.net.www.protocol.http=ALL-UNNAMED + --add-exports java.base/sun.security.ssl=ALL-UNNAMED +