Skip to content

Commit 664a3ed

Browse files
committed
ControlMode(test): Add attach failure, flags, and retry placeholder
1 parent 481da34 commit 664a3ed

File tree

3 files changed

+70
-6
lines changed

3 files changed

+70
-6
lines changed

tests/test_control_client_logs.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,37 @@ def test_control_client_notification_parsing(
9797
notif = proto.get_notification(timeout=0.1)
9898
assert notif is not None
9999
assert notif.kind.name in {"SESSION_CHANGED", "CLIENT_SESSION_CHANGED", "RAW"}
100+
101+
102+
@pytest.mark.engines(["control"])
103+
def test_control_client_lists_control_flag(
104+
control_client_logs: tuple[t.Any, ControlProtocol],
105+
) -> None:
106+
"""list-clients should show control client with C flag on tmux >= 3.2."""
107+
proc, proto = control_client_logs
108+
if has_lt_version("3.2"):
109+
pytest.skip("tmux < 3.2 omits client_flags")
110+
111+
assert proc.stdin is not None
112+
list_ctx = CommandContext(
113+
argv=[
114+
"tmux",
115+
"list-clients",
116+
"-F",
117+
"#{client_pid} #{client_flags} #{session_name}",
118+
],
119+
)
120+
proto.register_command(list_ctx)
121+
proc.stdin.write('list-clients -F"#{client_pid} #{client_flags} #{session_name}"\n')
122+
proc.stdin.write("detach-client\n")
123+
proc.stdin.flush()
124+
125+
stdout_data, _ = proc.communicate(timeout=5)
126+
for line in stdout_data.splitlines():
127+
proto.feed_line(line.rstrip("\n"))
128+
129+
assert list_ctx.done.wait(timeout=0.5)
130+
result = proto.build_result(list_ctx)
131+
assert any(
132+
len(parts := line.split()) >= 2 and "C" in parts[1] for line in result.stdout
133+
)

tests/test_control_mode_engine.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,32 @@ def test_iter_notifications_survives_overflow(
298298
first = next(notif_iter, None)
299299
assert first is not None
300300
assert first.kind.name == "SESSIONS_CHANGED"
301+
302+
303+
class RestartRetryFixture(t.NamedTuple):
304+
"""Fixture for restart + retry behavior."""
305+
306+
test_id: str
307+
raise_once: bool
308+
309+
310+
@pytest.mark.xfail(reason="Engine retry path not covered yet", strict=False)
311+
@pytest.mark.parametrize(
312+
"case",
313+
[
314+
RestartRetryFixture(
315+
test_id="retry_after_broken_pipe",
316+
raise_once=True,
317+
),
318+
],
319+
ids=lambda c: c.test_id,
320+
)
321+
def test_run_result_retries_after_broken_pipe(
322+
case: RestartRetryFixture,
323+
monkeypatch: pytest.MonkeyPatch,
324+
) -> None:
325+
"""Placeholder: run_result should retry after broken pipe and succeed."""
326+
engine = ControlModeEngine()
327+
# TODO: Implement retry simulation when engine supports injectable I/O.
328+
with pytest.raises(exc.ControlModeConnectionError):
329+
engine.run("list-sessions")

tests/test_control_mode_regressions.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -692,12 +692,13 @@ def test_attach_to_existing_session(case: AttachFixture) -> None:
692692
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
693693
bootstrap = Server(socket_name=socket_name)
694694
try:
695-
# Create the target session via subprocess engine
696-
bootstrap.new_session(
697-
session_name=case.attach_to,
698-
attach=False,
699-
kill_session=True,
700-
)
695+
if case.expect_attached:
696+
# Create the target session via subprocess engine
697+
bootstrap.new_session(
698+
session_name=case.attach_to,
699+
attach=False,
700+
kill_session=True,
701+
)
701702
engine = ControlModeEngine(attach_to=case.attach_to)
702703
server = Server(socket_name=socket_name, engine=engine)
703704
if not case.expect_attached:

0 commit comments

Comments
 (0)