Skip to content

fix: v3/v4 error bodies + deterministic API version in acceptance ITs - #3

Open
emmanuelbruno wants to merge 2 commits into
developfrom
fix/v3v4-error-bodies-deterministic-version
Open

emmanuelbruno wants to merge 2 commits into
developfrom
fix/v3v4-error-bodies-deterministic-version

Conversation

@emmanuelbruno

@emmanuelbruno emmanuelbruno commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Two defects fixed

1. v3/v4 error responses had empty bodies (API contract violation).
ProductServiceV3/ProductServiceV4 threw entity-less WebApplicationException/NotFoundException for 409/404, and GlobalExceptionMapper passes WebApplicationExceptions through untouched — so clients got empty bodies. The shared Cucumber scenarios assert containsString("SKU already exists") / containsString("Product not found") (only v5's plain-exception path produced text/plain bodies via ConflictMapper/NotFoundMapper).
Evidence: GHA run 34215125166 — arm64 leg: Tests run: 77, Failures: 9, all 9 = the error message should contain on the 409-create / 404-get / 404-delete scenarios.

2. Non-deterministic API version in the acceptance ITs (v3/v4 were never actually tested).
Hooks.java had five tag-based @Before hooks (@v1@v5) each overwriting the scenario-scoped VersionContext. The shared catalog scenarios are tagged @v3 @v4 @v5, so in any run three hooks fired in nondeterministic order and the last one won — each CatalogV*AcceptanceIT exercised a random version (usually v5, hence "previously green"). In run 34215125166 all three of V3/V4/V5 classes landed on v3/v4 and failed identically.

Changes

Commit 1 — fix: return error bodies for v3/v4 409/404 responses (API contract)
ProductServiceV3 (get-404, create-409; delete delegates to get) and ProductServiceV4 (get-404, create-409, delete-404) now throw Response.status(...).entity(...).type(text/plain).build() with wording mirroring the v5 mappers exactly: "Product SKU already exists: <sku>" (409) and "Product not found: <sku>" (404). GlobalExceptionMapper, the v5 mappers, and all v5 behavior are untouched.

Commit 2 — test: pin API version deterministically per acceptance IT class
Deleted the five tag-based version setters from Hooks.java and added one tagless @Before glue hook per IT class (V1VersionHookV5VersionHook in org.acme.api.cucumber.v1v5), each IT's @CucumberOptions.glue now includes its own package. Exactly one version setter can fire per IT class, so each class deterministically exercises its own version.
Note: the spec initially assumed only V3/V4/V5 IT classes exist, but CatalogV1AcceptanceIT/CatalogV2AcceptanceIT also exist (features tagged @v1/@v2); they get the same deterministic per-class treatment (V1/V2 hooks), so all five tag hooks are replaced 1:1.

Verification

CI on head 3f977b7 — run https://github.com/ebpro/notebook-java-rest-sample-quarkus/actions/runs/34233437148success (~2m15s).

Note: the run was scheduled onto the ARM self-hosted runner (ebpro-org-arm-*), so this fix is validated on the same architecture that was failing the multiarch PR #2 arm64 leg.

  • Integration (failsafe): Tests run: 77, Failures: 0, Errors: 0, Skipped: 0
    • per class: v1 10, v2 11, v3 16, v4 16, v5 20
  • Unit (surefire): Tests run: 7, Failures: 0, Errors: 0, Skipped: 0
  • Determinism (fix b): TestDebugFilter shows 0 cross-version hits — every class hit only its own version:
    • CatalogV1AcceptanceIT/api/v1/... (2/2)
    • CatalogV2AcceptanceIT/api/v2/... (2/2)
    • CatalogV3AcceptanceIT/api/v3/... (4/4)
    • CatalogV4AcceptanceIT/api/v4/... (4/4)
    • CatalogV5AcceptanceIT/api/v5/... (6/6)
  • Error bodies (fix a): the 9 assertions that failed in run 34215125166 (empty bodies) now PASS, e.g. v3/v4 409 → Product SKU already exists: TV-1, v3/v4 404 → Product not found: NON-EXISTENT.
  • Local ./mvnw -B verify was not run (local Testcontainers/podman socket unavailable for this user); the CI run above is the verification gate.

v3/v4 threw entity-less WebApplicationException/NotFoundException; features assert "SKU already exists"/"Product not found" substrings; messages mirror the v5 mappers (text/plain). Evidence: GHA run 34215125166 (9 failures, empty bodies on v4).
the five tag-based @before hooks in Hooks.java overwrote VersionContext in nondeterministic order, so V3/V4 IT classes exercised a random version (usually v5); v3/v4 were never actually tested; each IT class now pins its own version.
Copilot AI lite review requested due to automatic review settings September 8, 2026 13:40

Copilot AI 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.

🟢 Approval recommended

The changes are narrowly scoped, align v3/v4 error bodies with the established v5 contract, and make acceptance tests deterministically exercise the intended API version per IT class.

Pull request overview

This PR fixes two acceptance-test-breaking defects: (1) v3/v4 404/409 responses violated the API contract by returning empty bodies, and (2) acceptance tests selected API versions nondeterministically due to multiple tag-based hooks racing to set the scenario version.

Changes:

  • Ensure v3/v4 404/409 WebApplicationException/NotFoundException responses include text/plain entities matching v5’s message wording.
  • Make acceptance tests deterministic by removing tag-based version hooks and introducing one per-IT-class version hook (v1–v5), then scoping glue per IT class.
File summaries
File Description
src/main/java/org/acme/service/v3/ProductServiceV3.java Build 404/409 Response objects with text/plain bodies so GlobalExceptionMapper passthrough preserves error entities.
src/main/java/org/acme/service/v4/ProductServiceV4.java Same as v3: ensure 404/409 exceptions carry response entities and content type.
src/test/java/org/acme/api/cucumber/steps/Hooks.java Removes tag-based version setters that could overwrite each other nondeterministically.
src/test/java/org/acme/api/cucumber/v1/V1VersionHook.java New per-class Cucumber @Before hook to pin VersionContext to v1.
src/test/java/org/acme/api/cucumber/v2/V2VersionHook.java New per-class Cucumber @Before hook to pin VersionContext to v2.
src/test/java/org/acme/api/cucumber/v3/V3VersionHook.java New per-class Cucumber @Before hook to pin VersionContext to v3.
src/test/java/org/acme/api/cucumber/v4/V4VersionHook.java New per-class Cucumber @Before hook to pin VersionContext to v4.
src/test/java/org/acme/api/cucumber/v5/V5VersionHook.java New per-class Cucumber @Before hook to pin VersionContext to v5.
src/test/java/org/acme/api/cucumber/v1/CatalogV1AcceptanceIT.java Adds v1 glue package so only the v1 pinning hook runs for this IT.
src/test/java/org/acme/api/cucumber/v2/CatalogV2AcceptanceIT.java Adds v2 glue package so only the v2 pinning hook runs for this IT.
src/test/java/org/acme/api/cucumber/v3/CatalogV3AcceptanceIT.java Adds v3 glue package so only the v3 pinning hook runs for this IT.
src/test/java/org/acme/api/cucumber/v4/CatalogV4AcceptanceIT.java Adds v4 glue package so only the v4 pinning hook runs for this IT.
src/test/java/org/acme/api/cucumber/v5/CatalogV5AcceptanceIT.java Adds v5 glue package so only the v5 pinning hook runs for this IT.
Review details
  • Files reviewed: 13/13 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants