Replace your mocked Sora client with a Sume contract test
Tests that mocked a Sora client now guard nothing. Write a small pytest contract test around your own video interface, plus one live smoke test against Sume.

If your test suite mocked a Sora client, those tests now prove only that your mock still works. Replace them with two layers. First, a contract test against your own video interface using recorded Sume response shapes from the video generation docs: submit returns an id, polling_url and pending, and polling ends in completed with unsigned_urls or in failed. Second, one opt-in live smoke test that spends real money and runs only with a key set.
What each layer owns
Keep the layers distinct so a flaky network never fails the main suite.
| Layer | Network | Checks | When it runs |
|---|---|---|---|
| Unit with fixtures | None | Request building, status mapping, error mapping | Every commit |
| Contract fixtures | None | Docs-shaped responses parse into your types | Every commit |
| Live smoke | Sume API | One short job completes and returns a URL | Nightly or manual |
The fixtures to write
Copy the shapes from the docs, not from memory: the 202 submit response, a poll response mid-job, a completed poll with unsigned_urls and usage.cost, a failed poll with an error, and the error envelope for 402 and 429 from the errors guide. Name each fixture for the behavior it proves.
A pytest sketch
This test feeds a fake poll sequence into a status-mapping function you own. It is runnable as written once placed in a file.
def map_status(s):
return {"pending": "queued", "in_progress": "running",
"completed": "done", "failed": "failed",
"cancelled": "failed", "canceled": "failed"}[s]
def test_poll_sequence_ends_done():
seq = ["pending", "in_progress", "in_progress", "completed"]
assert [map_status(s) for s in seq][-1] == "done"
def test_unknown_status_raises():
import pytest
with pytest.raises(KeyError):
map_status("mystery")The live smoke test
Gate it with an environment check so it skips without a key. Submit one short, low-resolution job with an Idempotency-Key, poll the job status with backoff, and assert you reached completed with a downloadable URL. Keep the prompt trivial: the test checks the plumbing, not the model quality. Expect it to take minutes and to cost real money, so run it nightly rather than per commit.
Sources
Related posts
More in Developers
- Reproduce the same AI voiceover later: model id, voice, settings
To redo a narration line months later you need the model id, voice, language, format and settings. Sume's completed TTS job records them. A short routine.
- defer_loading and tool search for Sume's MCP tools
Set defer_loading: true on the Sume MCP tool so OpenAI tool search loads definitions on demand, then use tools_list and tools_schema for details.
- Wire an OpenAI mcp_approval_response to a Sume spend cap
When a person approves an mcp_approval_request, reuse the approved dollar amount as max_spend_usd on the Sume call so the approval and the cap match.
- require_approval never with tool_names for Sume read tools
Use the object form of require_approval to skip approval only for Sume read tools like account_me, and keep every paid tool on the approval path.
Written by Sume