from pathlib import Path import os import socket from tamq.cleanup import SHIM_MARKER, cleanup_runtime from tamq.cli import main from tamq.store import Store class FakeManager: def __init__(self, command_dir: Path): self.command_dir = command_dir self.identity = (42, "tmux-amq-42-test") self.commands = [] def _existing_session_identity(self): return self.identity def _run(self, *args, check=True): self.commands.append(args) if args[0] == "show-options": return str(self.command_dir) if args[0] == "kill-session": self.identity = None return "" def configure_paths(tmp_path, monkeypatch): state = tmp_path / "state" runtime = tmp_path / "runtime" runtime.mkdir() monkeypatch.setenv("TAMQ_STATE_DIR", str(state)) monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime)) monkeypatch.setenv("TAMQ_SOCKET", str(runtime / "tamq.sock")) monkeypatch.setenv("TMUX_TMPDIR", str(tmp_path / "tmux")) return state, runtime def test_cleanup_is_dry_run_then_removes_only_owned_runtime( tmp_path, monkeypatch ): state, runtime = configure_paths(tmp_path, monkeypatch) command_dir = state / "commands" / "tamq" command_dir.mkdir(parents=True) generated = command_dir / "@audit-core" generated.write_text(f"#!/bin/sh\n{SHIM_MARKER}\n", encoding="utf-8") unrelated = command_dir / "keep-me" unrelated.write_text("operator file\n", encoding="utf-8") for name in ("tamq.sock", "tamq.pid", "tamq.lock"): (runtime / name).write_text("stale\n", encoding="utf-8") tmux_socket_dir = tmp_path / "tmux" / f"tmux-{os.getuid()}" tmux_socket_dir.mkdir(parents=True) stale_tmux_socket = tmux_socket_dir / "tamq-old-test" socket_handle = socket.socket(socket.AF_UNIX) socket_handle.bind(str(stale_tmux_socket)) socket_handle.close() live_tmux_socket = tmux_socket_dir / "tamq-live-test" live_socket_handle = socket.socket(socket.AF_UNIX) live_socket_handle.bind(str(live_tmux_socket)) live_socket_handle.listen() store = Store(state / "tamq.sqlite3") message_id = store.add("a", "b", "preserve me") store.register_endpoint("ep", 42, "tamq", ["a", "b"]) assert store.claim(message_id, "ep") is not None store.close() manager = FakeManager(command_dir) async def not_running(): return False monkeypatch.setattr("tamq.cleanup.ping", not_running) stopped = [] dry_run = cleanup_runtime( apply=False, manager=manager, stop_service=lambda: stopped.append(True), ) assert dry_run["managed_session"] is True assert dry_run["active_endpoints"] == 1 assert dry_run["leases"] == 1 assert dry_run["history_preserved"] == 1 assert dry_run["stale_tmux_socket_count"] == 1 assert generated.exists() assert (runtime / "tamq.sock").exists() assert stale_tmux_socket.exists() assert manager.identity is not None applied = cleanup_runtime( apply=True, manager=manager, stop_service=lambda: stopped.append(True), ) assert applied["errors"] == [] assert stopped == [] assert manager.identity is None assert not generated.exists() assert unrelated.exists() assert not any((runtime / name).exists() for name in ("tamq.sock", "tamq.pid", "tamq.lock")) assert not stale_tmux_socket.exists() assert live_tmux_socket.exists() reopened = Store(state / "tamq.sqlite3") assert len(reopened.list()) == 1 assert reopened.endpoints() == [] assert reopened.db.execute("SELECT COUNT(*) FROM leases").fetchone()[0] == 0 reopened.close() repeated = cleanup_runtime( apply=True, manager=manager, stop_service=lambda: stopped.append(True), ) assert repeated["errors"] == [] assert unrelated.exists() live_socket_handle.close() live_tmux_socket.unlink() def test_cleanup_refuses_unverified_running_service(tmp_path, monkeypatch): state, runtime = configure_paths(tmp_path, monkeypatch) (runtime / "tamq.pid").write_text("41", encoding="utf-8") manager = FakeManager(state / "commands" / "tamq") async def running(): return True async def request(_payload): return {"ok": True, "pid": 42} monkeypatch.setattr("tamq.cleanup.ping", running) monkeypatch.setattr("tamq.cleanup.request", request) stopped = [] report = cleanup_runtime( apply=True, manager=manager, stop_service=lambda: stopped.append(True), ) assert report["errors"] == ["refusing to stop an unverified service PID"] assert stopped == [] assert manager.identity is not None def test_cleanup_stops_verified_service_before_removing_runtime( tmp_path, monkeypatch ): state, runtime = configure_paths(tmp_path, monkeypatch) (runtime / "tamq.pid").write_text("42", encoding="utf-8") manager = FakeManager(state / "commands" / "tamq") liveness = iter((True, False)) async def ping(): return next(liveness) async def request(_payload): return {"ok": True, "pid": 42} monkeypatch.setattr("tamq.cleanup.ping", ping) monkeypatch.setattr("tamq.cleanup.request", request) stopped = [] report = cleanup_runtime( apply=True, manager=manager, stop_service=lambda: stopped.append(42) or 42, ) assert report["errors"] == [] assert stopped == [42] assert manager.identity is None assert not (runtime / "tamq.pid").exists() def test_cleanup_cli_is_dry_run_by_default(monkeypatch, capsys): calls = [] def cleanup_runtime(**kwargs): calls.append(kwargs) return {"errors": [], "apply": kwargs["apply"]} monkeypatch.setattr("tamq.cli.cleanup_runtime", cleanup_runtime) assert main(["cleanup", "--session", "test-session"]) == 0 assert calls[0]["apply"] is False assert calls[0]["session"] == "test-session" assert '"apply": false' in capsys.readouterr().out assert main(["cleanup", "--yes"]) == 0 assert calls[1]["apply"] is True