diff options
| author | historia <historiavg@proton.me> | 2026-08-24 17:37:34 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-24 17:37:34 -0400 |
| commit | d950fc8e64ee508334e608f6045d687d73a464be (patch) | |
| tree | 87e5539b486c7f15ffba53bbba6ef6bb3a02540e /app/tests/test_hub.py | |
| parent | 919544c0931d53bb81904b6212ff14f856549da3 (diff) | |
| download | tts-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.py | 191 |
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): |
