aboutsummaryrefslogtreecommitdiff
path: root/tests/test_hub.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-24 01:57:13 -0400
committerhistoria <historiavg@proton.me>2026-08-24 01:58:17 -0400
commitc02d66b2d3221c0c5f5e8f2cb2ae218f1e325a0a (patch)
treee9ec4f35c18102d4624d3cd59358d192be7bbfcb /tests/test_hub.py
parent194c63e4d11e6de9792a736a7b99788f1db78741 (diff)
downloadtts-audiobook-generator-c02d66b2d3221c0c5f5e8f2cb2ae218f1e325a0a.tar.gz
feat: manage venv for all backends
Diffstat (limited to 'tests/test_hub.py')
-rw-r--r--tests/test_hub.py145
1 files changed, 136 insertions, 9 deletions
diff --git a/tests/test_hub.py b/tests/test_hub.py
index ce9af43..21f795e 100644
--- a/tests/test_hub.py
+++ b/tests/test_hub.py
@@ -8,8 +8,9 @@ import unittest
from pathlib import Path
from unittest.mock import patch
-from ui import hub, tui
+from backends import BackendStatus, ServerSpec
from tests.test_tui import FakeCurses, FakeScreen
+from ui import hub, tui
class HubHelperTests(unittest.TestCase):
@@ -93,7 +94,7 @@ class HubMenuTests(unittest.TestCase):
labels = [label for label, _ in captured["options"]]
self.assertEqual(labels, ["Set up a backend...", "Quit"])
- def test_menu_has_all_four_when_one_installed(self):
+ def test_menu_has_all_five_when_one_installed(self):
captured = {}
def fake_menu(stdscr, title, options, **kwargs):
@@ -111,7 +112,7 @@ class HubMenuTests(unittest.TestCase):
self.assertEqual(
labels,
["Convert books...", "Set up a backend...",
- "Configure a backend...", "Quit"])
+ "Configure a backend...", "Server...", "Quit"])
# The status table is passed through, one row per backend.
self.assertEqual(captured["rows"],
[("qwen-tts", "installed", "warn", "body")])
@@ -137,9 +138,9 @@ class HubMenuTests(unittest.TestCase):
[("audio.cpp", "unavailable", "err", "dim"),
("qwen-tts", "running", "ok", "body")])
- def test_menu_has_all_four_when_one_running_only(self):
+ def test_menu_has_all_five_when_one_running_only(self):
# Running but not installed (an external server) still unlocks the
- # Convert/Configure entries.
+ # Convert/Configure/Server entries.
captured = {}
def fake_menu(stdscr, title, options, **kwargs):
@@ -156,14 +157,14 @@ class HubMenuTests(unittest.TestCase):
self.assertEqual(
labels,
["Convert books...", "Set up a backend...",
- "Configure a backend...", "Quit"])
+ "Configure a backend...", "Server...", "Quit"])
def test_convert_with_no_available_backend_offers_setup(self):
# One installed-but-not-ready backend → Convert is offered. The
# convert menu lists no available backend, so only "Set up a
# backend..." is shown; Enter selects it → setup menu lists 3
# backends; Esc goes back → convert returns None → main menu loops.
- # Then quit: main menu now has 4 options, Quit is the 4th (Down x3).
+ # Then quit: main menu now has 5 options, Quit is the 5th (Down x4).
from backends import BackendInfo, BackendStatus
none = BackendStatus("k", "l", installed=True, configured=False)
infos = [BackendInfo("audiocpp", "audio.cpp", lambda: none,
@@ -181,13 +182,139 @@ class HubMenuTests(unittest.TestCase):
with patch.object(hub, "detect_all", return_value=statuses), \
patch.object(hub, "REGISTRY", infos):
# Convert(Enter), setup-entry(Enter), Esc on setup menu,
- # back at main menu -> Down x3 -> Enter (Quit).
+ # back at main menu -> Down x4 -> Enter (Quit).
screen = FakeScreen(keys=[10, 10, 27,
FakeCurses.KEY_DOWN, FakeCurses.KEY_DOWN,
- FakeCurses.KEY_DOWN, 10])
+ FakeCurses.KEY_DOWN, FakeCurses.KEY_DOWN,
+ 10])
result = hub._hub_menu(screen)
self.assertIsNone(result)
+class SelectSpecTests(unittest.TestCase):
+ """_select_spec: mode-aware server selection (qwen has two servers)."""
+
+ def _qwen_status(self):
+ return BackendStatus(
+ "qwen", "qwen-tts", installed=True, configured=True,
+ servers=[ServerSpec("qwen-custom", "http://127.0.0.1:7860", []),
+ ServerSpec("qwen-clone", "http://127.0.0.1:7861", [])])
+
+ def test_qwen_custom_mode(self):
+ spec = hub._select_spec(self._qwen_status(), {"clone": None})
+ self.assertEqual(spec.name, "qwen-custom")
+
+ def test_qwen_clone_mode(self):
+ spec = hub._select_spec(self._qwen_status(), {"clone": "ref.wav"})
+ self.assertEqual(spec.name, "qwen-clone")
+
+ def test_audiocpp_returns_single_spec(self):
+ st = BackendStatus("audiocpp", "audio.cpp", installed=True,
+ configured=True,
+ servers=[ServerSpec("audiocpp", "http://x", [])])
+ spec = hub._select_spec(st, {})
+ self.assertEqual(spec.name, "audiocpp")
+
+ def test_none_when_no_servers(self):
+ st = BackendStatus("qwen", "qwen-tts", installed=False,
+ configured=False)
+ self.assertIsNone(hub._select_spec(st, {}))
+
+
+class RunConversionTests(unittest.TestCase):
+ """_run_conversion: autostart, hint-when-manual, and stop-after."""
+
+ def test_autostart_starts_server_then_converts(self):
+ spec = ServerSpec("qwen-custom", "http://127.0.0.1:7860", ["x"])
+ status = BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, running=False,
+ servers=[spec])
+ kwargs = {"autostart": "qwen-custom"}
+ with patch.object(hub, "detect_all", return_value=[status]), \
+ patch.object(hub, "_find_spec", return_value=spec), \
+ patch.object(hub.servers, "start", return_value=True) as mk_start, \
+ patch.object(hub.audiobook, "convert", return_value=0) as mk_conv, \
+ patch("builtins.input", return_value="n") as mk_input, \
+ patch.object(hub.servers, "stop") as mk_stop:
+ hub._run_conversion("qwen", kwargs)
+ mk_start.assert_called_once_with(spec)
+ mk_conv.assert_called_once()
+ # User declined stopping → stop not called.
+ mk_stop.assert_not_called()
+
+ def test_autostart_stop_when_user_says_yes(self):
+ spec = ServerSpec("qwen-custom", "http://127.0.0.1:7860", ["x"])
+ status = BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, running=False,
+ servers=[spec])
+ kwargs = {"autostart": "qwen-custom"}
+ with patch.object(hub, "detect_all", return_value=[status]), \
+ patch.object(hub, "_find_spec", return_value=spec), \
+ patch.object(hub.servers, "start", return_value=True), \
+ patch.object(hub.audiobook, "convert", return_value=0), \
+ patch("builtins.input", return_value="y"), \
+ patch.object(hub.servers, "stop") as mk_stop:
+ hub._run_conversion("qwen", kwargs)
+ mk_stop.assert_called_once_with("qwen-custom")
+
+ def test_autostart_aborts_when_server_fails(self):
+ spec = ServerSpec("qwen-custom", "http://127.0.0.1:7860", ["x"])
+ status = BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, running=False,
+ launch_hint="hint cmd", servers=[spec])
+ kwargs = {"autostart": "qwen-custom"}
+ with patch.object(hub, "detect_all", return_value=[status]), \
+ patch.object(hub, "_find_spec", return_value=spec), \
+ patch.object(hub.servers, "start", return_value=False), \
+ patch.object(hub.audiobook, "convert") as mk_conv, \
+ patch.object(hub.servers, "stop") as mk_stop:
+ hub._run_conversion("qwen", kwargs)
+ mk_conv.assert_not_called()
+ mk_stop.assert_not_called()
+
+ def test_no_autostart_prints_hint_when_not_running(self):
+ status = BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, running=False,
+ launch_hint="the-hint")
+ with patch.object(hub, "detect_all", return_value=[status]), \
+ patch.object(hub.audiobook, "convert", return_value=0) as mk_conv:
+ hub._run_conversion("qwen", {})
+ mk_conv.assert_called_once()
+
+
+class AddAutostartTests(unittest.TestCase):
+ """_add_autostart: offers to start the server when it isn't running."""
+
+ def setUp(self):
+ tui._THEME.clear()
+ self.curses = FakeCurses()
+ self._patcher = patch.dict("sys.modules", {"curses": self.curses})
+ self._patcher.start()
+ self.addCleanup(self._patcher.stop)
+ self.addCleanup(tui._THEME.clear)
+
+ def _status(self):
+ spec = ServerSpec("qwen-custom", "http://127.0.0.1:7860", ["x"])
+ return BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, running=False,
+ servers=[spec])
+
+ def test_sets_autostart_when_user_confirms(self):
+ screen = FakeScreen(keys=[10]) # Enter = Yes
+ cmd = ("convert", "qwen", {"clone": None})
+ with patch.object(hub, "detect_all", return_value=[self._status()]), \
+ patch("backends.common.server_running", return_value=False):
+ hub._add_autostart(screen, cmd, [self._status()])
+ self.assertEqual(cmd[2]["autostart"], "qwen-custom")
+
+ def test_no_autostart_when_server_already_running(self):
+ screen = FakeScreen(keys=[10])
+ cmd = ("convert", "qwen", {"clone": None})
+ with patch.object(hub, "detect_all", return_value=[self._status()]), \
+ patch("backends.common.server_running", return_value=True):
+ hub._add_autostart(screen, cmd, [self._status()])
+ self.assertNotIn("autostart", cmd[2])
+
+
if __name__ == "__main__":
unittest.main()