Skip to content

Feat/testing the full image before publishing - #84

Merged
VonAdamo merged 4 commits into
mainfrom
feat/testing-the-full-image-before-publishing
Feb 18, 2026
Merged

Feat/testing the full image before publishing#84
VonAdamo merged 4 commits into
mainfrom
feat/testing-the-full-image-before-publishing

Conversation

@TatjanaTrajkovic

@TatjanaTrajkovic TatjanaTrajkovic commented Feb 17, 2026

Copy link
Copy Markdown

Summary
This PR introduces integration testing framework using Testcontainers. It allows the project to automatically build the Docker image and run real HTTP requests against the server in a containerized environment before publishing.
A Key benefit using Testcontainers is taht all Docker containers and resoruces are automatically cleaned up after the tests finish, ensuring no stale containers are left running on the developer machine.

Changes

  • AppIT.java: Implemented a new integration test suite.
    • Automated Lifecycle: Uses https://github.com/testcontainers to handle the full lifecycle (start, test, and cleanup) of the Docker container.
    • Verifies 200 OK and character encoding (rocket emoji check) for the home page.
    • Verifies 404 Not Found for non-existent resources.
    • Added @SuppressWarnings("resource") to handle false-positive IDE warnings for the managed container.
  • Dockerfile: Fixed the JAR copy instruction.
    • Replaced the *.jar wildcard with an explicit path to /app/target/app.jar. This resolves a conflict where multiple JARs in the build stage caused the Docker build to fail.
  • pom.xml: Added necessary dependencies for testing:
    • testcontainers and junit-jupiter (for container management).

Test plan
Run the following command to verify the full build and integrations tests:
./mvnw verify -Dfailsafe.useFile=false
Verify that the AppIT starts the Docker container, all tests pass with a BUILD SUCCESS, and the container is automatically removed.
Keep in mind that docker needs to be running on computer when running the above command.

Summary by CodeRabbit

  • Tests

    • Added new integration tests that run the server in containerized environments to verify HTTP responses (index page, 404 handling).
  • Chores

    • Added test-scoped dependencies to enable advanced integration testing.
    • Made build artifact handling more consistent to improve repeatable test and runtime behavior.

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds Testcontainers-based integration tests, two test-scoped Testcontainers dependencies, and updates Dockerfile to copy a fixed artifact name (target/app.jar) instead of a wildcard.

Changes

Cohort / File(s) Summary
Build / Container
Dockerfile
Replaced COPY from /app/target/*.jar to /app/target/app.jar, making the Docker build rely on a fixed artifact name.
Maven config
pom.xml
Added test-scoped dependencies org.testcontainers:testcontainers:2.0.3 and org.testcontainers:junit-jupiter:1.21.4 to enable Testcontainers-based tests.
Integration tests
src/test/java/org/juv25d/AppIT.java
Introduces Testcontainers GenericContainer setup and two integration tests: one asserting 200 OK and HTML for /, another asserting 404 for /not-found.html; adds helper HTTP client method and container lifecycle annotations.

Sequence Diagram(s)

sequenceDiagram
  participant Test as Test Runner
  participant TC as Testcontainers (Docker)
  participant App as App (inside Container)
  participant HTTP as HttpClient

  Test->>TC: start container from local image (mount project)
  TC->>App: initialize server, expose 8080, wait for HTTP 200 on "/"
  Note right of TC: readiness check
  HTTP->>App: GET "/"
  App-->>HTTP: 200 + index HTML
  HTTP->>Test: return response
  HTTP->>App: GET "/not-found.html"
  App-->>HTTP: 404 + body "404"
  HTTP->>Test: return response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • fmazmz
  • annikaholmqvist94

Poem

🐰 I hopped into tests with a jar in tow,
Containers bloom and the tiny servers glow,
GETs and 404s I nibble and know,
From wildcard weeds to an app that’s slow,
Hooray — the CI carrots grow! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/testing the full image before publishing' directly relates to the main changeset objective: adding integration tests to validate the Docker image before publishing, which is reflected across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/testing-the-full-image-before-publishing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@TatjanaTrajkovic TatjanaTrajkovic linked an issue Feb 17, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/test/java/org/juv25d/AppIT.java (2)

27-27: Make HttpClient static to share it across test instances.

JUnit 5 creates a new AppIT instance per test method, so HttpClient.newHttpClient() is called twice. Since HttpClient is designed to be reused, making it static eliminates the redundant allocation and any internal thread-pool overhead.

♻️ Proposed refactor
-    private final HttpClient client = HttpClient.newHttpClient();
+    private static final HttpClient client = HttpClient.newHttpClient();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/AppIT.java` at line 27, Make the HttpClient instance
shared across test instances by changing the non-static field client in the
AppIT class to a static field: locate the declaration "private final HttpClient
client = HttpClient.newHttpClient();" in class AppIT and modify it to be static
so the HttpClient is created once and reused across JUnit 5 test instances;
ensure other uses of client in the class remain unchanged.

24-24: Consider adding a .dockerignore to reduce the build context size.

withFileFromPath(".", Paths.get(".")) transfers the entire project directory — including target/, .git/, and any other generated artifacts — into the Docker daemon as the build context. This can significantly slow down the image build step, especially in CI.

A .dockerignore at the project root (e.g., excluding target/, .git/, *.md) keeps the context lean without affecting the COPY pom.xml and COPY src steps inside the Dockerfile.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/AppIT.java` at line 24, The test uses
withFileFromPath(".", Paths.get(".")) which sends the entire repo as Docker
build context; add a .dockerignore at project root (exclude target/, .git/,
.idea/, *.class, *.log, etc.) so the build context is small and CI builds are
faster, then keep using withFileFromPath(".", Paths.get(".")) unchanged; ensure
.dockerignore still allows necessary files (pom.xml and src/) by not listing
them.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pom.xml`:
- Around line 43-54: The pom references invalid Testcontainers versions; update
the dependency versions for org.testcontainers:testcontainers and
org.testcontainers:junit-jupiter to the existing release 1.21.3 by changing the
<version> elements for the artifactId testcontainers and junit-jupiter to 1.21.3
so Maven can resolve the artifacts.

In `@src/test/java/org/juv25d/AppIT.java`:
- Around line 22-25: The Testcontainers GenericContainer "server" is missing a
readiness wait and can return connection-refused; update the container
definition that builds with ImageFromDockerfile and withExposedPorts(8080) to
include a waitingFor strategy (e.g., Wait.forHttp("/") or
Wait.forListeningPort() with an appropriate forStatusCode and a startup timeout
via Duration) so Testcontainers waits until the Java HTTP server is actually
accepting connections on port 8080 before tests proceed; apply this to the
static "server" variable initialization.

---

Nitpick comments:
In `@src/test/java/org/juv25d/AppIT.java`:
- Line 27: Make the HttpClient instance shared across test instances by changing
the non-static field client in the AppIT class to a static field: locate the
declaration "private final HttpClient client = HttpClient.newHttpClient();" in
class AppIT and modify it to be static so the HttpClient is created once and
reused across JUnit 5 test instances; ensure other uses of client in the class
remain unchanged.
- Line 24: The test uses withFileFromPath(".", Paths.get(".")) which sends the
entire repo as Docker build context; add a .dockerignore at project root
(exclude target/, .git/, .idea/, *.class, *.log, etc.) so the build context is
small and CI builds are faster, then keep using withFileFromPath(".",
Paths.get(".")) unchanged; ensure .dockerignore still allows necessary files
(pom.xml and src/) by not listing them.

Comment thread pom.xml
Comment thread src/test/java/org/juv25d/AppIT.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/test/java/org/juv25d/AppIT.java (2)

21-27: LGTM — wait strategy is now in place.

The .waitingFor(Wait.forHttp("/").forStatusCode(200)) on line 27 correctly addresses the previously raised concern about race conditions between container RUNNING state and the server being ready to accept connections.

💡 Optional: add an explicit startup timeout for slow CI environments

The default Testcontainers startup timeout is 60 seconds. In resource-constrained CI runners (especially on first run, when the base image needs to be pulled), that can be tight. An explicit ceiling avoids a hard-to-diagnose timeout failure:

 ).withExposedPorts(8080)
-    .waitingFor(Wait.forHttp("/").forStatusCode(200));
+    .waitingFor(Wait.forHttp("/").forStatusCode(200)
+        .withStartupTimeout(java.time.Duration.ofMinutes(2)));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/AppIT.java` around lines 21 - 27, Add an explicit
startup timeout to the Testcontainers GenericContainer "server" to avoid flaky
failures in slow CI; update the container configuration for the static field
server (GenericContainer<?> server) to chain a
withStartupTimeout(Duration.ofSeconds(...)) call with an appropriate ceiling
(e.g., 120s) and ensure java.time.Duration is imported so the wait strategy
(Wait.forHttp("/").forStatusCode(200)) has a longer overall startup window.

29-29: Consider a static HttpClient to avoid per-test-instance allocation.

Containers declared as static fields are started only once before any test method is executed and stopped after the last test method has executed. The HttpClient is stateless and safe to share across tests, so creating a new instance per test-instance (JUnit Jupiter's default PER_METHOD lifecycle) allocates unnecessary objects. In Java 21+, HttpClient also implements AutoCloseable — none of the instances here are ever closed.

♻️ Proposed refactor
-    private final HttpClient client = HttpClient.newHttpClient();
+    private static final HttpClient client = HttpClient.newHttpClient();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/AppIT.java` at line 29, The HttpClient in AppIT is
created per test-instance which is unnecessary and never closed; change the
instance field "private final HttpClient client" to a shared static client
(e.g., "private static HttpClient client") and initialize it once for the test
class, and if you want to honor Java 21's AutoCloseable behavior, create it in a
`@BeforeAll` (or static initializer) and close it in an `@AfterAll` method so the
single HttpClient is reused across tests and properly cleaned up.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/test/java/org/juv25d/AppIT.java`:
- Around line 4-8: Update the JUnit Jupiter Testcontainers dependency in pom.xml
to match Testcontainers 2.0.3: replace the old artifact declaration using
groupId/org.testcontainers and artifactId/junit-jupiter (version 1.21.4) with
the new artifactId testcontainers-junit-jupiter and version 2.0.3, keeping scope
test; ensure the groupId remains org.testcontainers so the project uses the
correct Testcontainers JUnit 5 module compatible with the core 2.0.3 APIs.

---

Nitpick comments:
In `@src/test/java/org/juv25d/AppIT.java`:
- Around line 21-27: Add an explicit startup timeout to the Testcontainers
GenericContainer "server" to avoid flaky failures in slow CI; update the
container configuration for the static field server (GenericContainer<?> server)
to chain a withStartupTimeout(Duration.ofSeconds(...)) call with an appropriate
ceiling (e.g., 120s) and ensure java.time.Duration is imported so the wait
strategy (Wait.forHttp("/").forStatusCode(200)) has a longer overall startup
window.
- Line 29: The HttpClient in AppIT is created per test-instance which is
unnecessary and never closed; change the instance field "private final
HttpClient client" to a shared static client (e.g., "private static HttpClient
client") and initialize it once for the test class, and if you want to honor
Java 21's AutoCloseable behavior, create it in a `@BeforeAll` (or static
initializer) and close it in an `@AfterAll` method so the single HttpClient is
reused across tests and properly cleaned up.

Comment thread src/test/java/org/juv25d/AppIT.java

@simonforsberg simonforsberg left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition! It’s great that we’re testing the actual server end-to-end instead of only using unit tests.

@VonAdamo VonAdamo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, looks good!

@VonAdamo
VonAdamo merged commit 3377579 into main Feb 18, 2026
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Testing the full image before publishing

3 participants