aboutsummaryrefslogtreecommitdiff
path: root/app/tests/test_hub.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-24 17:37:34 -0400
committerhistoria <historiavg@proton.me>2026-08-24 17:37:34 -0400
commitd950fc8e64ee508334e608f6045d687d73a464be (patch)
tree87e5539b486c7f15ffba53bbba6ef6bb3a02540e /app/tests/test_hub.py
parent919544c0931d53bb81904b6212ff14f856549da3 (diff)
downloadtts-audiobook-generator-d950fc8e64ee508334e608f6045d687d73a464be.tar.gz
feat: tui backend server progress and generate script progress
Diffstat (limited to 'app/tests/test_hub.py')
-rw-r--r--app/tests/test_hub.py191
1 files changed, 112 insertions, 79 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index a0545cc..5f91a61 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -917,92 +917,125 @@ class SelectSpecTests(unittest.TestCase):
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()
-
- def test_remote_conversion_skips_setup_checks(self):
- # A remote conversion targets an external server: no autostart, no
- # "not fully set up" warning, no launch hint — just convert.
- with patch.object(hub, "detect_all", return_value=[]) as mk_detect, \
- patch.object(hub.audiobook, "convert", return_value=0) as mk_conv:
- hub._run_conversion("audiocpp", {"api_url": "http://10.0.0.5:8080"})
- mk_conv.assert_called_once_with(
- backend="audiocpp", api_url="http://10.0.0.5:8080")
+class PrepareRunConfigTests(unittest.TestCase):
+ """_prepare_run_config: the run view's inputs from the accepted form."""
+
+ def _spec(self, name="qwen-custom", url="http://127.0.0.1:7860"):
+ return ServerSpec(name, url, ["x"])
+
+ def test_remote_targets_the_api_url(self):
+ with patch.object(hub, "detect_all", return_value=[]) as mk_detect:
+ cfg = hub._prepare_run_config(
+ "audiocpp", {"api_url": "http://10.0.0.5:8080"})
+ self.assertEqual(cfg.server_url, "http://10.0.0.5:8080")
+ self.assertIsNone(cfg.autostart_spec)
+ self.assertEqual(cfg.server_identity, "audiocpp")
+ self.assertIn("remote", cfg.backend_label)
# The remote path never re-detects or touches managed-instance state.
mk_detect.assert_not_called()
- def test_managed_conversion_warns_when_port_occupied_by_other_server(self):
+ def test_autostart_sets_the_spec_and_pops_the_flag(self):
+ spec = self._spec()
+ kwargs = {"autostart": "qwen-custom"}
+ with patch.object(hub, "detect_all", return_value=[]), \
+ patch.object(hub, "_find_spec", return_value=spec):
+ cfg = hub._prepare_run_config("qwen", kwargs)
+ self.assertIs(cfg.autostart_spec, spec)
+ self.assertEqual(cfg.server_name, "qwen-custom")
+ self.assertNotIn("autostart", kwargs)
+
+ def test_autostart_with_missing_spec_continues_with_notice(self):
+ kwargs = {"autostart": "gone"}
+ with patch.object(hub, "detect_all", return_value=[]), \
+ patch.object(hub, "_find_spec", return_value=None):
+ cfg = hub._prepare_run_config("qwen", kwargs)
+ self.assertIsNone(cfg.autostart_spec)
+ self.assertIn("gone", cfg.notice)
+
+ def test_managed_conversion_flags_foreign_server_on_port(self):
spec = ServerSpec("audiocpp", "http://127.0.0.1:8080", ["x"])
status = BackendStatus("audiocpp", "audio.cpp", installed=True,
- configured=True, running=False,
- servers=[spec])
+ configured=True, servers=[spec])
with patch.object(hub, "detect_all", return_value=[status]), \
- patch.object(hub, "_select_spec", return_value=spec), \
patch("backends.common.server_running", return_value=True), \
- patch.object(hub.servers, "alive", return_value=False), \
- patch.object(hub.audiobook, "convert", return_value=0) as mk_conv, \
- patch("builtins.print") as mk_print:
- hub._run_conversion("audiocpp", {})
- mk_conv.assert_called_once()
- printed = " ".join(str(call.args[0]) for call in mk_print.call_args_list)
- self.assertIn("did not start", printed)
+ patch.object(hub.servers, "alive", return_value=False):
+ cfg = hub._prepare_run_config("audiocpp", {})
+ self.assertEqual(cfg.server_url, spec.url)
+ self.assertIsNone(cfg.autostart_spec)
+ self.assertIn("did not start", cfg.notice)
+
+ def test_managed_not_running_sets_url_without_autostart(self):
+ spec = self._spec()
+ status = BackendStatus("qwen", "qwen-tts", installed=True,
+ configured=True, servers=[spec])
+ with patch.object(hub, "detect_all", return_value=[status]), \
+ patch("backends.common.server_running", return_value=False):
+ cfg = hub._prepare_run_config("qwen", {"clone": None})
+ self.assertEqual(cfg.server_url, spec.url)
+ self.assertIsNone(cfg.autostart_spec)
+
+
+class PreflightTests(unittest.TestCase):
+ """_preflight: overwrite prompts run in the TUI, plan stashed in kwargs."""
+
+ def _cmd(self):
+ return ("convert", "qwen", {"clone": None, "output_format": "mp3"})
+
+ def test_books_stashed_on_kwargs(self):
+ stdscr = object()
+ cmd = self._cmd()
+ with patch.object(hub.AudiobookConverter, "preflight_overwrites",
+ return_value=(["book.txt"], [("book.txt", "x")])) \
+ as mk_pre:
+ self.assertTrue(hub._preflight(stdscr, cmd))
+ self.assertEqual(cmd[2]["book_files"], ["book.txt"])
+ self.assertEqual(cmd[2]["planned"], [("book.txt", "x")])
+ # The confirm callback passed to preflight is a TUI yes/no.
+ confirm = mk_pre.call_args.kwargs["confirm"]
+ with patch.object(hub.tui, "confirm", return_value=True) as mk_confirm:
+ self.assertTrue(confirm("overwrite?", True))
+ mk_confirm.assert_called_once()
+
+ def test_nothing_to_convert_flashes_and_returns_false(self):
+ stdscr = object()
+ with patch.object(hub.AudiobookConverter, "preflight_overwrites",
+ return_value=([], [])), \
+ patch.object(hub.tui, "flash") as mk_flash:
+ self.assertFalse(hub._preflight(stdscr, self._cmd()))
+ mk_flash.assert_called_once()
+
+ def test_all_skipped_flashes_and_returns_false(self):
+ stdscr = object()
+ with patch.object(hub.AudiobookConverter, "preflight_overwrites",
+ return_value=(["book.txt"], [])), \
+ patch.object(hub.tui, "flash") as mk_flash:
+ self.assertFalse(hub._preflight(stdscr, self._cmd()))
+ mk_flash.assert_called_once()
+
+
+class DispatchConversionTests(unittest.TestCase):
+ """_dispatch_conversion: builds the config and runs the run view."""
+
+ def test_runs_run_view_inside_curses(self):
+ from tests.test_tui import FakeScreen
+
+ class FakeView:
+ def __init__(self, scr, config):
+ self.config = config
+ def run(self):
+ pass
+
+ made = []
+ with patch.object(hub, "_prepare_run_config",
+ return_value=hub.runview.RunConfig(
+ backend="qwen", backend_label="qwen-tts",
+ kwargs={}, book_files=[], planned=[])) as mk_cfg, \
+ patch("curses.wrapper",
+ side_effect=lambda cb: cb(FakeScreen())) as mk_wrapper, \
+ patch.object(hub.runview, "RunView", FakeView):
+ hub._dispatch_conversion("qwen", {})
+ mk_cfg.assert_called_once()
+ mk_wrapper.assert_called_once()
class AddAutostartTests(unittest.TestCase):