Skip to content

Phase 5: generated-client vs generated-server integration harness - #13

Merged
aaylward merged 1 commit into
mainfrom
claude/smithy-cpp-generator-plan-fpeqzt
Jul 7, 2026
Merged

aaylward merged 1 commit into
mainfrom
claude/smithy-cpp-generator-plan-fpeqzt

Conversation

@aaylward

@aaylward aaylward commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Phase 5: the integration harness

The headline requirement from the plan — generated clients integration-test generated servers — now generates automatically for every fixture module (integrationTests plugin setting / --integration-tests runner flag): tests/integration_test.cc, in which the module's own generated client drives its own generated server over both the in-memory loopback and a real socket on an ephemeral port, with identical parameterized test bodies.

Coverage matrix (per operation)

  • Seeded random round-trips (8 iterations): a generated ScriptedHandler records the parsed input and answers with a scripted output, so both wire directions are asserted independently with operator== — client serialize → server parse, and server serialize → client parse.
  • Maximal row: every optional member set, containers at max size.
  • One test per modeled error: a random typed detail must survive the wire (code, kind, and full detail equality).
  • Unknown-response-member tolerance: a new smithy::testing::MutatingTransport injects an unknown member into document-map response bodies; clients must ignore it.

Random values

RandomValueGenerator emits constraint-valid, wire-exact Random<Shape>(Rng&) builders: pattern strings use fixed Java-checked candidates, numbers respect @range with boundary bias (min/max come up 10% each), @uniqueItems lists stay distinct, @idempotencyToken members are always set (the client would auto-fill and break request equality), timestamps are whole seconds (http-date precision), floats are dyadic eighths (exact in JSON/CBOR at both widths), and engaged containers are never empty. The Rng is seeded, so failures reproduce deterministically. UBSan immediately earned its keep by catching an int64 span overflow in the first version of the generated Rng.

Fixture corpus

New examples/roundtrip kitchen-sink model generated in both protocol variants from shared shapes: RoundTripRest (every supported HTTP binding at once — label, query, headers, prefix headers, blob and structure payloads, documents, all three timestamp formats, sparse/unique lists, unions, both error classes) and RoundTripRpc (the same shapes over CBOR). Weather and cafe get integration suites too — four suites, 42 test cases, each running in both transport modes.

Mutation check (exit criterion)

Deliberately corrupting a generated serializer (1 + value.precise in the roundtrip serde) fails the suite on the spot; regenerating restores green. Documented as the ongoing practice in docs/design/integration-testing.md.

CI

bazel test //... already runs on Linux gcc/clang, macOS, and Windows plus a clang ASan+UBSan job on every PR — that matrix now includes all four integration suites in both transport modes, exceeding the plan's nightly-sanitizer requirement.

Validation

  • bazel test //...: 37/37 green (gcc and clang --config=asan --config=ubsan)
  • gradle build (codegen unit tests incl. byte-determinism) green; goldens regenerated with zero drift
  • clang-format / clang-tidy / buildifier clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01WjaNFwBZxoHdqagvq8ycQf


Generated by Claude Code

Every fixture module now ships a generated tests/integration_test.cc
(behind the new integrationTests plugin setting / --integration-tests
runner flag): the module's own generated client drives its own generated
server over BOTH the in-memory loopback and a real socket on an
ephemeral port, with identical parameterized test bodies.

Coverage matrix per operation:
- Seeded random round-trips (8 iterations): a ScriptedHandler records
  the parsed input and answers with a scripted output, so client
  serialize -> server parse and server serialize -> client parse are
  asserted independently with operator==.
- A maximal row: every optional member set, containers at max size.
- One test per modeled error: a random typed detail must survive the
  wire (code, kind, full detail equality).
- Unknown-response-member tolerance: a new
  smithy::testing::MutatingTransport injects an unknown member into
  document-map response bodies; clients must ignore it.

RandomValueGenerator emits constraint-valid, wire-exact Random<Shape>
builders: pattern strings use fixed Java-checked candidates, numbers
respect @range with boundary bias, @Uniqueitems lists stay distinct,
@idempotencyToken members are always set, timestamps are whole seconds,
floats are dyadic eighths, and engaged containers are never empty.
UBSan immediately earned its keep by catching an int64 span overflow in
the first version of the generated Rng.

Fixture corpus: new examples/roundtrip kitchen-sink model generated in
BOTH protocol variants from shared shapes - RoundTripRest (every
supported HTTP binding at once: label, query, headers, prefix headers,
blob and structure payloads, documents, all three timestamp formats,
sparse/unique lists, unions, both error classes) and RoundTripRpc (the
same shapes over CBOR).

Mutation-checked: corrupting a generated serializer (1 + value.precise)
fails the suite on the spot; regenerating restores green. CI already
runs the full matrix (Linux gcc/clang, macOS, Windows + ASan/UBSan) on
every PR, which now includes all four integration suites in both
transport modes. Docs: docs/design/integration-testing.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjaNFwBZxoHdqagvq8ycQf
@aaylward
aaylward merged commit 8c90595 into main Jul 7, 2026
7 checks passed
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