Skip to content

Commit 6d6405f

Browse files
committed
ControlMode(test[regressions]): Track remaining control-mode gaps with strict xfails
why: Document the last failing control-mode behaviors observed in full suite runs. what: - Add xfail repros for control-client visibility in attached_sessions, switch_client bad-name handling, multi-var environment propagation, session.kill EOF handling - Preserve existing env/capture-pane/attached visibility regressions with NamedTuple + test_id parametrization
1 parent 212e65b commit 6d6405f

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

tests/test_control_mode_regressions.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,173 @@ def test_server_kill_handles_control_eof_gracefully() -> None:
419419
finally:
420420
with contextlib.suppress(Exception):
421421
server.kill()
422+
423+
424+
#
425+
# New repros for remaining control-mode failures in full suite
426+
#
427+
428+
429+
class AttachedSessionsFixture(t.NamedTuple):
430+
"""Fixture for attached_sessions filtering failures."""
431+
432+
test_id: str
433+
expect_empty: bool
434+
435+
436+
ATTACHED_SESSIONS_CASES = [
437+
pytest.param(
438+
AttachedSessionsFixture(
439+
test_id="control_client_hidden",
440+
expect_empty=True,
441+
),
442+
id="attached_control_client_hidden",
443+
marks=pytest.mark.xfail(
444+
reason="control client still appears in attached_sessions",
445+
strict=True,
446+
),
447+
),
448+
]
449+
450+
451+
@pytest.mark.parametrize("case", ATTACHED_SESSIONS_CASES)
452+
def test_attached_sessions_filters_control_client(
453+
case: AttachedSessionsFixture,
454+
) -> None:
455+
"""Attached sessions should exclude the control-mode client itself."""
456+
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
457+
engine = ControlModeEngine()
458+
server = Server(socket_name=socket_name, engine=engine)
459+
460+
try:
461+
# Start a user session; control client should remain hidden.
462+
server.new_session(session_name="user_session", attach=False, kill_session=True)
463+
attached = server.attached_sessions
464+
if case.expect_empty:
465+
assert attached == []
466+
finally:
467+
with contextlib.suppress(Exception):
468+
server.kill()
469+
470+
471+
class BadSessionNameFixture(t.NamedTuple):
472+
"""Fixture for switch_client behavior with control client present."""
473+
474+
test_id: str
475+
session_name: str
476+
expect_exception: type[BaseException] | None
477+
478+
479+
BAD_SESSION_NAME_CASES = [
480+
pytest.param(
481+
BadSessionNameFixture(
482+
test_id="switch_client_should_raise",
483+
session_name="hey moo",
484+
expect_exception=exc.LibTmuxException,
485+
),
486+
id="switch_client_bad_name",
487+
marks=pytest.mark.xfail(
488+
reason="control client makes switch_client succeed instead of raising",
489+
strict=True,
490+
),
491+
),
492+
]
493+
494+
495+
@pytest.mark.parametrize("case", BAD_SESSION_NAME_CASES)
496+
def test_switch_client_respects_bad_session_names(
497+
case: BadSessionNameFixture,
498+
) -> None:
499+
"""switch_client should reject invalid names even with control client attached."""
500+
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
501+
engine = ControlModeEngine()
502+
server = Server(socket_name=socket_name, engine=engine)
503+
try:
504+
session = server.new_session(
505+
session_name="hey moomoo",
506+
attach=False,
507+
kill_session=True,
508+
)
509+
assert session is not None
510+
assert case.expect_exception is not None
511+
with pytest.raises(case.expect_exception):
512+
server.switch_client(f"{case.session_name}moo")
513+
finally:
514+
with contextlib.suppress(Exception):
515+
server.kill()
516+
517+
518+
class EnvMultiFixture(t.NamedTuple):
519+
"""Fixture for multi-var environment propagation errors."""
520+
521+
test_id: str
522+
environment: dict[str, str]
523+
expected_value: str
524+
525+
526+
ENV_MULTI_CASES = [
527+
pytest.param(
528+
EnvMultiFixture(
529+
test_id="new_window_multi_vars",
530+
environment={"ENV_VAR_1": "window_1", "ENV_VAR_2": "window_2"},
531+
expected_value="window_1",
532+
),
533+
id="env_new_window_multi",
534+
marks=pytest.mark.xfail(
535+
reason="control-mode loses environment with multiple -e flags",
536+
strict=True,
537+
),
538+
),
539+
]
540+
541+
542+
@pytest.mark.parametrize("case", ENV_MULTI_CASES)
543+
def test_environment_multi_var_propagation(case: EnvMultiFixture) -> None:
544+
"""Multiple -e flags should all be delivered inside the pane."""
545+
env = shutil.which("env")
546+
assert env is not None
547+
548+
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
549+
engine = ControlModeEngine()
550+
server = Server(socket_name=socket_name, engine=engine)
551+
552+
try:
553+
session = server.new_session(
554+
session_name="env_multi_repro",
555+
attach=True,
556+
window_name="window_with_environment",
557+
window_shell=f"{env} PS1='$ ' sh",
558+
environment=case.environment,
559+
kill_session=True,
560+
)
561+
pane = session.active_window.active_pane
562+
assert pane is not None
563+
pane.send_keys("echo $ENV_VAR_1", literal=True, suppress_history=False)
564+
output = pane.capture_pane()
565+
assert output[-2] == case.expected_value
566+
finally:
567+
with contextlib.suppress(Exception):
568+
server.kill()
569+
570+
571+
@pytest.mark.xfail(
572+
reason="Session.kill still surfaces ControlModeConnectionError on EOF",
573+
strict=True,
574+
)
575+
def test_session_kill_handles_control_eof() -> None:
576+
"""Session.kill should swallow control-mode EOF when tmux exits."""
577+
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
578+
engine = ControlModeEngine()
579+
server = Server(socket_name=socket_name, engine=engine)
580+
581+
try:
582+
session = server.new_session(
583+
session_name="kill_session_repro",
584+
attach=False,
585+
kill_session=True,
586+
)
587+
assert session is not None
588+
session.kill()
589+
finally:
590+
with contextlib.suppress(Exception):
591+
server.kill()

0 commit comments

Comments
 (0)