7e18a70796
- Resolve UU conflict in hooks_cli.py: take develop/HEAD approach (mine synchronously via _mine_sync, then pass through unconditionally). _mine_sync already catches subprocess.TimeoutExpired — fixes Copilot #1. - Add tests/test_palace_locks.py: 4 tests covering mine_global_lock non-blocking semantics (acquire, second-acquire raises MineAlreadyRunning, reusable after release, release on exception) — fixes Copilot #4. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""Tests for mine_global_lock: non-blocking cross-process lock semantics."""
|
|
import threading
|
|
|
|
import pytest
|
|
|
|
from mempalace.palace import MineAlreadyRunning, mine_global_lock
|
|
|
|
|
|
def test_mine_global_lock_acquired(tmp_path, monkeypatch):
|
|
"""Lock is acquired and released without error."""
|
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
with mine_global_lock():
|
|
pass # should not raise
|
|
|
|
|
|
def test_mine_global_lock_second_acquire_raises(tmp_path, monkeypatch):
|
|
"""Concurrent second acquire raises MineAlreadyRunning."""
|
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
results: list[str] = []
|
|
|
|
with mine_global_lock():
|
|
# While this lock is held, spawn a thread that tries to acquire.
|
|
def try_acquire():
|
|
try:
|
|
with mine_global_lock():
|
|
results.append("acquired")
|
|
except MineAlreadyRunning:
|
|
results.append("blocked")
|
|
|
|
t = threading.Thread(target=try_acquire)
|
|
t.start()
|
|
t.join(timeout=5)
|
|
|
|
assert results == ["blocked"]
|
|
|
|
|
|
def test_mine_global_lock_reusable_after_release(tmp_path, monkeypatch):
|
|
"""Lock can be re-acquired after the context manager exits."""
|
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
|
|
with mine_global_lock():
|
|
pass # first acquire + release
|
|
|
|
# Second acquire must succeed; MineAlreadyRunning would propagate as failure.
|
|
with mine_global_lock():
|
|
pass
|
|
|
|
|
|
def test_mine_global_lock_exception_still_releases(tmp_path, monkeypatch):
|
|
"""Lock is released even when the body raises."""
|
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
|
|
with pytest.raises(ValueError):
|
|
with mine_global_lock():
|
|
raise ValueError("boom")
|
|
|
|
# Must be acquirable again after the exception.
|
|
with mine_global_lock():
|
|
pass
|