Add spring-boot-product-catalog sample (Spring Boot + PostgreSQL) - #149
Add spring-boot-product-catalog sample (Spring Boot + PostgreSQL)#149dhananjay6561 wants to merge 8 commits into
Conversation
A product-catalog REST API demonstrating Keploy replacing hand-written API tests. Ships a committed test set of 57 cases and 190 Postgres mocks under keploy/products-crud/, plus an app-only docker-compose.keploy.yml that replays the full suite green with no database present. - Full CRUD, category filters, inventory summary, stock adjustment - Multi-stage Dockerfile (Temurin 21), docker-compose for record/replay - Paths-scoped CI workflow: Maven build + end-to-end smoke test - Listed as sample #11 in the root README Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
There was a problem hiding this comment.
Pull request overview
Adds a new spring-boot-product-catalog sample module: a Spring Boot + PostgreSQL product-catalog REST API intended to demonstrate Keploy record/replay testing with a committed test-set and DB mocks.
Changes:
- Introduces a CRUD + inventory summary REST API (controller/service/repository/model + DTOs + error handling).
- Adds Docker-based local run + seed traffic generator + Keploy configuration and a committed Keploy test-set (tests + mocks + mappings).
- Adds documentation and a paths-scoped GitHub Actions workflow for module CI.
Reviewed changes
Copilot reviewed 89 out of 90 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| spring-boot-product-catalog/src/test/java/io/keploy/productcatalog/ProductCatalogApplicationTests.java | Adds a basic Spring context smoke test for the new sample. |
| spring-boot-product-catalog/src/main/resources/application.properties | Configures app name, server port, lazy init, datasource, JPA, and actuator health exposure. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/ProductController.java | Defines the REST API endpoints for product CRUD, stock adjustment, and inventory summary. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/error/ResourceNotFoundException.java | Adds a domain-specific exception for 404 cases. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/error/InsufficientStockException.java | Adds a domain-specific exception for 409 stock conflicts. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/error/GlobalExceptionHandler.java | Provides stable, structured JSON error responses for deterministic Keploy replays. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/dto/StockAdjustmentRequest.java | Adds the PATCH stock-adjust request payload with validation. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/dto/ProductResponse.java | Adds the API response DTO and mapping from the JPA entity. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/dto/ProductRequest.java | Adds create/update request DTO with validation constraints. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/web/dto/InventorySummaryResponse.java | Adds the response model for aggregated inventory summary endpoint. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/service/ProductService.java | Implements CRUD logic, stock adjustment, and inventory aggregation. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/repository/ProductRepository.java | Adds the Spring Data JPA repository with category filtering query. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/ProductCatalogApplication.java | Adds the Spring Boot application entry point. |
| spring-boot-product-catalog/src/main/java/io/keploy/productcatalog/model/Product.java | Adds the Product JPA entity schema and creation timestamp behavior. |
| spring-boot-product-catalog/seed.sh | Adds a curl-based traffic generator used for Keploy recording and CI smoke testing. |
| spring-boot-product-catalog/README.md | Documents sample purpose, architecture, API, Keploy record/replay steps, and troubleshooting. |
| spring-boot-product-catalog/pom.xml | Defines the module’s Spring Boot, JPA, validation, web, and test dependencies. |
| spring-boot-product-catalog/mvnw.cmd | Adds Maven Wrapper script for Windows. |
| spring-boot-product-catalog/mvnw | Adds Maven Wrapper script for Unix-like systems. |
| spring-boot-product-catalog/keploy/products-crud/tests/put-api-products-by-id-5.yaml | Adds a recorded Keploy test case for PUT validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/put-api-products-by-id-4.yaml | Adds a recorded Keploy test case for PUT 404 behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/put-api-products-by-id-3.yaml | Adds a recorded Keploy test case for PUT update behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/put-api-products-by-id-2.yaml | Adds a recorded Keploy test case for PUT update behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/put-api-products-by-id-1.yaml | Adds a recorded Keploy test case for PUT update behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-9.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-8.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-7.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-6.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-5.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-4.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-3.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-20.yaml | Adds a recorded Keploy test case for POST multi-field validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-2.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-19.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-18.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-17.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-16.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-15.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-14.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-13.yaml | Adds a recorded Keploy test case for POST validation failure behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-12.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-11.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-10.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/post-api-products-1.yaml | Adds a recorded Keploy test case for POST create behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-9.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-8.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-7.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-6.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-5.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-4.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-3.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-2.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-17.yaml | Adds a recorded Keploy test case for GET-by-id 404 behavior after delete. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-16.yaml | Adds a recorded Keploy test case for GET-by-id 404 behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-15.yaml | Adds a recorded Keploy test case for GET-by-id behavior after update. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-14.yaml | Adds a recorded Keploy test case for GET-by-id behavior after update. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-13.yaml | Adds a recorded Keploy test case for GET-by-id behavior after update. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-12.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-11.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-10.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-by-id-1.yaml | Adds a recorded Keploy test case for GET-by-id behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-9.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-8.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-7.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-6.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-5.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-4.yaml | Adds a recorded Keploy test case for list-by-category behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-3.yaml | Adds a recorded Keploy test case for list-all behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-2.yaml | Adds a recorded Keploy test case for list-all empty behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-12.yaml | Adds a recorded Keploy test case for list-by-category behavior after updates/deletes. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-11.yaml | Adds a recorded Keploy test case for list-all behavior after updates/deletes. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-10.yaml | Adds a recorded Keploy test case for list-by-category empty behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/get-api-products-1.yaml | Adds a recorded Keploy test case for list-all empty behavior (early). |
| spring-boot-product-catalog/keploy/products-crud/tests/delete-api-products-by-id-3.yaml | Adds a recorded Keploy test case for DELETE 404 behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/delete-api-products-by-id-2.yaml | Adds a recorded Keploy test case for DELETE success behavior. |
| spring-boot-product-catalog/keploy/products-crud/tests/delete-api-products-by-id-1.yaml | Adds a recorded Keploy test case for DELETE success behavior. |
| spring-boot-product-catalog/keploy/products-crud/mappings.yaml | Adds test-to-mocks mapping so stateful reads replay against the correct mocks. |
| spring-boot-product-catalog/keploy/products-crud/config.yaml | Adds Keploy test-set metadata configuration. |
| spring-boot-product-catalog/keploy/.gitignore | Ignores Keploy runtime artifacts (reports/logs) within the module. |
| spring-boot-product-catalog/keploy.yml | Adds Keploy configuration for record/replay (compose command, ports, noise rules, mappings, delays). |
| spring-boot-product-catalog/Dockerfile | Adds a multi-stage container build for the sample (Temurin 21 build + slim runtime). |
| spring-boot-product-catalog/docker-compose.yml | Adds app + Postgres compose stack with healthchecks for local run/recording. |
| spring-boot-product-catalog/docker-compose.keploy.yml | Adds an app-only compose stack for dependency-free Keploy replay. |
| spring-boot-product-catalog/.mvn/wrapper/maven-wrapper.properties | Adds Maven Wrapper configuration for reproducible builds. |
| spring-boot-product-catalog/.gitignore | Adds module-specific ignores (target/, IDE files, Keploy artifacts). |
| spring-boot-product-catalog/.gitattributes | Normalizes line endings for mvnw and .cmd scripts. |
| spring-boot-product-catalog/.dockerignore | Excludes build outputs and keploy/ fixtures from Docker build context. |
| README.md | Registers the new sample as entry #11 in the repository root README. |
| .github/workflows/spring-boot-product-catalog.yml | Adds a paths-scoped CI workflow to build and smoke-test the new sample. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The not-found message was 'Product not found with id: <id>', but the committed GET/PUT/DELETE 404 tests assert body.message as 'Product <id> not found' (only header.Date is noise). Restore the recorded wording so the suite replays green as the README states, and add a guard comment so the contract-sensitive string isn't reworded again. Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
…ic stock
- docker-compose.yml: add an app healthcheck (Actuator /health via curl) so
'docker compose up --wait' blocks until the app is actually ready. Left the
DB-absent docker-compose.keploy.yml alone, where a db health check would fail.
- seed.sh: exercise GET /summary and PATCH /{id}/stock (409 + 404) so the README's
're-record picks them up' claim holds; fail loudly if the app never becomes ready
instead of silently proceeding and exiting 0.
- ProductService/ProductRepository: make adjustStock an atomic guarded UPDATE so
concurrent PATCHes can't lose an update or bypass the >= 0 guard. Scoped to the
(un-recorded) stock path via a @Modifying query rather than @Version, which would
change every INSERT/UPDATE and break the committed Postgres mocks.
Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
The aggregate /actuator/health endpoint runs the JDBC db indicator on every poll (interval: 5s), which Keploy captures as extra Postgres mocks during keploy record and bloats mocks.yaml. The readiness group (already enabled via management.endpoint.health.probes.enabled) doesn't touch the DB, so it still gives 'docker compose up --wait' a real ready-to-serve signal without polluting the recorded capture. Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
|
LGTM ✅ |
amaan-bhati
left a comment
There was a problem hiding this comment.
Reviewed the full sample — the Keploy integration layer is well thought out (ignoreOrdering, mappings, readiness-probe healthcheck to avoid recording DB traffic, noise rules on createdAt/Date). There are two build-breaking issues in pom.xml that need to be fixed before anything else can be validated, plus six supporting findings.
See inline comments for details.
…eanup - Dockerfile: run the JVM as a non-root 'spring' user. - workflow: smoke now 'needs: build', so it doesn't rebuild and burn its timeout when the build has already failed. - keploy.yml: drop the unused mongoPassword default (this app is Postgres-only). - Product: remove the setCreatedAt setter; createdAt is @PrePersist-assigned on an updatable=false column, so a setter is silently dropped on save and misleads callers. - seed.sh: fail loudly in create() when the POST fails or returns no id, instead of appending an empty id and corrupting later phases. Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
|
@amaan-bhati thanks for the thorough review — all eight comments addressed, pushed in Fixed
Please sanity-check my reasoning on these two
Ready for another look when you have a moment 🙏 |
amaan-bhati
left a comment
There was a problem hiding this comment.
Second pass — good progress: Dockerfile now runs as a non-root user, setCreatedAt removed, mongoPassword cleaned from keploy.yml, needs: build wired in CI, and create() in seed.sh has explicit error handling. Three items from the previous round are still open.
…t -e - pom.xml: use spring-boot-starter-web and the aggregate spring-boot-starter-test instead of the 4.x modular starters. Both resolve on 4.1.0 (verified), but the classic starters are the conventional choice for a sample; -web still brings embedded Tomcat (tomcat-embed-core 11.0.22) + spring-webmvc. - seed.sh: enable 'set -e' so a failure in any phase (not just create()) aborts loudly. Hardened id_of to 'grep -m1' (no downstream head -> no SIGPIPE) so the pipeline stays clean under -e + pipefail, and guarded the id extraction with '|| true' to preserve the friendly no-id error. Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
amaan-bhati
left a comment
There was a problem hiding this comment.
Third pass — all prior findings have been addressed. Five new items below, ranging from a correctness bug in the stock-adjustment path to two test coverage gaps. The pom.xml and Dockerfile are now clean; the Keploy integration layer is solid.
… dead test
- ProductService.adjustStock: on a 0-row update, re-check existsById so a product
deleted concurrently between findById and the UPDATE returns 404, not a misleading 409.
- GlobalExceptionHandler: handle MethodArgumentTypeMismatchException so a non-numeric
path variable (/api/products/abc) returns the uniform {status,error,message} 400 shape
instead of Spring's default ProblemDetail.
- Remove the placeholder @SpringBootTest (it needs a live DB, so CI skipped it and it was
dead code) and the now-unused spring-boot-starter-test dependency. The Keploy recorded
suite is this sample's test coverage.
Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
…, name length=120
Regenerates the Keploy test set against the updated app so all committed changes that
touch recorded state land together and replay stays green:
- Coverage: the suite now exercises all seven endpoints — adds GET /api/products/summary
and PATCH /api/products/{id}/stock (restock, ship, 409 over-decrement, 404), closing the
previously documented gap. 57 -> 63 test cases, 190 -> 214 Postgres mocks.
- Determinism: list/filter/summary queries now use an explicit ORDER BY id
(findByCategoryIgnoreCaseOrderByIdAsc / findAll(Sort.by("id"))), so re-records reproduce
a stable row order instead of Postgres heap order.
- Schema: name column is length = 120, matching the @SiZe(max = 120) validation constraint;
the regenerated CREATE-table mock reflects it, so the DB-absent replay still starts clean.
- README updated for the new counts and full-coverage note.
Verified green both ways: 'keploy test' (real DB) and the DB-absent docker-compose.keploy.yml
replay both report Total: 63 Passed: 63 Failed: 0.
Signed-off-by: dhananjay6561 <dhananjayaggarwal6561@gmail.com>
|
@amaan-bhati third-pass items all addressed — pushed in Code fixes (7c68ee4)
Re-recorded the suite (3803f1d) — this closes the coverage gap and lands the two recording-coupled items together:
I believe that clears every thread across the three passes. Ready for another look whenever you have a moment 🙏 |
Description
Adds a new Java sample — spring-boot-product-catalog, a Spring Boot + PostgreSQL product-catalog REST API used to demonstrate Keploy replacing hand-written API tests. Instead of JUnit fixtures and mocks, Keploy records real traffic once (capturing every downstream Postgres call as a mock) and replays it as a regression suite that needs no database at all.
The sample ships a committed test set under
keploy/products-crud/:docker-compose.keploy.yml— an app-only Compose file with nopostgresservice at all; the suite still passes green because every DB call is served from the recorded mocksTraffic generator —
seed.sh: a bundled script drives the entire workload in one pass — 12 products across several categories, every read path, category filters, the/summaryrollup,PUTupdates,PATCH /{id}/stockadjustments (restock, ship, and the409over-decrement), deletes, and the404/400validation paths. This is exactly what produced the committed suite: runningkeploy recordand then./seed.shin another terminal generates all 63 cases. It's idempotent-friendly (chains the ids returned byPOSTinto later calls) and fails loudly (set -euo pipefail) if the app never comes up or a create returns no id, so a bad run can't silently record a partial capture.Also adds a paths-scoped CI workflow (
.github/workflows/spring-boot-product-catalog.yml) and lists the sample as #11 in the root README.Issues are disabled on this repo; no linked
keploy/keployissue.Type of change
How Has This Been Tested?
The stack runs entirely in Docker (no local Java/Maven needed).
Record (brings the stack up in record mode, then drive traffic with
./seed.shfrom another terminal):Replay against the recorded mocks:
Result:
Dependency-free replay — same green result with no database service present:
Checklist: