39 lines
1.5 KiB
Python
39 lines
1.5 KiB
Python
|
|
"""warm_cities.py's cross-process single-instance guard (LOCK_PATH + the
|
||
|
|
core/singleton.py flock it reuses) -- an overlapping deploy launching a second
|
||
|
|
copy while the first is still warming must stand down, not double-spend
|
||
|
|
archive-fetch quota."""
|
||
|
|
import fcntl
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
|
||
|
|
import warm_cities
|
||
|
|
|
||
|
|
|
||
|
|
def test_lock_path_lives_under_data_dir():
|
||
|
|
assert os.path.dirname(warm_cities.LOCK_PATH) == warm_cities.paths.DATA_DIR
|
||
|
|
assert os.path.basename(warm_cities.LOCK_PATH) == "warm_cities.lock"
|
||
|
|
|
||
|
|
|
||
|
|
def test_second_instance_stands_down_and_exits_zero(tmp_path):
|
||
|
|
"""With the lock already held (simulating an overlapping deploy invocation), a
|
||
|
|
second run of the script must log and exit 0 immediately -- never reaching
|
||
|
|
main()'s network/parquet-write path."""
|
||
|
|
lock = str(tmp_path / "warm_cities.lock")
|
||
|
|
fd = os.open(lock, os.O_RDWR | os.O_CREAT, 0o644)
|
||
|
|
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||
|
|
try:
|
||
|
|
env = dict(os.environ, THERMOGRAPH_DATA_DIR=str(tmp_path))
|
||
|
|
# If the guard didn't work, this would try a real network fetch (or hang)
|
||
|
|
# instead of returning almost instantly with exit code 0.
|
||
|
|
result = subprocess.run(
|
||
|
|
[sys.executable, warm_cities.__file__, "--limit", "0"],
|
||
|
|
cwd=os.path.dirname(os.path.abspath(warm_cities.__file__)),
|
||
|
|
env=env, capture_output=True, text=True, timeout=20,
|
||
|
|
)
|
||
|
|
assert result.returncode == 0
|
||
|
|
assert "already running" in result.stdout
|
||
|
|
finally:
|
||
|
|
fcntl.flock(fd, fcntl.LOCK_UN)
|
||
|
|
os.close(fd)
|