feat(sdk-generator): emit SSE contract tests in the contract-tests backend (TS + Python) - #47
Merged
Merged
Conversation
…ckend (TS + Python) Previously emitStreamContractTestFile was only wired into the channel-harness sample — so SDK regens (contract-tests-ts/py) shipped the generated stream() methods with no contract test. Wire SSE coverage into generateContractTests itself, for both backends. - method-chain-builder: add buildStreamCalls (the streaming inverse of buildMethodCalls), sharing the resource walk so streaming ops get the same accessor chains (client.v1.ai.chat.completions.stream). - typescript-emitter: emit __tests__/contract/streams/<resource>.contract.test.ts — construct PlatformClient pointed at the harness, registerStreamScenario with autoEmit (harness synthesizes contract-valid event payloads, resolving $refs), iterate stream(), assert event order; plus a non-2xx -> ApiError case. - python-emitter: emit tests/contract/streams/test_<resource>.py — same shape over AsyncPlatformClient.stream(). - Both gated by the existing opt-in env (ARCHASTRO_RUN_CHANNEL_CONTRACT_TESTS): excluded from the default test run + the harness subprocess boots when the spec has channels OR streams. These run green once their deps land: runtime streamSSE/stream_sse (archastro-js #34 / archastro-python #28) and registerStreamScenario on the harness client (TS: shipped in this PR's channel-harness; Python: phx_channel harness.py). Generator suite 299; channel-harness 63. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bumped) The v0.6.0 release bumped @archastro/sdk-generator, but channel-harness still pinned ^0.5.0 — which 0.6.0 doesn't satisfy — so a fresh `npm ci` pulled the published 0.5.6 (pre-SSE-contract-test exports, missing emitResourceFile) instead of linking the workspace, breaking the pretest. Bump to ^0.6.0 and `npm dedupe` so it links the workspace 0.6.0 (minimal lockfile change). Note: this caret keeps drifting whenever sdk-generator's version bumps — the release process should bump this dependency in lockstep (the two packages are co-released). Verified: npm ci links the workspace, cold Node 20 run is green (channel-harness 63, sdk-generator 299). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Follow-up to #43 (merged). #43 landed SSE method emission, typed events, the channel-harness SSE support, and the sample contract-test loop — but the contract-tests backend that the SDK repos regenerate from (
--lang contract-tests-ts/py) still skipped streaming ops, so SDK regens shipped the generatedstream()methods with no contract test. This wires SSE coverage intogenerateContractTestsitself, for both backends.method-chain-builder: addbuildStreamCalls— the streaming inverse ofbuildMethodCalls, sharing the resource walk so streaming ops get the same SDK accessor chains (client.v1.ai.chat.completions.stream).__tests__/contract/streams/<resource>.contract.test.ts: constructPlatformClientagainst the harness,registerStreamScenariowithautoEmit(the harness synthesizes contract-valid event payloads, resolving$refs — no SDK-side fixtures needed), iteratestream(), assert the event order; plus a non-2xx →ApiErrorcase.tests/contract/streams/test_<resource>.py: same shape overAsyncPlatformClient.stream().ARCHASTRO_RUN_CHANNEL_CONTRACT_TESTS): excluded from the default run, and the harness subprocess boots when the spec has channels or streams.sequenceDiagram participant T as generated streams test participant H as harness control API participant C as PlatformClient.stream() participant S as harness SSE endpoint T->>H: registerStreamScenario(autoEmit each event) T->>C: for await ev of client.v1.ai.chat.completions.stream(input) C->>S: POST text/event-stream S-->>C: event frames (synthesized, contract-valid) C-->>T: {event, data} ... assert event orderScope
Generator-only (archastro-openapi). No runtime/SDK changes here.
Risk
Low. Additive: a new builder function + new emitted files behind the existing opt-in gate. The default contract-test run (REST, Prism-backed) is unchanged. Generator suite 299 (incl. 3 new tests covering TS + Python emission + the gating).
Testing
tscclean.streams/ai.contract.test.ts(client.v1.ai.chat.completions.stream(...), autoEmit ×6, assert order, 402→ApiError) andtests/contract/streams/test_ai.py(async equivalent).Runs green once deps land (unchanged from #43's follow-ups)
These tests are opt-in (excluded by default), so they don't affect CI. To execute:
streamSSE/stream_sse— archastro-js [codex] feat(sdk-generator): propagate OpenAPI docs into SDKs #34, archastro-python feat(python): emit response_type so generated calls deserialize into Pydantic models #28.registerStreamScenarioon the harness client — TS: shipped via channel-harness (in feat(sdk-generator): emit SSE streaming methods for x-sdk-streaming #43); Python: needs adding toarchastro-python'sphx_channel/harness.py.