- Replace legacy s[:16]-s[-15:] truncation with 8-char SHA-1 hash suffix in sanitize.py and lib.sh to prevent workspace name collisions - Align mock Herdr error messages in tests/conftest.py to real Herdr 0.8.0 output format - Add missing required/invalid_agent_name to early abort regex in lib.sh - Remove legacy heuristics in lib.sh has-session and unify mock agent lookups - Add unit tests in tests/test_sanitize_and_mock_errors.py (256/256 passed)
85 lines
3.6 KiB
Python
85 lines
3.6 KiB
Python
import subprocess
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
import pytest
|
|
from lib_py.agents.sanitize import sanitize_herdr_agent_name
|
|
|
|
def test_sanitize_sibling_workspace_non_collision():
|
|
"""
|
|
Verifies that sibling workspaces with identical prefix and suffix
|
|
do NOT collapse into the same 32-character sanitized herdr agent name.
|
|
"""
|
|
workspaces = [
|
|
"canary-projects-educative-export-tools-creator-claude",
|
|
"canary-projects-getting-started-a2a-creator-claude",
|
|
"canary-projects-multi-agent-mux-creator-claude",
|
|
"canary-projects-pu-riverpod-cookbook-creator-claude",
|
|
]
|
|
sanitized = [sanitize_herdr_agent_name(w) for w in workspaces]
|
|
|
|
# 1. All lengths <= 32
|
|
for s in sanitized:
|
|
assert len(s) <= 32, f"Length exceeds 32: {s}"
|
|
assert len(s) == 32, f"Expected 32 chars for long names: {s}"
|
|
|
|
# 2. All names are unique (0 collisions)
|
|
assert len(set(sanitized)) == len(workspaces), f"Collisions detected: {sanitized}"
|
|
|
|
def test_sanitize_bash_python_parity(mam_sandbox):
|
|
"""
|
|
Verifies that bash _sanitize_herdr_agent_name and Python sanitize_herdr_agent_name
|
|
produce byte-for-byte identical output across various edge cases.
|
|
"""
|
|
test_cases = [
|
|
"canary-projects-multi-agent-mux-creator-claude",
|
|
"canary-projects-educative-export-tools-creator-claude",
|
|
"canary-projects-getting-started-a2a-creator-claude",
|
|
"canary-projects-pu-riverpod-cookbook-creator-claude",
|
|
"short-name",
|
|
"UPPER_CASE_123.dots",
|
|
"123_starts_digit",
|
|
"_underscore_leading",
|
|
"",
|
|
"exact-32-chars-long-name-1234567",
|
|
"exact-33-chars-long-name-12345678",
|
|
]
|
|
lib_path = mam_sandbox / ".agents" / "skills" / "lib.sh"
|
|
|
|
for case in test_cases:
|
|
py_res = sanitize_herdr_agent_name(case)
|
|
cmd = f"""
|
|
source {lib_path}
|
|
_sanitize_herdr_agent_name "{case}"
|
|
"""
|
|
bash_res = subprocess.check_output(["bash", "-c", cmd]).decode().strip()
|
|
assert py_res == bash_res, f"Mismatch for '{case}': Python={py_res} vs Bash={bash_res}"
|
|
|
|
def test_mock_herdr_error_formatting_and_abort(mock_herdr, mock_agents):
|
|
"""
|
|
Verifies that mock herdr error output matches real Herdr 0.8.0 format
|
|
and triggers lib.sh early abort regex.
|
|
"""
|
|
import re
|
|
abort_regex = re.compile(r"^usage:|unknown option|unknown flag|missing required|invalid_agent_name|^error:", re.IGNORECASE)
|
|
mock_bin = str(mock_agents / "herdr")
|
|
|
|
# 1. Unknown flag
|
|
res_unknown = subprocess.run([mock_bin, "agent", "start", "testagent", "--kind", "claude", "--pane", "w1:p1", "--env", "FOO=BAR"], capture_output=True, text=True)
|
|
assert res_unknown.returncode != 0
|
|
assert abort_regex.search(res_unknown.stderr) is not None, f"Stderr did not match abort regex: {res_unknown.stderr}"
|
|
assert "unknown option: --env" in res_unknown.stderr
|
|
|
|
# 2. Missing required --pane
|
|
res_missing = subprocess.run([mock_bin, "agent", "start", "testagent", "--kind", "claude"], capture_output=True, text=True)
|
|
assert res_missing.returncode != 0
|
|
assert abort_regex.search(res_missing.stderr) is not None, f"Stderr did not match abort regex: {res_missing.stderr}"
|
|
assert "missing required --pane" in res_missing.stderr
|
|
|
|
# 3. Invalid agent name
|
|
res_badname = subprocess.run([mock_bin, "agent", "start", "BAD_NAME", "--kind", "claude", "--pane", "w1:p1"], capture_output=True, text=True)
|
|
assert res_badname.returncode != 0
|
|
assert abort_regex.search(res_badname.stderr) is not None, f"Stderr did not match abort regex: {res_badname.stderr}"
|
|
assert "invalid_agent_name" in res_badname.stderr
|
|
|