test: shave register/shutdown/TC waits on loopback#1711
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1711 +/- ##
=======================================
Coverage 99.76% 99.76%
=======================================
Files 33 33
Lines 3426 3427 +1
Branches 471 471
=======================================
+ Hits 3418 3419 +1
Misses 5 5
Partials 3 3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
all the windows TC tests fail with this pr try harder |
PR Review — test: shave register/shutdown/TC waits on loopbackMechanics are clean and the speedups are real: extracting 🟢 Suggestions1. Verify 0.1s timeout headroom on slow CI/PyPy (`tests/utils/test_asyncio.py`, L68)Both the Checklist
SummaryMechanics are clean and the speedups are real: extracting |
The Windows failure is almost certainly the combination of two compounding factors in
Two options to fix:
I'd lean toward the second — it preserves the speedup intent of the PR without making the cleanup poll do double duty as a slack budget for scheduler jitter. |
`async_check_service` paid an inline `random.randint(150, 250)` ms wait on every `register_service` — RFC 6762 §8.1 thundering-herd avoidance for real networks, pure overhead on 127.0.0.1. Extracted as a module constant `_REGISTER_RANDOM_INTERVAL` and patched in the `quick_timing` fixture to (1, 5)ms alongside the existing _CHECK_TIME / _REGISTER_TIME / _UNREGISTER_TIME shaves. Also: - `test_shutdown_loop`: drop `.result(1)` → `.result(0.1)` and patch `_TASK_AWAIT_TIMEOUT` to 0.1s. The 1s waits were `shutdown_loop`'s outer timeout on a never-completing `asyncio.sleep(5)` — the test only needs the loop to be stoppable while a task is pending. - `test_tc_bit_defers_last_response_missing`: patch `_TC_DELAY_RANDOM_INTERVAL` (400-500ms, RFC 6762 §7.2 TC-bit deferral) to (10, 20)ms and tighten the cleanup poll loop. - `test_integration`: wait for the browser's first startup query to fire (with empty cache) before registering. Previously the test relied on the register's 150-250ms random wait being longer than the browser's 20-120ms first-query delay; with the new fast register that race flipped and the first query started seeing the known PTR via §7.1 known-answer suppression. Speedups on loopback (CPython 3.12): | test | before | after | | ----------------------------------------------------- | ------ | ----- | | test_shutdown_loop | 1.16s | 0.26s | | test_tc_bit_defers_last_response_missing | 0.79s | 0.32s | | test_async_service_registration_name_conflict | 0.72s | 0.10s | | test_name_conflicts | 0.50s | 0.10s | Plus a smaller transparent shave on every other `quick_timing` register-based test. Full suite: 338 passed, 2 skipped. No production behavior change — `_REGISTER_RANDOM_INTERVAL` still defaults to the RFC 6762 §8.1 value on real networks.
…ot fire the timer mid-assertion
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
ca16a07 to
6b84b72
Compare
The root cause is almost certainly Windows' default timer resolution. CPython's Two viable fixes:
Option 1 is the cleaner call — it keeps the test exercising the same code path on all platforms, just with a wider RFC 6762 §7.2 defer window that all OS timer resolutions can resolve. The poll loop's cleanup window would need to widen correspondingly to stay above the upper bound. The diff snippet you pasted shows the patch is applied at function level — that's the right scope, just needs a Windows-safe value. |
What
Speed up four slow tests by extracting one production constant (
_REGISTER_RANDOM_INTERVAL, the RFC 6762 §8.1 random pre-probe wait inasync_check_service) and patching it throughquick_timingon loopback, plus three localised test-only patches.Part of #1707.
Why
async_check_servicewaits a random 150-250ms before probing — RFC 6762 §8.1 thundering-herd avoidance for real networks, pure overhead on 127.0.0.1. Tests that usequick_timingalready get probe/announce/goodbye intervals shrunk, but the inlinerandom.randinton this path is opaque to patching. Three of the slowest tests in #1707 without an in-flight PR (test_async_service_registration_name_conflict,test_name_conflicts, and everything that registers a service) pay this for nothing.test_shutdown_loopandtest_tc_bit_defers_last_response_missingcarry similar dead waits — a 1s outer timeout inshutdown_loopagainst a never-completing pending task, and an 800ms cleanup poll against a 400-500ms RFC 6762 §7.2 TC-bit defer timer.How
_REGISTER_RANDOM_INTERVAL = (150, 250)as a module-level constant in_core.pyand patch it inquick_timingalongside the other loopback shaves. No production change — default still matches the RFC value.test_shutdown_loop: patch_TASK_AWAIT_TIMEOUTto 0.1s and drop.result(1)→.result(0.1). Both were just upper bounds on a never-completing pending task.test_tc_bit_defers_last_response_missing: patch_TC_DELAY_RANDOM_INTERVALto (10, 20)ms and tighten the cleanup poll loop.test_integration: wait for the browser's first startup query to fire (cache empty) before registering. The original test relied on the 150-250ms register-random-wait being longer than the browser's 20-120ms first-query delay; with the new fast register that race flipped and the first query started picking up the known PTR via §7.1 known-answer suppression.Speedups (CPython 3.12, loopback)
test_shutdown_looptest_tc_bit_defers_last_response_missingtest_async_service_registration_name_conflicttest_name_conflictsPlus a smaller transparent shave on every other
quick_timing-using test that registers a service.Test plan
tests/suite passes (338 passed, 2 skipped, ~47s wall)Quality Report
Changes: 6 files changed, 31 insertions(+), 12 deletions(-)
Code scan: clean
Tests: passed (4 PASSED)
Branch hygiene: clean
Generated by Kōan post-mission quality pipeline