Q105 pointed beam/CHECK at pytest; pytest is not installed on this interpreter, so the gate exited 2 and ran zero cells. run_lane_tests.py collects TestCase classes (TestLoader) and bare module-level def test_*() (FunctionTestCase) itself, treats an unimportable module and a printed FAIL transcript as faults, and exits 0/1/2. Four test files that imported pytest now use beam_assert.raises/fail and unittest.mock; no cell dropped. Measured: unittest discover 353 tests; runner 570 (353 + 217 bare); bash wizard-work/beam/CHECK rc 0; test_run_lane_tests.py 10 cells OK; 7-mutant battery in scratch copies all as expected (HEAD CHECK rc 2, broken bare rc 1, pytest import rc 1, failing TestCase rc 1, script FAIL rc 1, empty lane rc 2, control rc 0). Record: WORK-QUEUE.md Q128; report wizard-outputs/volt/2026-10-30-q128.md
102 lines
3.0 KiB
Python
102 lines
3.0 KiB
Python
import time
|
|
import threading
|
|
from unittest import mock
|
|
from beam_assert import raises
|
|
from ratelimit import TokenBucket, make_bucket, RateLimitError
|
|
|
|
|
|
def test_basic_burst():
|
|
b = make_bucket(rate=10, capacity=5, clock=lambda: 0.0)
|
|
# capacity 5, all available at t=0
|
|
for _ in range(5):
|
|
assert b.acquire(1, blocking=False) is True
|
|
assert b.acquire(1, blocking=False) is False
|
|
|
|
|
|
def test_refill():
|
|
t = [0.0]
|
|
b = make_bucket(rate=2, capacity=4, clock=lambda: t[0])
|
|
assert b.acquire(4, blocking=False) is True
|
|
assert b.acquire(1, blocking=False) is False
|
|
t[0] = 1.0 # 2 tokens refilled
|
|
assert b.acquire(2, blocking=False) is True
|
|
assert b.acquire(1, blocking=False) is False
|
|
|
|
|
|
def test_acquire_zero():
|
|
b = make_bucket(rate=1, capacity=1, clock=lambda: 0.0)
|
|
assert b.acquire(0) is True
|
|
assert b.tokens() == 1.0
|
|
|
|
|
|
def test_capacity_cap():
|
|
t = [0.0]
|
|
b = make_bucket(rate=10, capacity=3, clock=lambda: t[0])
|
|
t[0] = 100.0
|
|
assert b.tokens() == 3.0 # capped, not 1003
|
|
|
|
|
|
def test_timeout():
|
|
t = [0.0]
|
|
def clock():
|
|
return t[0]
|
|
b = make_bucket(rate=1, capacity=1, clock=clock)
|
|
assert b.acquire(1, blocking=False) is True
|
|
# need 1 more token, refill 1/s; timeout 0.5 -> fail
|
|
ok = b.acquire(1, blocking=True, timeout=0.5)
|
|
assert ok is False
|
|
|
|
|
|
def test_blocking_success_with_fake_sleep():
|
|
# Q128: this cell used pytest's `monkeypatch` fixture, so neither
|
|
# `unittest discover` nor run_lane_tests.py could ever execute it --
|
|
# it was a test no runner in this lane ran. unittest.mock is stdlib
|
|
# and does the same job, so the cell is collected and graded now.
|
|
t = [0.0]
|
|
b = make_bucket(rate=2, capacity=2, clock=lambda: t[0])
|
|
assert b.acquire(2, blocking=False) is True
|
|
# patch time.sleep to advance the bucket's clock
|
|
def fake_sleep(s):
|
|
t[0] += s
|
|
with mock.patch.object(time, "sleep", fake_sleep):
|
|
assert b.acquire(2, blocking=True, timeout=5) is True
|
|
|
|
|
|
def test_n_exceeds_capacity_nonblocking():
|
|
b = make_bucket(rate=1, capacity=2, clock=lambda: 0.0)
|
|
assert b.acquire(5, blocking=False) is False
|
|
|
|
|
|
def test_n_exceeds_capacity_blocking_raises():
|
|
b = make_bucket(rate=1, capacity=2, clock=lambda: 0.0)
|
|
with raises(RateLimitError):
|
|
b.acquire(5, blocking=True)
|
|
|
|
|
|
def test_negative_n():
|
|
b = make_bucket(rate=1, capacity=2, clock=lambda: 0.0)
|
|
with raises(ValueError):
|
|
b.acquire(-1, blocking=False)
|
|
|
|
|
|
def test_thread_safety():
|
|
b = make_bucket(rate=1000, capacity=100, clock=time.monotonic)
|
|
results = []
|
|
def worker():
|
|
for _ in range(50):
|
|
results.append(b.acquire(1, blocking=True))
|
|
threads = [threading.Thread(target=worker) for _ in range(4)]
|
|
for th in threads:
|
|
th.start()
|
|
for th in threads:
|
|
th.join()
|
|
assert all(results)
|
|
assert len(results) == 200
|
|
|
|
|
|
def test_invalid_params():
|
|
with raises(ValueError):
|
|
TokenBucket(rate=0, capacity=1)
|
|
with raises(ValueError):
|
|
TokenBucket(rate=1, capacity=0)
|