Initial commit

This commit is contained in:
LZH-YS1998
2026-07-01 17:56:31 +08:00
commit d78931979d
731 changed files with 311088 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
"""Concurrency tests for the _config_lock pattern used in P2.
The real WSHandler requires a full engine/store/ws stack to boot, which makes
a pure-unit concurrency test prohibitively heavy. Instead we test the *pattern*
applied in P2 — a single asyncio.Lock serializing any number of mixed
`add_role` and `reorg_decide` style coroutines — and assert:
- Every operation completes (20 ops in our case).
- `asyncio.Lock` never produces a RuntimeError ("lock already held") — which
would indicate same-task reentry.
- The log shows strictly interleaved entries (no two tasks recorded an
"inside-lock" line between each other's enter/exit).
- The whole batch completes well under the 10s budget.
Evidence: ws_handler.py:175 defines `self._config_lock = asyncio.Lock()`.
P2 wraps `_handle_reorg_decide`, `_handle_set_mode`, and the `company_profile`
swap under this same lock. The proof of no deadlock is static (D4 in the plan);
this test is a dynamic smoke that the cooperative-locking behavior holds.
"""
from __future__ import annotations
import asyncio
import time
import pytest
@pytest.mark.asyncio
async def test_add_role_and_reorg_decide_serialized():
"""20 mixed ops share one lock; no exceptions, no deadlock, finishes fast."""
lock = asyncio.Lock()
# Event log records enter/exit around the critical section so we can verify
# the lock serialized the body. If two tasks ever interleaved between an
# enter and its matching exit, the test fails.
log: list[tuple[str, str]] = [] # (op, phase)
async def guarded(op: str) -> None:
async with lock:
log.append((op, "enter"))
# Yield to event loop so other tasks get a chance to observe
# whether they see an "inside-lock" window (they should not).
await asyncio.sleep(0)
log.append((op, "exit"))
started = time.monotonic()
tasks = []
for i in range(10):
tasks.append(asyncio.create_task(guarded(f"add_role:{i}")))
tasks.append(asyncio.create_task(guarded(f"reorg_decide:{i}")))
results = await asyncio.gather(*tasks, return_exceptions=True)
elapsed = time.monotonic() - started
exceptions = [r for r in results if isinstance(r, BaseException)]
assert exceptions == [], f"Unexpected exceptions: {exceptions}"
# Every op must produce exactly one enter + one exit.
assert len(log) == 40, f"Expected 40 log entries (20 ops × 2), got {len(log)}"
# Verify lock-mutual-exclusion: iterating the log, each enter must be
# immediately followed by the SAME op's exit (no interleave).
i = 0
while i < len(log):
assert log[i][1] == "enter", f"Expected enter at index {i}, got {log[i]}"
assert log[i + 1] == (log[i][0], "exit"), (
f"Enter for {log[i][0]} was not immediately followed by its exit; "
f"saw {log[i + 1]} — indicates lock was not held across the body."
)
i += 2
# Counts must balance.
add_role_count = sum(1 for (op, phase) in log if phase == "enter" and op.startswith("add_role"))
reorg_count = sum(1 for (op, phase) in log if phase == "enter" and op.startswith("reorg_decide"))
assert add_role_count == 10
assert reorg_count == 10
# 10s budget; a correct cooperative-lock implementation finishes in <1s.
assert elapsed < 10.0, f"Test took {elapsed:.2f}s, exceeded 10s budget"
@pytest.mark.asyncio
async def test_lock_is_not_reentrant_from_same_task():
"""asyncio.Lock must NOT be re-acquirable from the same task (would deadlock).
This is the invariant that the P2 plan relied on (D4 deadlock proof): if any
code path under `_handle_reorg_decide` re-acquired `_config_lock` we'd
deadlock. Here we verify the Lock primitive's behavior — the test passes
only when a re-acquire attempt blocks forever (we force it to time out).
"""
lock = asyncio.Lock()
async def try_reentrant():
async with lock:
# Attempting to acquire again from the same task must block.
try:
await asyncio.wait_for(lock.acquire(), timeout=0.2)
except asyncio.TimeoutError:
return "blocked_as_expected"
# Only reach here if stdlib ever became reentrant (it is not).
lock.release()
return "unexpected_reentry"
outcome = await try_reentrant()
assert outcome == "blocked_as_expected", (
f"Expected asyncio.Lock to block on same-task re-acquire, got {outcome}"
)