Unit test a transcription retry loop with a fake 429 in Python

Test your Sume STT retry code without calling the API: inject the POST and sleep, return a 429 with retry-after, and assert the same key is sent twice.

4 min readSume
All posts

You can test a Sume transcription retry loop without the network by passing the HTTP call and the sleep function in as arguments. A fake post returns (429, {"retry-after": "2"}) and then (202, {}); the test asserts that the loop slept 2.0 seconds and sent the same Idempotency-Key both times. Those two assertions are the contract in Errors and rate limits and Jobs and results: honor retry-after, and retry with the same key so no second paid job is created. Read 2026-10-06.

What to assert

A retry loop has three behaviors worth pinning down. Anything beyond that is testing the standard library.

Retry behaviors to test, from the rules in Errors and rate limits (docs.sume.com), read 2026-10-06.
BehaviorAssertion
Waits as toldThe sleep argument equals the retry-after header
Same intent, same keyEvery attempt sends the identical key
BoundedAfter tries attempts the function returns None

The code and its tests

Save it as ut2.py and run python -m unittest ut2. Both tests pass in a few milliseconds because nothing sleeps.

import time, unittest


def submit_with_retry(post, key, sleep=time.sleep, tries=5):
    for _ in range(tries):
        status, headers = post(key)
        if status == 429:
            sleep(float(headers.get("retry-after", "5")))
            continue
        return status


class RetryTest(unittest.TestCase):
    def test_retry_keeps_the_key(self):
        keys, naps = [], []
        replies = iter([(429, {"retry-after": "2"}), (202, {})])

        def post(key):
            keys.append(key)
            return next(replies)

        self.assertEqual(submit_with_retry(post, "stt-1", sleep=naps.append), 202)
        self.assertEqual((keys, naps), (["stt-1", "stt-1"], [2.0]))

    def test_gives_up(self):
        post = lambda key: (429, {})
        self.assertIsNone(submit_with_retry(post, "k", sleep=lambda s: None, tries=3))

Wiring the real call in

In production, pass a post that wraps requests.post and returns (response.status_code, response.headers). The loop does not care where the numbers come from, which is what makes it testable.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume