Skip to content

Commit 9d7a142

Browse files
test(requestlog): make the byte-budget drain test independent of runner speed
My own test, and it broke the release build. CI reported `assert 239800 == 0` on the very commit that was supposed to ship v1.11.0, so no image was pushed and the tag and release were never cut. The test drained a 50-row queue with `batch_size=100` and `flush_ms=10`, then asserted the byte counter was back to zero. `_collect()` stops at whichever comes first, `batch_size` rows or the flush deadline - and with a batch size larger than the row count, the deadline is the only thing that can end it. It was measuring the scheduler, not the sink. The arithmetic is exact: a row here weighs 1400 + 4096 + 4096 = 9592 bytes, and 239 800 is 25 of them. `_collect()` returned half the queue because 25 iterations of `asyncio.wait_for` were enough to exhaust 10 ms on that runner. The workflow builds `linux/amd64,linux/arm64`, so one of the two runs under qemu emulation; a local `docker build` compiles the native platform only and never sees that path. I could not reproduce the failure even building both platforms here - this machine fits 49 iterations inside 10 ms - which is the point: a test whose result depends on how fast the host is will pass everywhere it is convenient and fail where it matters. Fixed structurally rather than by widening the window: `batch_size` now EQUALS the row count, so the collect loop exits on the count and never consults the deadline at all. The flush window is generous as a backstop, the drain runs in a loop instead of a single call, and the row count is asserted on the way in and on the way out so a future change cannot make it vacuous. Verified on both platforms the workflow builds: 1667 passed / 152 skipped on linux/arm64 and on linux/amd64 under emulation. No production code changes.
1 parent 5f995d9 commit 9d7a142

1 file changed

Lines changed: 29 additions & 5 deletions

File tree

backend/tests/test_request_log_fleet_scale.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,16 +278,40 @@ def test_queue_memory_is_bounded_even_at_the_max_body_size_ceiling():
278278
)
279279

280280

281+
_DRAIN_ROWS = 50
282+
283+
281284
def test_the_byte_budget_is_released_as_rows_drain():
282-
"""A budget that only ever counts up is a slow leak, not a limit."""
285+
"""A budget that only ever counts up is a slow leak, not a limit.
286+
287+
Deliberately time-INDEPENDENT. `_collect()` stops at whichever comes first,
288+
`batch_size` rows or the `flush_ms` deadline, so a batch size larger than
289+
the row count makes the result a function of how fast the runner happens to
290+
be. The first version of this test used batch=100/flush=10ms for 50 rows and
291+
passed on a native build while failing in CI, which builds
292+
linux/amd64 + linux/arm64 and therefore runs one of them under qemu
293+
emulation: 25 iterations of `asyncio.wait_for` were enough to exhaust 10 ms
294+
there, `_collect()` returned half a batch, and the assertion read
295+
`239800 == 0` - measuring the scheduler, not the sink.
296+
297+
So: batch size EQUAL to the row count, so the loop exits on the count and
298+
never consults the deadline; a generous flush window in case it somehow
299+
does; and a drain loop rather than a single call. Nothing here depends on
300+
wall-clock speed.
301+
"""
283302
async def drain():
284-
sink = RequestLogSink(2000, 100, 10, max_bytes=8 * 1024 * 1024)
303+
sink = RequestLogSink(2000, _DRAIN_ROWS, 5000, max_bytes=8 * 1024 * 1024)
285304
blob = b"x" * 4096
286305
set_config(replace(get_config(), capture_agent_success=True))
287-
for _ in range(50):
306+
for _ in range(_DRAIN_ROWS):
288307
sink.offer(_row(target=None, request_body_raw=blob, response_body_raw=blob))
289-
assert sink.stats["queued_bytes"] > 0
290-
await sink._collect()
308+
assert sink.stats["queued_bytes"] > 0, "nothing was queued, so nothing is being measured"
309+
assert sink._queue.qsize() == _DRAIN_ROWS, "the queue did not take every row"
310+
311+
drained = 0
312+
while not sink._queue.empty():
313+
drained += len(await sink._collect())
314+
assert drained == _DRAIN_ROWS, f"drained {drained} of {_DRAIN_ROWS} rows"
291315
return sink.stats["queued_bytes"]
292316

293317
assert asyncio.run(drain()) == 0

0 commit comments

Comments
 (0)