Skip to content

test: synchronize stream cancellation test on an event instead of a sleep - #188

Merged
lesnik512 merged 1 commit into
mainfrom
claude/vigilant-boyd-a65bd3
Oct 17, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
claude/vigilant-boyd-a65bd3

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #187

Problem

test_cancellation_propagates_cleanly in tests/test_client_stream.py started consume(), slept 10 ms, and cancelled. It assumed two things about timing: that the consumer had read the first chunk by then, and that the body's asyncio.sleep(1.0) was still running when the cancel arrived.

Reproduction (before)

On origin/main (b9e2861), with scratch copies of the test file:

  • Waiting 1.1 s before task.cancel() stands in for a stall longer than the body's hold. The body finished, consume() returned, and the test failed with DID NOT RAISE CancelledError.
  • Dropping the wait entirely cancels the task before it reads anything. The test still passed, so it could not tell a mid-body cancel from a cancel before the request.

Fix

The body sets first_chunk_consumed after its first yield, which only resumes once the consumer has taken that chunk and asked for the next one. It then waits on an asyncio.Event that is never set, so it holds until cancelled however long the test takes. The test waits on first_chunk_consumed (inside a 5 s asyncio.timeout that only guards against a hang) before cancelling. No sleep is involved in correctness.

With the fix, the 1.1 s stall copy passes. On an 8-core Mac with 16 yes > /dev/null processes running, pytest tests/test_client_stream.py -k cancellation --count 2000 passed 2000 of 2000.

Other timed sleeps in tests/

None outside the bulkhead tests share the flaw. test_timeout.py sleeps 5 s against a 0.01 s timeout, and the timeout callback is due first even after a stall. The retry tests inject a recording _sleep. test_threading_with_shared_budget.py passes real asyncio.sleep as the retry backoff, which affects speed only. test_circuit_breaker.py and test_circuit_breaker_props.py use sleep(0) to yield. tests/test_client_stream_sync.py has no cancellation test and no sleeps.

Checks

just lint, just lint-ci and just test-ci pass locally (1307 tests, 100% coverage).

…leep

test_cancellation_propagates_cleanly slept 10 ms and assumed body consumption had begun and that the body's 1 s sleep was still running when it cancelled. A stall over 1 s let the body finish, and a cancel before consumption began still passed. The body now signals once the first chunk is consumed and then waits on an event that is never set.
@lesnik512
lesnik512 merged commit eb4b2d2 into main Oct 17, 2026
13 checks passed
@lesnik512
lesnik512 deleted the claude/vigilant-boyd-a65bd3 branch October 17, 2026 11:20
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.

test_cancellation_propagates_cleanly synchronizes on a sleep

1 participant