feat(cli,registry): introduce --herdr-workspace option and decouple socket fallback chains
This commit is contained in:
@@ -78,21 +78,103 @@ def test_create_validate_env_key(mam_sandbox):
|
||||
# ==============================================================================
|
||||
|
||||
def test_resume_resolve_herdr_session_default(mam_sandbox):
|
||||
"""Test resolve_herdr_workspace fallback behavior when session is not in YAML."""
|
||||
res = run_lib_func(mam_sandbox, "resolve_herdr_workspace", "non-existent-session")
|
||||
"""Test resolve_herdr_session fallback behavior when session is not in YAML."""
|
||||
res = run_lib_func(mam_sandbox, "resolve_herdr_session", "non-existent-session")
|
||||
assert res.returncode == 0
|
||||
assert res.stdout.strip() != ""
|
||||
|
||||
def test_resume_resolve_herdr_session_env(mam_sandbox):
|
||||
"""Test resolve_herdr_workspace fallback to HERDR_SESSION_NAME or HERDR_SERVER_NAME env var."""
|
||||
res = run_lib_func(mam_sandbox, "resolve_herdr_workspace", "non-existent-session", env={"HERDR_SESSION_NAME": "custom_session"})
|
||||
"""Test resolve_herdr_session fallback to HERDR_SESSION_NAME or HERDR_SERVER_NAME env var."""
|
||||
res = run_lib_func(mam_sandbox, "resolve_herdr_session", "non-existent-session", env={"HERDR_SESSION_NAME": "custom_session"})
|
||||
assert res.returncode == 0
|
||||
assert res.stdout.strip() == "custom_session"
|
||||
|
||||
res_legacy = run_lib_func(mam_sandbox, "resolve_herdr_workspace", "non-existent-session", env={"HERDR_SERVER_NAME": "custom_server"})
|
||||
res_legacy = run_lib_func(mam_sandbox, "resolve_herdr_session", "non-existent-session", env={"HERDR_SERVER_NAME": "custom_server"})
|
||||
assert res_legacy.returncode == 0
|
||||
assert res_legacy.stdout.strip() == "custom_server"
|
||||
|
||||
def test_resolvers_are_decoupled(mam_sandbox):
|
||||
"""소켓과 워크스페이스 라벨이 다른 행에서 두 함수가 서로 다른 값을 낸다."""
|
||||
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
|
||||
yaml_path.write_text("""herdr_sessions:
|
||||
- name: d-creator-claude
|
||||
status: running
|
||||
herdr_session: socket-A
|
||||
herdr_server: socket-A
|
||||
herdr_workspace: label-B
|
||||
pane:
|
||||
cwd: /tmp
|
||||
""")
|
||||
s = run_lib_func(mam_sandbox, "resolve_herdr_session", "d-creator-claude")
|
||||
w = run_lib_func(mam_sandbox, "resolve_herdr_workspace", "d-creator-claude")
|
||||
assert s.stdout.strip() == "socket-A"
|
||||
assert w.stdout.strip() == "label-B"
|
||||
|
||||
def test_workspace_label_never_resolves_as_socket(mam_sandbox):
|
||||
"""B-22: herdr_session 이 없는 행에서도 herdr_workspace 는 소켓 이름이 되지 않는다."""
|
||||
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
|
||||
yaml_path.write_text("""herdr_sessions:
|
||||
- name: legacy-creator-claude
|
||||
status: running
|
||||
herdr_workspace: my-label
|
||||
pane:
|
||||
cwd: /tmp
|
||||
""")
|
||||
s = run_lib_func(mam_sandbox, "resolve_herdr_session", "legacy-creator-claude")
|
||||
assert s.stdout.strip() != "my-label"
|
||||
|
||||
def test_socket_resolver_fallback_chain(mam_sandbox):
|
||||
"""herdr_server 만 있는 행 -> herdr_server 반환, 둘 다 없으면 기본/슬러그 fallback."""
|
||||
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
|
||||
yaml_path.write_text("""herdr_sessions:
|
||||
- name: srv-only-creator-claude
|
||||
status: running
|
||||
herdr_server: socket-from-srv
|
||||
pane:
|
||||
cwd: /tmp
|
||||
""")
|
||||
s = run_lib_func(mam_sandbox, "resolve_herdr_session", "srv-only-creator-claude")
|
||||
assert s.stdout.strip() == "socket-from-srv"
|
||||
|
||||
def test_workspace_resolver_prefers_the_row_over_the_caller_argument(mam_sandbox):
|
||||
"""C-1: 등록된 행에는 herdr_workspace 가 없지만 pane.cwd 가 있다.
|
||||
호출자가 '다른' 워크스페이스를 넘겨도 행의 cwd 가 이긴다."""
|
||||
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
|
||||
yaml_path.write_text("""herdr_sessions:
|
||||
- name: pa-creator-claude
|
||||
status: running
|
||||
pane:
|
||||
cwd: /path/to/project_a
|
||||
""")
|
||||
r = run_lib_func(mam_sandbox, "resolve_herdr_workspace",
|
||||
"pa-creator-claude", "/path/to/project_b")
|
||||
assert r.stdout.strip() == "to-project-a"
|
||||
|
||||
def test_workspace_resolver_uses_the_argument_only_when_unregistered(mam_sandbox):
|
||||
"""③ 분기가 살아 있음을 확인 — 미등록 세션에서는 인자가 쓰인다."""
|
||||
r = run_lib_func(mam_sandbox, "resolve_herdr_workspace",
|
||||
"not-registered", "/path/to/project_b")
|
||||
assert r.stdout.strip() == "to-project-b"
|
||||
|
||||
@pytest.mark.parametrize("path", ["/tmp", "/", "/a/My_Proj.v2", "/private/var/folders/q_/x"])
|
||||
def test_slug_parity_between_bash_and_python(mam_sandbox, path):
|
||||
"""D5 는 두 슬러그 구현의 일치에 의존한다 (lib.sh derive_workspace_slug 와
|
||||
resolve_herdr_workspace / reconcile.sh 의 인라인 slug())."""
|
||||
b = run_lib_func(mam_sandbox, "derive_workspace_slug", path).stdout.strip()
|
||||
p = run_lib_func(mam_sandbox, "resolve_herdr_workspace", "not-registered", path).stdout.strip()
|
||||
assert b.removeprefix("mam-") == p
|
||||
|
||||
def test_no_socket_lookup_falls_back_to_workspace_label(mam_sandbox):
|
||||
"""B-22 구조 가드: 소켓 lookup 표현식에 herdr_workspace 가 다시 끼어들지 못한다."""
|
||||
import re
|
||||
pat = re.compile(r"herdr_session'\)\s*or\s*.*herdr_workspace")
|
||||
lib_sh = mam_sandbox / "skills" / "lib.sh"
|
||||
reconcile_sh = mam_sandbox / "skills" / "multi-agent-mux-monitor" / "scripts" / "reconcile.sh"
|
||||
status_sh = mam_sandbox / "skills" / "multi-agent-mux-status" / "scripts" / "status.sh"
|
||||
for f in (lib_sh, reconcile_sh, status_sh):
|
||||
for i, line in enumerate(f.read_text().splitlines(), 1):
|
||||
assert not pat.search(line), f"{f.name}:{i} — socket lookup falls back to workspace label:\n{line}"
|
||||
|
||||
def test_resume_find_workspace_uuid_empty(mam_sandbox):
|
||||
"""Test find_workspace_uuid returns empty string for non-existent workspace."""
|
||||
res = run_lib_func(mam_sandbox, "find_workspace_uuid", "/non/existent/path", "claude")
|
||||
|
||||
Reference in New Issue
Block a user