Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a03397-4d51-7fd1-8ff2-946eb22ea2bc
This commit is contained in:
parent
398fe316b4
commit
e995cab1b8
12 changed files with 391 additions and 42 deletions
|
|
@ -13,6 +13,16 @@ def test_help_and_version(capsys):
|
|||
assert "usage:" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_root_help_exposes_repository_shorthand_and_command(capsys):
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
main(["--help"])
|
||||
assert exc.value.code == 0
|
||||
output = capsys.readouterr().out
|
||||
assert "tamq [--detach] [--command COMMAND] REPO [REPO ...]" in output
|
||||
assert "With no --command" in output
|
||||
assert "@TARGET: MESSAGE" in output
|
||||
|
||||
|
||||
def test_attach_delegates_to_tmux(monkeypatch):
|
||||
calls = []
|
||||
monkeypatch.delenv("TMUX", raising=False)
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ def test_isolated_installed_tool_session_smoke(tmp_path):
|
|||
timeout=60,
|
||||
)
|
||||
assert run(str(tamq), "--version").stdout.strip() == "0.1.0"
|
||||
root_help = run(str(tamq), "--help").stdout
|
||||
assert "tamq [--detach] [--command COMMAND] REPO [REPO ...]" in root_help
|
||||
started = json.loads(
|
||||
run(
|
||||
str(tamq),
|
||||
|
|
@ -176,7 +178,7 @@ def test_isolated_installed_tool_session_smoke(tmp_path):
|
|||
"send-keys",
|
||||
"-t",
|
||||
"tamq:railiance-platform",
|
||||
f"{tamq} send '@activity-core: installed-message'",
|
||||
"@activity-core: installed-message",
|
||||
"C-m",
|
||||
)
|
||||
deadline = time.monotonic() + 5
|
||||
|
|
@ -191,10 +193,16 @@ def test_isolated_installed_tool_session_smoke(tmp_path):
|
|||
if inbox:
|
||||
break
|
||||
time.sleep(0.05)
|
||||
assert inbox, run(
|
||||
*tmux, "capture-pane", "-p", "-t", "tamq:railiance-platform"
|
||||
).stdout
|
||||
assert inbox[-1]["sender_repo"] == "railiance-platform"
|
||||
assert inbox[-1]["body"] == "installed-message"
|
||||
assert inbox[-1]["state"] == "pending"
|
||||
message_id = inbox[-1]["message_id"]
|
||||
assert run(str(tamq), "inbox", "--repo", "activity-core").stdout == (
|
||||
f"#railiance-platform: installed-message [{message_id}]\n"
|
||||
)
|
||||
target_after = run(
|
||||
*tmux, "capture-pane", "-p", "-t", "tamq:activity-core"
|
||||
).stdout
|
||||
|
|
@ -209,6 +217,32 @@ def test_isolated_installed_tool_session_smoke(tmp_path):
|
|||
).stdout.splitlines()
|
||||
]
|
||||
assert all_messages[-1]["state"] == "acknowledged"
|
||||
|
||||
run(
|
||||
*tmux,
|
||||
"send-keys",
|
||||
"-t",
|
||||
"tamq:railiance-platform",
|
||||
"@activity-core filtered-message",
|
||||
"C-m",
|
||||
)
|
||||
deadline = time.monotonic() + 5
|
||||
while time.monotonic() < deadline:
|
||||
pending = run(
|
||||
str(tamq), "inbox", "--repo", "activity-core", "--json"
|
||||
).stdout
|
||||
if "filtered-message" in pending:
|
||||
break
|
||||
time.sleep(0.05)
|
||||
message_log = tmp_path / "msg.log"
|
||||
run(
|
||||
str(tamq), "inbox", "--repo", "activity-core", "--filter",
|
||||
f"cat >> {message_log}",
|
||||
)
|
||||
assert "#railiance-platform: filtered-message [m-" in message_log.read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert run(str(tamq), "inbox", "--repo", "activity-core").stdout == ""
|
||||
status = json.loads(run(str(tamq), "status").stdout)
|
||||
assert status["service"] is True
|
||||
assert [item["endpoint_id"] for item in status["endpoints"]] == [started["instance_id"]]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import json
|
||||
import shlex
|
||||
|
||||
from tamq.cli import main
|
||||
from tamq.store import Store
|
||||
|
||||
|
||||
async def service_is_down():
|
||||
|
|
@ -35,3 +37,64 @@ def test_inbox_requires_repository_outside_managed_window(tmp_path, monkeypatch,
|
|||
monkeypatch.delenv("TAMQ_REPO", raising=False)
|
||||
assert main(["inbox"]) == 2
|
||||
assert "requires --repo" in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_human_inbox_is_comment_safe_on_every_line(tmp_path, monkeypatch, capsys):
|
||||
monkeypatch.setenv("TAMQ_STATE_DIR", str(tmp_path / "state"))
|
||||
monkeypatch.setattr("tamq.cli.validate_targets", lambda repos: None)
|
||||
store = Store(tmp_path / "state" / "tamq.sqlite3")
|
||||
message_id = store.add("flex-auth", "audit-core", "first\nsecond\x1b[31m")
|
||||
store.close()
|
||||
|
||||
assert main(["inbox", "--repo", "audit-core"]) == 0
|
||||
assert capsys.readouterr().out == (
|
||||
f"#flex-auth: first\n# second\\x1b[31m [{message_id}]\n"
|
||||
)
|
||||
|
||||
|
||||
def test_inbox_filter_logs_and_acknowledges_successful_messages(tmp_path, monkeypatch, capsys):
|
||||
monkeypatch.setenv("TAMQ_STATE_DIR", str(tmp_path / "state"))
|
||||
monkeypatch.setattr("tamq.cli.validate_targets", lambda repos: None)
|
||||
store = Store(tmp_path / "state" / "tamq.sqlite3")
|
||||
first_id = store.add("flex-auth", "audit-core", "review 'quoted' $value")
|
||||
second_id = store.add("railiance-platform", "audit-core", "second")
|
||||
store.close()
|
||||
log = tmp_path / "messages.log"
|
||||
|
||||
assert main([
|
||||
"inbox", "--repo", "audit-core", "--filter",
|
||||
f"cat >> {shlex.quote(str(log))}",
|
||||
]) == 0
|
||||
assert log.read_text(encoding="utf-8") == (
|
||||
f"#flex-auth: review 'quoted' $value [{first_id}]\n"
|
||||
f"#railiance-platform: second [{second_id}]\n"
|
||||
)
|
||||
assert main(["inbox", "--repo", "audit-core"]) == 0
|
||||
assert capsys.readouterr().out == ""
|
||||
|
||||
|
||||
def test_failed_inbox_filter_leaves_current_and_later_messages_pending(tmp_path, monkeypatch, capsys):
|
||||
monkeypatch.setenv("TAMQ_STATE_DIR", str(tmp_path / "state"))
|
||||
monkeypatch.setattr("tamq.cli.validate_targets", lambda repos: None)
|
||||
store = Store(tmp_path / "state" / "tamq.sqlite3")
|
||||
first_id = store.add("a", "audit-core", "first")
|
||||
second_id = store.add("b", "audit-core", "second")
|
||||
store.close()
|
||||
|
||||
assert main(["inbox", "--repo", "audit-core", "--filter", "false"]) == 1
|
||||
assert first_id in capsys.readouterr().err
|
||||
assert main(["inbox", "--repo", "audit-core", "--json"]) == 0
|
||||
rows = [json.loads(line) for line in capsys.readouterr().out.splitlines()]
|
||||
assert [row["message_id"] for row in rows] == [first_id, second_id]
|
||||
assert all(row["state"] == "pending" for row in rows)
|
||||
|
||||
|
||||
def test_inbox_filter_rejects_non_pending_and_json_modes(tmp_path, monkeypatch, capsys):
|
||||
monkeypatch.setenv("TAMQ_STATE_DIR", str(tmp_path / "state"))
|
||||
monkeypatch.setattr("tamq.cli.validate_targets", lambda repos: None)
|
||||
assert main(["inbox", "--repo", "audit-core", "--all", "--filter", "cat"]) == 2
|
||||
assert "cannot be combined" in capsys.readouterr().err
|
||||
assert main(["inbox", "--repo", "audit-core", "--json", "--filter", "cat"]) == 2
|
||||
assert "cannot be combined" in capsys.readouterr().err
|
||||
assert main(["inbox", "--repo", "audit-core", "--filter", " "]) == 2
|
||||
assert "must not be empty" in capsys.readouterr().err
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ def test_tap_propagates_terminal_size_resize_and_raw_mouse_input(tmp_path, monke
|
|||
session,
|
||||
tmux_command=("tmux", "-L", socket_name),
|
||||
tamq_command=(sys.executable, "-m", "tamq.cli"),
|
||||
command_dir=tmp_path / "commands",
|
||||
)
|
||||
plan = LaunchPlan(
|
||||
("activity-core",),
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ def test_real_tmux_starts_two_repo_windows_and_reuses_them(tmp_path, monkeypatch
|
|||
session,
|
||||
tmux_command=("tmux", "-L", socket_name),
|
||||
tamq_command=(sys.executable, "-m", "tamq.cli"),
|
||||
command_dir=tmp_path / "commands",
|
||||
)
|
||||
plan = LaunchPlan(
|
||||
("railiance-platform", "activity-core"),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
from tamq import tmux
|
||||
import pytest
|
||||
|
||||
|
||||
def test_tmux_manager_builds_tap_windows(tmp_path, monkeypatch):
|
||||
calls = []
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
repo_a = tmp_path / "a"
|
||||
repo_b = tmp_path / "b"
|
||||
repo_a.mkdir()
|
||||
|
|
@ -42,7 +45,7 @@ def test_tmux_manager_builds_tap_windows(tmp_path, monkeypatch):
|
|||
def test_tmux_manager_reuses_session_instance_id(tmp_path, monkeypatch):
|
||||
repo = tmp_path / "a"
|
||||
repo.mkdir()
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
options = {"@tamq_managed": "1"}
|
||||
monkeypatch.setattr(tmux, "validate_targets", lambda repos: None)
|
||||
monkeypatch.setattr(tmux, "repository_paths", lambda: {"a": str(repo)})
|
||||
|
|
@ -74,7 +77,7 @@ def test_tmux_manager_reuses_session_instance_id(tmp_path, monkeypatch):
|
|||
def test_preflight_rejects_foreign_session(tmp_path, monkeypatch):
|
||||
repo = tmp_path / "a"
|
||||
repo.mkdir()
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
monkeypatch.setattr(tmux, "validate_targets", lambda repos: None)
|
||||
monkeypatch.setattr(tmux, "repository_paths", lambda: {"a": str(repo)})
|
||||
monkeypatch.setattr(tmux.shutil, "which", lambda command: f"/bin/{command}")
|
||||
|
|
@ -95,7 +98,7 @@ def test_preflight_rejects_foreign_session(tmp_path, monkeypatch):
|
|||
|
||||
|
||||
def test_tmux_only_plan_starts_agent_without_tap(tmp_path, monkeypatch):
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
calls = []
|
||||
plan = tmux.LaunchPlan(("a",), {"a": str(tmp_path)}, ("codex", "--quiet"))
|
||||
|
||||
|
|
@ -120,7 +123,8 @@ def test_tmux_only_plan_starts_agent_without_tap(tmp_path, monkeypatch):
|
|||
|
||||
|
||||
def test_neutral_plan_starts_shell_without_sending_keystrokes(tmp_path, monkeypatch):
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
command_dir = tmp_path / "commands"
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=command_dir)
|
||||
calls = []
|
||||
plan = tmux.LaunchPlan(("a", "b"), {"a": str(tmp_path), "b": str(tmp_path)}, ())
|
||||
|
||||
|
|
@ -145,12 +149,53 @@ def test_neutral_plan_starts_shell_without_sending_keystrokes(tmp_path, monkeypa
|
|||
new_window = next(call for call in calls if call and call[0] == "new-window")
|
||||
assert "TAMQ_REPO=a" in new_session
|
||||
assert "TAMQ_REPO=b" in new_window
|
||||
assert f"PATH={command_dir}{os.pathsep}" in " ".join(new_session)
|
||||
assert f"PATH={command_dir}{os.pathsep}" in " ".join(new_window)
|
||||
assert (command_dir / "@a").is_file()
|
||||
assert (command_dir / "@a:").is_file()
|
||||
assert (command_dir / "@b").is_file()
|
||||
assert (command_dir / "@b:").is_file()
|
||||
|
||||
|
||||
def test_address_commands_preserve_message_arguments(tmp_path):
|
||||
command_dir = tmp_path / "commands"
|
||||
manager = tmux.TmuxManager(
|
||||
"tamq-test", tamq_command=("echo",), command_dir=command_dir,
|
||||
)
|
||||
manager._install_address_commands(["audit-core"])
|
||||
|
||||
for name in ("@audit-core", "@audit-core:"):
|
||||
result = subprocess.run(
|
||||
[str(command_dir / name), "Some message!", "$value", "; literal", "--from"],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
assert result.stdout == "send -- @audit-core: Some message! $value ; literal --from\n"
|
||||
|
||||
|
||||
def test_address_commands_reject_unsafe_repository_names(tmp_path):
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
with pytest.raises(tmux.TmuxError, match="cannot be exposed"):
|
||||
manager._install_address_commands(["../outside"])
|
||||
|
||||
|
||||
def test_address_commands_do_not_replace_unowned_commands(tmp_path):
|
||||
command_dir = tmp_path / "commands"
|
||||
command_dir.mkdir()
|
||||
existing = command_dir / "@audit-core"
|
||||
existing.write_text("#!/bin/sh\necho mine\n", encoding="utf-8")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=command_dir)
|
||||
|
||||
with pytest.raises(tmux.TmuxError, match="refusing to replace"):
|
||||
manager._install_address_commands(["audit-core"])
|
||||
assert existing.read_text(encoding="utf-8") == "#!/bin/sh\necho mine\n"
|
||||
|
||||
|
||||
def test_preflight_rejects_missing_agent(tmp_path, monkeypatch):
|
||||
repo = tmp_path / "a"
|
||||
repo.mkdir()
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
monkeypatch.setattr(tmux, "validate_targets", lambda repos: None)
|
||||
monkeypatch.setattr(tmux, "repository_paths", lambda: {"a": str(repo)})
|
||||
monkeypatch.setattr(tmux.shutil, "which", lambda command: None if command == "missing-agent" else f"/bin/{command}")
|
||||
|
|
@ -161,7 +206,7 @@ def test_preflight_rejects_missing_agent(tmp_path, monkeypatch):
|
|||
def test_preflight_deduplicates_repositories(tmp_path, monkeypatch):
|
||||
repo = tmp_path / "a"
|
||||
repo.mkdir()
|
||||
manager = tmux.TmuxManager("tamq-test")
|
||||
manager = tmux.TmuxManager("tamq-test", command_dir=tmp_path / "commands")
|
||||
monkeypatch.setattr(tmux, "validate_targets", lambda repos: None)
|
||||
monkeypatch.setattr(tmux, "repository_paths", lambda: {"a": str(repo)})
|
||||
monkeypatch.setattr(tmux.shutil, "which", lambda command: f"/bin/{command}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue