test: full E2E test suite across processing, backoffice & flows#245
Conversation
Add a live end-to-end test suite that exercises every SDK operation against the Gr4vy sandbox, mirroring the harness already shipped on the PHP, Go, TypeScript and Python SDKs. - Harness (test/util): one isolated merchant per JVM (= per Gradle shard), a Reaches() "endpoint reached" assertion (4xx counts as reached), shared fixtures/generators, and a JSON interceptor that injects an unknown response field for forward-compat plus records reached endpoints when GR4VY_TRACK_HTTP=1. - Tests sharded into flows/ (happy-path lifecycles), processing/ and backoffice/, covering CRUD with real 2xx where the mock supports it and Reaches() for mock-unsupported operations. Transactions report create is a real happy path. - scripts/endpoint_coverage/EndpointCoverage.java builds the operation catalogue from generated source and reports endpoint-reach coverage. - CI sharded by package with a stable ci-complete gate (so the required check name is stable as shards change), a build+offline matrix on Java 11/17/21, and a coverage PR comment. Fork PRs skip the live suite. - Supersedes the single-file BaseTest/CheckoutSessionsTest scaffold. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface assertion messages and stack traces in the Gradle test log so live E2E failures are diagnosable from CI output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Reports: the transactions report spec requires fields/filters/sort in params; supply a valid set so create/get/put/executions run as real 2xx. - Reaches: count any HTTP status < 500 as reached. payment-services verify returns an empty text/html 200, which the SDK surfaces as an APIException with code=200 — that still reached the endpoint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Endpoint-reach coverage107 / 107 operations reached by a real HTTP request (100%). Every operation in the SDK was reached. 🎉 |
There was a problem hiding this comment.
Pull request overview
Adds a comprehensive live end-to-end (E2E) test harness for the Java SDK that exercises processing, backoffice, and flow lifecycles against the Gr4vy sandbox, plus CI sharding and an endpoint-reach coverage report.
Changes:
- Introduces a shared E2E test harness (
Harness,Reaches, fixtures/generators) and a suite of live tests organized by package (flows/,processing/,backoffice/). - Adds a test HTTP client wrapper that injects unknown JSON fields for forward-compat checks and records reached endpoints for coverage reporting.
- Updates CI to compile across Java 11/17/21, run offline unit tests separately, shard live E2E tests, and post a sticky endpoint-coverage PR comment.
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| TESTING.md | Documents how to run the offline vs live E2E suite and the coverage report. |
| src/test/java/com/gr4vy/sdk/util/Reaches.java | Adds a reach-only assertion helper for endpoints that can’t return clean 2xx in the deterministic mock. |
| src/test/java/com/gr4vy/sdk/util/JsonInterceptorHttpClient.java | Wraps the HTTP client to inject unknown JSON fields and record reached endpoints. |
| src/test/java/com/gr4vy/sdk/util/Harness.java | Provisions one sandbox merchant + mock-card payment service per test JVM and exposes a merchant-bound SDK client. |
| src/test/java/com/gr4vy/sdk/util/Gen.java | Adds a seedable generator for light property-style E2E tests. |
| src/test/java/com/gr4vy/sdk/util/Fixtures.java | Adds shared deterministic fixture data (cards, addresses, ids, bodies). |
| src/test/java/com/gr4vy/sdk/util/Checkout.java | Adds raw checkout-session “fields” PUT helpers (session-id-authenticated). |
| src/test/java/com/gr4vy/sdk/util/BaseTest.java | Removes the prior single-suite scaffold. |
| src/test/java/com/gr4vy/sdk/processing/TransactionsTest.java | Adds E2E coverage for transactions and related sub-resources. |
| src/test/java/com/gr4vy/sdk/processing/PropertyTest.java | Adds a small property-style E2E test for transaction creation. |
| src/test/java/com/gr4vy/sdk/processing/PaymentMethodsTest.java | Adds E2E coverage for payment methods and reach-only token sub-resources. |
| src/test/java/com/gr4vy/sdk/processing/PaymentLinksTest.java | Adds E2E coverage for payment links. |
| src/test/java/com/gr4vy/sdk/processing/GiftCardsTest.java | Adds E2E coverage for gift cards (reach-only where unsupported). |
| src/test/java/com/gr4vy/sdk/processing/DigitalWalletsTest.java | Adds E2E coverage for digital wallets (mostly reach-only). |
| src/test/java/com/gr4vy/sdk/processing/CheckoutSessionsTest.java | Adds E2E coverage for checkout sessions. |
| src/test/java/com/gr4vy/sdk/processing/CatalogTest.java | Adds E2E coverage for read-only catalog endpoints. |
| src/test/java/com/gr4vy/sdk/processing/BuyersTest.java | Adds E2E coverage for buyers and nested resources. |
| src/test/java/com/gr4vy/sdk/flows/TransactionLifecycleTest.java | Adds a full happy-path card transaction lifecycle flow test. |
| src/test/java/com/gr4vy/sdk/flows/CheckoutSessionLifecycleTest.java | Adds a full happy-path checkout session lifecycle flow test. |
| src/test/java/com/gr4vy/sdk/flows/BuyerLifecycleTest.java | Adds a full happy-path buyer lifecycle flow test. |
| src/test/java/com/gr4vy/sdk/CheckoutSessionsTest.java | Removes the prior single-file checkout session E2E tests. |
| src/test/java/com/gr4vy/sdk/backoffice/ThreeDsScenariosTest.java | Adds E2E coverage for 3DS scenarios (reach-only where unsupported). |
| src/test/java/com/gr4vy/sdk/backoffice/ThreeDsConfigurationTest.java | Adds E2E coverage for per-merchant 3DS configuration endpoints. |
| src/test/java/com/gr4vy/sdk/backoffice/ReportsTest.java | Adds E2E coverage for reports + report executions. |
| src/test/java/com/gr4vy/sdk/backoffice/ReportExecutionsTest.java | Adds E2E coverage for top-level report executions listing. |
| src/test/java/com/gr4vy/sdk/backoffice/PayoutsTest.java | Adds E2E coverage for payouts (reach-only where unsupported). |
| src/test/java/com/gr4vy/sdk/backoffice/PaymentServicesTest.java | Adds E2E coverage for payment services (reach-only for verify/session). |
| src/test/java/com/gr4vy/sdk/backoffice/MerchantAccountsTest.java | Adds E2E coverage for merchant accounts (admin endpoints). |
| src/test/java/com/gr4vy/sdk/backoffice/AuditLogsTest.java | Adds E2E coverage for audit logs listing. |
| src/test/java/com/gr4vy/sdk/backoffice/AccountUpdaterTest.java | Adds E2E coverage for account updater job creation (reach-only). |
| build-extras.gradle | Improves test logging output to aid debugging failures. |
| .gitignore | Ignores generated endpoint-coverage output under /coverage/. |
| .github/workflows/ci.yaml | Reworks CI into build/offline/e2e shards + coverage report + stable ci-complete gate. |
Comments suppressed due to low confidence (1)
src/test/java/com/gr4vy/sdk/util/JsonInterceptorHttpClient.java:154
- Computing Content-Length from InputStream.available() is unreliable (it changes as the stream is read and isn’t guaranteed to reflect total length). Since the body is already fully materialized and substituted, it’s safer to omit Content-Length entirely rather than emitting a potentially wrong value.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ft balances) Close the endpoint-reach gap to 107/107: - Paze digital-wallet sessions: paze, mobile create/review/complete. - transactions void_ (distinct from cancel) and refunds().all().create(). - gift-cards balances lookup. All are mock-unsupported, so they assert via Reaches (a 4xx/404 proves the endpoint was routed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 35 out of 37 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/test/java/com/gr4vy/sdk/util/JsonInterceptorHttpClient.java:146
ModifiedHttpResponse.headers()recalculatesContent-Lengthfrombody.available(), which depends on the stream’s current position. If the SDK reads from the body before accessing headers (or accesses headers multiple times), this can produce an incorrectContent-Lengthvalue. Safer approach: omitContent-Lengthentirely in the wrapped response (it’s not required for streaming reads) rather than risk lying about it.
- GiftCardBalanceRequest requires items; PazeClient requires id/name/profileId and PazeTransactionValue requires currency/amount — populate them so the requests actually reach the endpoint (the build() validation ran client-side before the call). - Coverage filename now carries a random suffix so shard artifacts with colliding PIDs don't overwrite when merged. - Clarify that the per-shard-merchant guarantee comes from CI running each package as a separate gradle invocation; a single local run shares one JVM. - Note the coverage script needs Java 17+ (record types); document async injection is sync-path only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er failures) - JsonInterceptorHttpClient: apply forward-compat injection on the async path too (shared maybeInject helper); drop best-effort stderr logging so the injector stays silent across the suite. - Reaches: drop the unreachable AuthException branch (it extends Gr4vyError) and the deprecated statusCode() call; preserve the cause via fail(msg, e). - Checkout: add connect + request timeouts to the raw field PUT. - CI: fail fast when PRIVATE_KEY is missing on non-PR runs so a misconfigured secret can't silently skip the live suite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sonl) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ModifiedHttpResponse carries the modified byte[] and derives Content-Length from its length, instead of the stream's remaining-bytes available() (which was read-state dependent and defaulted to 0 on error). - Drop contents/pull-requests write scope from the e2e job; it only reads the repo and uploads artifacts (auto-approve lives in ci-complete). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- sendAsync uses ResponseWithBody's mapping constructor (non-null bodyMapper) so previousResponse() can't NPE on a redirect chain, while still returning the injected body. - Checkout.API_BASE_URL is derived from Gr4vy.SERVERS + a shared Harness.SERVER_ID so it can't drift from the client the harness builds. - ci-complete drops contents: write (it only approves the bot PR). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Media types are case-insensitive; normalize the header before checking for application/json so e.g. Application/JSON still gets the forward-compat field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Adds a live end-to-end test suite for the Java SDK that exercises every operation against the Gr4vy sandbox, mirroring the harness already shipped on the PHP, Go, TypeScript and Python SDKs. This is the last SDK in the fleet to get the treatment.
How it works
util/Harnessprovisions a fresh random-id merchant + a deterministicmock-cardservice on first use and caches it in a static holder. Gradle runs each package in its own JVM, so each shard gets exactly one merchant.Harness.client()returns a merchant-bound client.Reaches()— for operations the deterministic mock can't fully satisfy (no live acquirer, network tokens, payouts, 3DS provider…), we assert only that the endpoint was reached:4xx= reached/pass,5xxor non-HTTP = fail. CRUD the mock supports (transactions, payment methods, buyers, checkout sessions, merchant accounts, payment services, reports) is asserted as real2xxwith non-empty ids.JsonInterceptorHttpClientinjects an unknownunexpected_field_*into every JSON object response so deserializers are continuously exercised against fields they weren't generated for (GR4VY_NO_INJECT=1to disable).GR4VY_TRACK_HTTP=1the client records method+path per JVM;scripts/endpoint_coverage/EndpointCoverage.javabuilds the operation catalogue from generated source and reports coverage. It's a report, not a gate.Layout
src/test/java/com/gr4vy/sdk/util/—Harness,Reaches,Fixtures,Checkout,Gen, enhancedJsonInterceptorHttpClientflows/— happy-path lifecycles (transaction, buyer, checkout session)processing/— transactions (+events/actions/settlements/refunds), payment methods (+network tokens/PS tokens), buyers (+shipping/gift cards), checkout sessions, gift cards, digital wallets, payment links, catalog, propertybackoffice/— merchant accounts, payment services, 3DS configs/scenarios, reports (+executions), payouts, audit logs, account updaterCI
Sharded by package (
flows/processing/backoffice) with a stableci-completegate so the required check name doesn't churn as shards change, a build + offline matrix on Java 11/17/21, and a coverage PR comment. Fork PRs have no key, so the live suite skips rather than fails.Notes
BaseTest/CheckoutSessionsTestscaffold../gradlew compileTestJava). The live suite needs a sandboxPRIVATE_KEY; coverage closure is verified by the CI coverage comment.🤖 Generated with Claude Code