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.
- Restyle burned-in captions without transcribing twice
Pass source_caption_id instead of video_url to re-burn a video under a new Sume caption style. Word timings are reused, so no second speech-to-text runs.
- Resume an Omni batch after a crash with stable idempotency keys
A worker dies halfway through 40 Omni clips. Build Idempotency-Key from the item id so a rerun resubmits safely, and treat 409 and 429 as signals, not failures.
- Retrain a cloned voice without breaking old videos
HeyGen keeps a voice ID when a clone is retrained. On Sume, an avatar is referenced by a stable handle, and each text-to-speech job records its voice and model.
Written by Sume