pm imported runtime_state's private helpers (_lock, _atomic_bytes, _bytes, _digest) at a dozen sites while runtime_state imports pm.environments at module top. The primitives are pm's: move them into the stdlib-only pm.filesystem as lock_fd, durable_write_bytes, read_bytes_or_none and file_digest, and repoint every pm caller. runtime_state keeps the private names only as import aliases: it still calls them through its own globals, and pre-PM updaters load them by these names mid-swap (tests/compat/old_updater_surface.json). Boot-subset test fixtures now copy pm/filesystem.py, since runtime_state imports it at process boot; worker-injection tests patch the name pm.publication now reads.
33 lines
1015 B
Python
33 lines
1015 B
Python
"""A writer queued behind the store lock says so instead of blocking silently."""
|
|
import os
|
|
import threading
|
|
import time
|
|
|
|
from pm.filesystem import lock_fd
|
|
from pm.store import Store
|
|
|
|
|
|
def test_install_lock_reports_what_it_waits_on(tmp_path, capsys):
|
|
store = Store(tmp_path / "store")
|
|
store.root.mkdir()
|
|
holder = os.open(store.root / ".install.lock", os.O_CREAT | os.O_RDWR, 0o600)
|
|
assert lock_fd(holder, wait=False)
|
|
entered = threading.Event()
|
|
|
|
def contend():
|
|
with store.install_lock():
|
|
entered.set()
|
|
|
|
waiter = threading.Thread(target=contend, daemon=True)
|
|
waiter.start()
|
|
deadline = time.monotonic() + 15
|
|
err = ""
|
|
while "waiting for" not in err and time.monotonic() < deadline:
|
|
time.sleep(0.1)
|
|
err += capsys.readouterr().err
|
|
assert str(store.root / ".install.lock") in err
|
|
assert not entered.is_set()
|
|
os.close(holder)
|
|
assert entered.wait(timeout=10), "the message must not replace the wait"
|
|
waiter.join(timeout=5)
|