Skip to content

feat: sourceBranch, comment, merge, multipart upload and 503 retry - #121

Merged
pashidlos merged 4 commits into
masterfrom
feat/contract-6.0
Nov 2, 2026
Merged

pashidlos merged 4 commits into
masterfrom
feat/contract-6.0

Conversation

@pashidlos

Copy link
Copy Markdown
Member

Brings sdk-java to the phase 2 SDK contract shared by all four SDKs. Builds on Java 11 and Gradle 6.1 like master, so it can be released as a minor before the toolchain PR.

Proposed release: 5.6.0. Nothing public is removed. Merge this before the toolchain PR, which is rebased on top of it.

What changes

Contract row Before Now
sourceBranch missing config option: builder, VRT_SOURCEBRANCH, vrt.json. Sent with every test run, JSON and multipart
comment missing TestRunOptions.comment
merge missing TestRunOptions.merge
multipart (file / bytes) base64 only track(name, Path) and track(name, byte[]) post to /test-runs/multipart. The image is not copied (ofByteArrays), and Content-Length is sent
503 + Retry-After no retry up to 3 retries, each wait min(Retry-After, 60 s). No retry without the header, or for other statuses
413 hints one hint base64 suggests multipart; multipart names MULTIPART_FILE_SIZE_LIMIT
httpTimeoutInSeconds 0 every request failed (IllegalArgumentException) no read limit. Negative values are still rejected

The 7-argument VisualRegressionTrackerConfig constructor is kept. New code uses the builder.

Upgrade note: because of the new track overloads, a call with a literal null or a bare Mockito any() as the image is ambiguous. Use anyString() / any(String.class) instead.

Rows already met (checked against the code)

  • Config: apiUrl, apiKey, project, branchName, ciBuildId, enableSoftAssert, httpTimeoutInSeconds (default 360, connect 10 s). Sources are env VRT_* and vrt.json; precedence per field is builder > env > file.
  • track request: os, browser, viewport, device, customTags, diffTollerancePercent, ignoreAreas, base64.
  • track result:
    • id, status (6 statuses plus UNKNOWN with a warning), and url;
    • imageUrl/diffUrl/baselineUrl via /images/;
    • only NEW and UNRESOLVED fail, and soft assert logs them.
  • Errors:
    • TestRunException.getStatusCode() carries the server's message;
    • hints for 413 and 422;
    • transport errors are the JDK's IOException, which never includes headers, so no apiKey.

Not in this PR

  • An apiUrl with a trailing slash still produces //test-runs. The server accepts it, but sdk-python strips the slash. Worth a follow-up.

Verification

  • ./gradlew check on Java 11: 59 tests. Every new behaviour got a failing test first.
  • A real run against visualregressiontracker/api:6.0.0-rc1, using the compose file from examples-java CI:
    • base64, bytes and Path tracking;
    • comment is stored;
    • after approving on release-*, a build on feature-* with sourceBranch=release-* gets OK instead of NEW;
    • merge=true comes back on the result;
    • a 6.6 MB PNG gets 413 with the multipart hint as base64, and goes through as bytes;
    • a changed image gives UNRESOLVED;
    • stop() ends the build.
  • 503 + Retry-After is covered by unit tests only: the rc1 server's diff queue can't be filled on demand.

🤖 Generated with Claude Code

pashidlos and others added 4 commits November 2, 2026 22:53
- sourceBranch in the config (builder, VRT_SOURCEBRANCH, vrt.json): the branch
  whose baselines a new branch compares against. The 7-argument config
  constructor is kept.
- TestRunOptions.comment and TestRunOptions.merge.
- track(name, byte[]) and track(name, Path) upload through
  POST /test-runs/multipart, which is not bound by BODY_PARSER_JSON_LIMIT.
  The 413 hint names the limit of the endpoint that was used.
- A 503 with Retry-After is retried up to 3 times, waiting at most 60 s each.
- httpTimeoutInSeconds 0 means no read limit instead of failing every request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t hint from the caller

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…etry-After and Content-Length

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Newer JDKs send a body of unknown length chunked, which some proxies refuse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pashidlos
pashidlos merged commit d60a5fe into master Nov 2, 2026
1 check passed
@pashidlos
pashidlos deleted the feat/contract-6.0 branch November 2, 2026 21:30
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.

1 participant