tmux-amq/tests/test_tmux_integration.py
tegwick 74b2f27997
Some checks failed
tamq-ci / test (push) Failing after 6s
feat: make sessions terminal neutral
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a03397-4d51-7fd1-8ff2-946eb22ea2bc
2026-08-24 20:10:08 +02:00

113 lines
4.2 KiB
Python

import os
import shutil
import sys
import time
from pathlib import Path
from uuid import uuid4
import pytest
from tamq.broker import BrokerIdentity, InputBroker
from tamq.control import ControlModeClient
from tamq.store import Store
from tamq.tmux import LaunchPlan, TmuxManager
@pytest.mark.skipif(shutil.which("tmux") is None, reason="tmux is not installed")
def test_real_tmux_starts_two_repo_windows_and_reuses_them(tmp_path, monkeypatch):
repo_a = tmp_path / "railiance-platform"
repo_b = tmp_path / "activity-core"
repo_a.mkdir()
repo_b.mkdir()
project_src = str(Path(__file__).resolve().parents[1] / "src")
existing_pythonpath = os.environ.get("PYTHONPATH")
monkeypatch.setenv("PYTHONPATH", project_src if not existing_pythonpath else f"{project_src}:{existing_pythonpath}")
monkeypatch.setenv("TAMQ_STATE_DIR", str(tmp_path / "state"))
socket_name = f"tamq-pytest-{os.getpid()}-{uuid4().hex[:8]}"
session = f"tamq-test-{uuid4().hex[:8]}"
manager = TmuxManager(
session,
tmux_command=("tmux", "-L", socket_name),
tamq_command=(sys.executable, "-m", "tamq.cli"),
)
plan = LaunchPlan(
("railiance-platform", "activity-core"),
{"railiance-platform": str(repo_a), "activity-core": str(repo_b)},
("sh", "-c", "printf 'alpha-ready\\n'; exec sleep 30"),
)
try:
endpoint = manager.ensure_plan(plan, tap=True)
assert endpoint.created_session is True
assert endpoint.created_windows == ("railiance-platform", "activity-core")
rows = manager._run(
"list-windows",
"-t",
session,
"-F",
"#{window_name}|#{pane_current_path}|#{pane_pid}",
).splitlines()
parsed = {name: (path, pid) for name, path, pid in (row.split("|", 2) for row in rows)}
assert set(parsed) == {"railiance-platform", "activity-core"}
assert parsed["railiance-platform"][0] == str(repo_a)
assert parsed["activity-core"][0] == str(repo_b)
deadline = time.monotonic() + 5
while time.monotonic() < deadline:
captures = [
manager._run("capture-pane", "-p", "-t", f"{session}:{repo}")
for repo in plan.repos
]
if all("alpha-ready" in capture for capture in captures):
break
time.sleep(0.05)
assert all("alpha-ready" in capture for capture in captures)
reused = manager.ensure_plan(plan, tap=True)
assert reused.created_session is False
assert reused.created_windows == ()
reused_rows = manager._run(
"list-windows",
"-t",
session,
"-F",
"#{window_name}|#{pane_current_path}|#{pane_pid}",
).splitlines()
reused_parsed = {name: (path, pid) for name, path, pid in (row.split("|", 2) for row in reused_rows)}
assert reused_parsed == parsed
assert reused.instance_id == endpoint.instance_id
store = Store(tmp_path / "state" / "tamq.sqlite3")
control = ControlModeClient(
session,
tmux_command=("tmux", "-L", socket_name),
)
try:
message_id = store.add("local", "activity-core", "integration-message")
control.start()
delivered = InputBroker(
store,
BrokerIdentity(endpoint.instance_id, "railiance-platform"),
).deliver_pending(
control,
window_for_repo=lambda repo: f"{session}:{repo}",
)
assert delivered == 1
assert store.list(state="injected")[0]["message_id"] == message_id
deadline = time.monotonic() + 5
while time.monotonic() < deadline:
capture = manager._run(
"capture-pane", "-p", "-t", f"{session}:activity-core"
)
if "#local: integration-message" in capture:
break
time.sleep(0.05)
assert "#local: integration-message" in capture
finally:
control.close()
store.close()
finally:
manager._run("kill-server", check=False)