Files
herdr-session-switch/tests/test_tmux_integration.py
T

207 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import os
from pathlib import Path
import shutil
import tempfile
import time
import unittest
import uuid
from herdr_hub.cli import (
BOOTSTRAP_WINDOW_NAME,
Endpoint,
HubError,
TmuxHub,
WINDOW_SHORT_LABEL_OPTION,
)
@unittest.skipUnless(shutil.which("tmux"), "tmux is required")
class TmuxIntegrationTests(unittest.TestCase):
def setUp(self) -> None:
self.temporary_directory = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary_directory.cleanup)
root = Path(self.temporary_directory.name)
self.fake_herdr = root / "herdr"
self.fake_herdr.write_text(
"#!/bin/sh\n"
"if [ \"${1:-}\" = \"--session\" ] && [ \"${2:-}\" = \"dead\" ]; then\n"
" exit 0\n"
"fi\n"
"exec sleep 30\n",
encoding="utf-8",
)
self.fake_herdr.chmod(0o755)
self.socket_name = f"herdr-hub-test-{os.getpid()}-{uuid.uuid4().hex[:8]}"
self.socket_path = Path(
os.environ.get("TMUX_TMPDIR", f"/tmp/tmux-{os.getuid()}")
) / self.socket_name
self.hub = TmuxHub(
tmux_bin=shutil.which("tmux") or "tmux",
socket_name=self.socket_name,
session_name="hub",
config_file="/dev/null",
script_path="/dev/null",
)
self.addCleanup(self._stop_hub)
def _stop_hub(self) -> None:
try:
self.hub.stop()
except Exception:
pass
self.socket_path.unlink(missing_ok=True)
def test_configures_isolated_server_and_adds_without_duplicates(self) -> None:
self.assertTrue(self.hub.ensure_server())
endpoints = [Endpoint.local(), Endpoint.remote("orangepi")]
added = self.hub.add_missing(endpoints, str(self.fake_herdr))
self.assertEqual(len(added), 2)
self.assertEqual(self.hub.add_missing(endpoints, str(self.fake_herdr)), [])
windows = self.hub.managed_windows()
self.assertEqual(
{window.key for window in windows},
{"local:default", "remote:orangepi:default"},
)
remote_window = next(
window for window in windows if window.key == "remote:orangepi:default"
)
self.assertEqual(remote_window.endpoint, Endpoint.remote("orangepi"))
all_names = self.hub.run(
["list-windows", "-t", "hub", "-F", "#{window_name}"]
).stdout.splitlines()
self.assertNotIn(BOOTSTRAP_WINDOW_NAME, all_names)
prefix = self.hub.run(["show-options", "-gv", "prefix"]).stdout.strip()
status = self.hub.run(["show-options", "-gv", "status"]).stdout.strip()
position = self.hub.run(
["show-options", "-gv", "status-position"]
).stdout.strip()
mouse = self.hub.run(["show-options", "-gv", "mouse"]).stdout.strip()
clipboard = self.hub.run(
["show-options", "-sv", "set-clipboard"]
).stdout.strip()
status_right = self.hub.run(
["show-options", "-gv", "status-right"]
).stdout.strip()
dead_format = self.hub.run(
["show-options", "-wgv", "remain-on-exit-format"]
).stdout.strip()
inactive_window_format = self.hub.run(
["show-options", "-wgv", "window-status-format"]
).stdout.strip()
current_window_format = self.hub.run(
["show-options", "-wgv", "window-status-current-format"]
).stdout.strip()
status_left_binding = self.hub.run(
["list-keys", "-T", "root", "MouseDown1StatusLeft"]
).stdout.strip()
close_binding = self.hub.run(
["list-keys", "-T", "prefix", "&"]
).stdout.strip()
self.assertEqual(prefix, "C-a")
self.assertEqual(status, "on")
self.assertEqual(position, "top")
self.assertEqual(mouse, "on")
self.assertEqual(clipboard, "on")
self.assertIn("连接已断开", status_right)
self.assertIn("C-a R", status_right)
self.assertIn("连接已断开", dead_format)
self.assertIn("Ctrl+A R", dead_format)
self.assertIn("client_width", inactive_window_format)
self.assertIn(WINDOW_SHORT_LABEL_OPTION, inactive_window_format)
self.assertNotIn("#I", inactive_window_format)
self.assertIn("client_width", current_window_format)
self.assertIn(WINDOW_SHORT_LABEL_OPTION, current_window_format)
self.assertIn("display-popup", status_left_binding)
self.assertIn("confirm-before", close_binding)
self.assertIn(" close --window ", close_binding)
local_short_label = self.hub.run(
[
"show-options",
"-wv",
"-t",
next(window.window_id for window in windows if window.key == "local:default"),
WINDOW_SHORT_LABEL_OPTION,
]
).stdout.strip()
remote_short_label = self.hub.run(
[
"show-options",
"-wv",
"-t",
remote_window.window_id,
WINDOW_SHORT_LABEL_OPTION,
]
).stdout.strip()
rendered_local_short_label = self.hub.run(
[
"display-message",
"-p",
"-t",
next(window.window_id for window in windows if window.key == "local:default"),
"#{=12:@herdr_hub_short_label}",
]
).stdout.strip()
self.assertEqual(local_short_label, "local")
self.assertEqual(remote_short_label, "orangepi")
self.assertEqual(rendered_local_short_label, "local")
def test_dismissed_window_stays_hidden_until_explicitly_reopened(self) -> None:
self.hub.ensure_server()
endpoints = [Endpoint.local(), Endpoint.local("work")]
self.hub.add_missing(endpoints, str(self.fake_herdr))
default_window = self.hub.window_for_key("local:default")
assert default_window is not None
self.hub.dismiss_window(default_window.window_id)
self.assertEqual(self.hub.dismissed_keys(), {"local:default"})
self.assertIsNone(self.hub.window_for_key("local:default"))
self.assertEqual(self.hub.add_missing(endpoints, str(self.fake_herdr)), [])
reopened = self.hub.activate_endpoint(Endpoint.local(), str(self.fake_herdr))
self.assertEqual(reopened.key, "local:default")
self.assertEqual(self.hub.dismissed_keys(), set())
work_window = self.hub.window_for_key("local:work")
assert work_window is not None
self.hub.dismiss_window(work_window.window_id)
with self.assertRaises(HubError):
self.hub.dismiss_window(reopened.window_id)
def test_dead_window_is_retained_and_can_be_respawned(self) -> None:
self.hub.ensure_server()
window = self.hub.create_window(Endpoint.local("dead"), str(self.fake_herdr))
self.hub.remove_bootstrap()
deadline = time.monotonic() + 3
dead = False
while time.monotonic() < deadline:
current = self.hub.window_for_key("local:dead")
dead = current.dead if current is not None else False
if dead:
break
time.sleep(0.05)
self.assertTrue(dead)
rendered_status = self.hub.run(
[
"display-message",
"-p",
"-t",
window.window_id,
"#{?pane_dead,× #{window_name} [断开],● #{window_name}}",
]
).stdout.strip()
self.assertEqual(rendered_status, f"× {window.name} [断开]")
self.hub.reconnect(window.window_id)
self.assertIsNotNone(self.hub.window_for_key("local:dead"))
if __name__ == "__main__":
unittest.main()