diff options
| author | historia <historiavg@proton.me> | 2026-08-26 02:25:55 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-26 02:25:55 -0400 |
| commit | 8b5c8697740ff415cf7f1d03c9fb5a8c8851d420 (patch) | |
| tree | 28c0323c54c896af5f89fb34b89a62e0fe0df291 /app/tests | |
| parent | acbd9ff2c91182d96c57ffb57bee6e9b3fcbcbd4 (diff) | |
| download | tts-audiobook-generator-8b5c8697740ff415cf7f1d03c9fb5a8c8851d420.tar.gz | |
refactor: audiocpp.py setup flow
Diffstat (limited to 'app/tests')
| -rw-r--r-- | app/tests/test_backends.py | 10 | ||||
| -rw-r--r-- | app/tests/test_backends_audiocpp.py | 497 | ||||
| -rw-r--r-- | app/tests/test_backends_faster.py | 3 | ||||
| -rw-r--r-- | app/tests/test_hub.py | 9 |
4 files changed, 262 insertions, 257 deletions
diff --git a/app/tests/test_backends.py b/app/tests/test_backends.py index 47dc5d4..4ff6f6e 100644 --- a/app/tests/test_backends.py +++ b/app/tests/test_backends.py @@ -71,7 +71,7 @@ class DetectAllTests(unittest.TestCase): (checkout / "server.json").write_text('{"models":[]}', encoding="utf-8") from backends import audiocpp - with patch.object(audiocpp, "find_local_checkout", + with patch.object(audiocpp.build, "find_local_checkout", return_value=checkout), \ patch("backends.common.server_running", return_value=False): @@ -84,9 +84,9 @@ class DetectAllTests(unittest.TestCase): def test_audiocpp_running_when_remote_server_identified(self): from backends import audiocpp - with patch.object(audiocpp, "find_local_checkout", + with patch.object(audiocpp.build, "find_local_checkout", return_value=None), \ - patch.object(audiocpp.probe, "identify_server", + patch.object(audiocpp.status.probe, "identify_server", return_value="audiocpp"): status = audiocpp.detect() # Not installed (no checkout) but a remote server answers. @@ -280,12 +280,12 @@ class RemoteSuppressionTests(unittest.TestCase): encoding="utf-8") (Path(td) / "audiocpp-server.pid").write_text( "4242", encoding="utf-8") - with patch.object(audiocpp, "find_local_checkout", + with patch.object(audiocpp.build, "find_local_checkout", return_value=checkout), \ patch.object(servers_mod, "LOG_DIR", Path(td)), \ patch.object(servers_mod, "_pid_alive", return_value=True), \ - patch.object(audiocpp.probe, "identify_server", + patch.object(audiocpp.status.probe, "identify_server", return_value="audiocpp"): status = audiocpp.detect() self.assertTrue(status.managed) diff --git a/app/tests/test_backends_audiocpp.py b/app/tests/test_backends_audiocpp.py index 05b47bd..59bd039 100644 --- a/app/tests/test_backends_audiocpp.py +++ b/app/tests/test_backends_audiocpp.py @@ -13,7 +13,10 @@ from unittest.mock import MagicMock, patch from converter import config from backends import audiocpp as make_server -from backends import common +import os + +from backends import common, servers +from ui import taskview from ui import tui FAKE_CONFIG = ( @@ -132,17 +135,17 @@ class FindWavFilesTests(unittest.TestCase): self._touch("notes.txt") (self.folder / "sub").mkdir() (self.folder / "sub" / "c.wav").write_bytes(b"x") - names = [path.name for path in make_server.find_wav_files(self.folder)] + names = [path.name for path in common.find_wav_files(self.folder)] self.assertEqual(names, ["a.WAV", "b.wav"]) def test_sorted_alphabetically_case_insensitive(self): for name in ("Zed.wav", "alpha.wav", "Beta.wav"): self._touch(name) - names = [path.name for path in make_server.find_wav_files(self.folder)] + names = [path.name for path in common.find_wav_files(self.folder)] self.assertEqual(names, ["alpha.wav", "Beta.wav", "Zed.wav"]) def test_empty_directory_returns_empty_list(self): - self.assertEqual(make_server.find_wav_files(self.folder), []) + self.assertEqual(common.find_wav_files(self.folder), []) class DetectWavDirTests(unittest.TestCase): @@ -167,42 +170,42 @@ class DetectWavDirTests(unittest.TestCase): def test_unique_wav_dir_in_tts_root_returned(self): found = self._wav_dir(self.tts_root, "voices") - self.assertEqual(make_server.detect_wav_dir(self.audiocpp, + self.assertEqual(common.detect_wav_dir(self.audiocpp, self.tts_root), found) def test_unique_wav_dir_in_audiocpp_root_returned(self): found = self._wav_dir(self.audiocpp, "reference") - self.assertEqual(make_server.detect_wav_dir(self.audiocpp, + self.assertEqual(common.detect_wav_dir(self.audiocpp, self.tts_root), found) def test_root_itself_containing_wavs_returned(self): (self.tts_root / "direct.wav").write_bytes(b"x") - self.assertEqual(make_server.detect_wav_dir(self.audiocpp, + self.assertEqual(common.detect_wav_dir(self.audiocpp, self.tts_root), self.tts_root) def test_multiple_wav_dirs_returns_none(self): self._wav_dir(self.tts_root, "one") self._wav_dir(self.audiocpp, "two") - self.assertIsNone(make_server.detect_wav_dir(self.audiocpp, + self.assertIsNone(common.detect_wav_dir(self.audiocpp, self.tts_root)) def test_output_dir_of_tts_root_excluded(self): self._wav_dir(self.tts_root, "output") - self.assertIsNone(make_server.detect_wav_dir(self.audiocpp, + self.assertIsNone(common.detect_wav_dir(self.audiocpp, self.tts_root)) def test_no_wavs_returns_none(self): - self.assertIsNone(make_server.detect_wav_dir(self.audiocpp, + self.assertIsNone(common.detect_wav_dir(self.audiocpp, self.tts_root)) def test_nested_wav_dir_not_seen(self): nested = self.tts_root / "outer" / "inner" nested.mkdir(parents=True) (nested / "voice.wav").write_bytes(b"x") - self.assertIsNone(make_server.detect_wav_dir(self.audiocpp, + self.assertIsNone(common.detect_wav_dir(self.audiocpp, self.tts_root)) @@ -210,27 +213,27 @@ class ConfigPortTests(unittest.TestCase): def test_port_parsed_from_config_url(self): with patch.object(config, "AUDIOCPP_API_URL", "http://127.0.0.1:8080"): - self.assertEqual(make_server.config_port(), 8080) + self.assertEqual(make_server.configsync.config_port(), 8080) def test_missing_port_falls_back(self): with patch.object(config, "AUDIOCPP_API_URL", "http://127.0.0.1"): - self.assertEqual(make_server.config_port(), + self.assertEqual(make_server.configsync.config_port(), make_server.FALLBACK_PORT) def test_invalid_url_falls_back(self): with patch.object(config, "AUDIOCPP_API_URL", "not a url"): - self.assertEqual(make_server.config_port(), + self.assertEqual(make_server.configsync.config_port(), make_server.FALLBACK_PORT) def test_url_with_port_replaces_port(self): # audiocpp reuses the shared helper (backends.common.url_with_port). self.assertEqual( - make_server.url_with_port("http://127.0.0.1:8080", 9000), + common.url_with_port("http://127.0.0.1:8080", 9000), "http://127.0.0.1:9000") def test_url_without_port_adds_port(self): self.assertEqual( - make_server.url_with_port("http://localhost", 8080), + common.url_with_port("http://localhost", 8080), "http://localhost:8080") @@ -247,7 +250,7 @@ class UpdateConfigPortTests(unittest.TestCase): self._tmp.cleanup() def test_rewrites_port_preserving_comment(self): - changed = make_server.update_config_api_url_port( + changed = make_server.configsync.update_config_api_url_port( 8080, config_path=self.config_path) self.assertTrue(changed) text = self.config_path.read_text(encoding="utf-8") @@ -260,18 +263,18 @@ class UpdateConfigPortTests(unittest.TestCase): def test_returns_false_when_no_url_line(self): path = Path(self._tmp.name) / "other.py" path.write_text('CHUNK_SIZE = 250\n', encoding="utf-8") - self.assertFalse(make_server.update_config_api_url_port( + self.assertFalse(make_server.configsync.update_config_api_url_port( 8080, config_path=path)) def test_port_unchanged_is_a_success_noop(self): # The file already holds the port: success, nothing rewritten. - self.assertTrue(make_server.update_config_api_url_port( + self.assertTrue(make_server.configsync.update_config_api_url_port( 9999, config_path=self.config_path)) self.assertEqual(self.config_path.read_text(encoding="utf-8"), FAKE_CONFIG) def test_returns_false_when_file_missing(self): - self.assertFalse(make_server.update_config_api_url_port( + self.assertFalse(make_server.configsync.update_config_api_url_port( 8080, config_path=Path(self._tmp.name) / "nope.py")) @@ -291,7 +294,7 @@ class UpdateConfigModelIdsTests(unittest.TestCase): self._tmp.cleanup() def test_rewrites_both_ids_preserving_lines(self): - changed = make_server.update_config_model_ids( + changed = make_server.configsync.update_config_model_ids( "higgs", "higgs", config_path=self.config_path) self.assertTrue(changed) text = self.config_path.read_text(encoding="utf-8") @@ -301,7 +304,7 @@ class UpdateConfigModelIdsTests(unittest.TestCase): self.assertIn('AUDIOCPP_API_URL = "http://127.0.0.1:9999"', text) def test_clone_id_optional(self): - changed = make_server.update_config_model_ids( + changed = make_server.configsync.update_config_model_ids( "voxcpm2", config_path=self.config_path) self.assertTrue(changed) text = self.config_path.read_text(encoding="utf-8") @@ -310,7 +313,7 @@ class UpdateConfigModelIdsTests(unittest.TestCase): def test_ids_unchanged_is_a_success_noop(self): # Both ids already hold their values: success, nothing rewritten. - changed = make_server.update_config_model_ids( + changed = make_server.configsync.update_config_model_ids( "qwen", "qwen-clone", config_path=self.config_path) self.assertTrue(changed) self.assertEqual(self.config_path.read_text(encoding="utf-8"), @@ -319,11 +322,11 @@ class UpdateConfigModelIdsTests(unittest.TestCase): def test_returns_false_when_lines_missing(self): path = Path(self._tmp.name) / "other.py" path.write_text('CHUNK_SIZE = 250\n', encoding="utf-8") - self.assertFalse(make_server.update_config_model_ids( + self.assertFalse(make_server.configsync.update_config_model_ids( "higgs", "higgs", config_path=path)) def test_returns_false_when_file_missing(self): - self.assertFalse(make_server.update_config_model_ids( + self.assertFalse(make_server.configsync.update_config_model_ids( "higgs", "higgs", config_path=Path(self._tmp.name) / "nope.py")) @@ -337,32 +340,32 @@ class ResolveWavDirArgTests(unittest.TestCase): self._tmp.cleanup() def test_resolves_to_absolute(self): - self.assertEqual(make_server.resolve_wav_dir_arg(str(self.folder)), + self.assertEqual(common.resolve_wav_dir_arg(str(self.folder)), self.folder.resolve()) def test_strips_surrounding_quotes(self): quoted = f'"{self.folder}"' - self.assertEqual(make_server.resolve_wav_dir_arg(quoted), + self.assertEqual(common.resolve_wav_dir_arg(quoted), self.folder.resolve()) def test_strips_single_quotes(self): quoted = f"'{self.folder}'" - self.assertEqual(make_server.resolve_wav_dir_arg(quoted), + self.assertEqual(common.resolve_wav_dir_arg(quoted), self.folder.resolve()) def test_strips_whitespace(self): - self.assertEqual(make_server.resolve_wav_dir_arg(f" {self.folder} "), + self.assertEqual(common.resolve_wav_dir_arg(f" {self.folder} "), self.folder.resolve()) def test_expands_tilde(self): - with patch.object(make_server.os.path, "expanduser", + with patch.object(os.path, "expanduser", return_value=str(self.folder)) as mock_expand: - result = make_server.resolve_wav_dir_arg("~/voices") + result = common.resolve_wav_dir_arg("~/voices") mock_expand.assert_called_once_with("~/voices") self.assertEqual(result, self.folder.resolve()) def test_trailing_slash_preserved_as_dir(self): - self.assertEqual(make_server.resolve_wav_dir_arg(f"{self.folder}/"), + self.assertEqual(common.resolve_wav_dir_arg(f"{self.folder}/"), self.folder.resolve()) @@ -388,20 +391,20 @@ class FindLocalCheckoutTests(unittest.TestCase): def test_none_when_no_checkout_in_app_dir(self): with tempfile.TemporaryDirectory() as td, \ - patch.object(make_server, "APP_DIR", Path(td)): - self.assertIsNone(make_server.find_local_checkout()) + patch.object(make_server.build, "APP_DIR", Path(td)): + self.assertIsNone(make_server.build.find_local_checkout()) def test_returns_the_managed_checkout(self): with tempfile.TemporaryDirectory() as td, \ - patch.object(make_server, "APP_DIR", Path(td)): + patch.object(make_server.build, "APP_DIR", Path(td)): checkout = _make_checkout(Path(td)) - self.assertEqual(make_server.find_local_checkout(), checkout) + self.assertEqual(make_server.build.find_local_checkout(), checkout) def test_none_when_checkout_lacks_model_specs(self): with tempfile.TemporaryDirectory() as td, \ - patch.object(make_server, "APP_DIR", Path(td)): + patch.object(make_server.build, "APP_DIR", Path(td)): (Path(td) / "audio.cpp").mkdir() - self.assertIsNone(make_server.find_local_checkout()) + self.assertIsNone(make_server.build.find_local_checkout()) class LoadModelCatalogTests(unittest.TestCase): @@ -413,7 +416,7 @@ class LoadModelCatalogTests(unittest.TestCase): self._td.cleanup() def test_includes_tts_families_excludes_asr(self): - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) families = [entry["family"] for entry in catalog] self.assertIn("qwen3_tts", families) self.assertIn("higgs_audio_tts", families) @@ -422,19 +425,19 @@ class LoadModelCatalogTests(unittest.TestCase): self.assertNotIn("qwen3_asr", families) def test_skips_families_with_no_packages(self): - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) self.assertNotIn("empty_tts", [entry["family"] for entry in catalog]) def test_families_sorted_alphabetically_by_display_name(self): - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) names = [entry["display_name"].lower() for entry in catalog] self.assertEqual(names, sorted(names)) self.assertNotIn("tested", catalog[0]) self.assertNotIn("TESTED_FAMILIES", dir(make_server)) def test_default_package_and_target_directory_resolved(self): - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) by_family = {entry["family"]: entry for entry in catalog} higgs = by_family["higgs_audio_tts"] self.assertEqual(higgs["install_id"], "higgs_audio_tts_4b_q8_0") @@ -449,12 +452,12 @@ class LoadModelCatalogTests(unittest.TestCase): {"id": "voxcpm2_q8_0", "format": "gguf", "target_directory": "VoxCPM2-GGUF"}, ]) - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) by_family = {entry["family"]: entry for entry in catalog} self.assertEqual(by_family["voxcpm2"]["install_id"], "voxcpm2_bf16") def test_clone_capability_from_tasks(self): - catalog = make_server.load_model_catalog(self.checkout) + catalog = make_server.catalog.load_model_catalog(self.checkout) by_family = {entry["family"]: entry for entry in catalog} self.assertTrue(by_family["higgs_audio_tts"]["clone_capable"]) self.assertFalse(by_family["supertonic"]["clone_capable"]) @@ -463,7 +466,7 @@ class LoadModelCatalogTests(unittest.TestCase): empty = Path(self._td.name) / "empty" empty.mkdir() with self.assertRaises(NotADirectoryError): - make_server.load_model_catalog(empty) + make_server.catalog.load_model_catalog(empty) class DetectBackendTests(unittest.TestCase): @@ -485,58 +488,58 @@ class DetectBackendTests(unittest.TestCase): return build_dir def test_no_build_dir_returns_none(self): - self.assertIsNone(make_server.detect_backend(self.checkout)) + self.assertIsNone(make_server.catalog.detect_backend(self.checkout)) def test_unique_linux_backend_detected(self): self._build("linux-cuda-release") - self.assertEqual(make_server.detect_backend(self.checkout), "cuda") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "cuda") def test_windows_exe_backend_detected(self): self._build("windows-vulkan-debug", binary="audiocpp_server.exe") - self.assertEqual(make_server.detect_backend(self.checkout), "vulkan") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "vulkan") def test_hip_backend_detected(self): self._build("linux-hip-release") - self.assertEqual(make_server.detect_backend(self.checkout), "hip") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "hip") def test_cpu_backend_detected(self): self._build("linux-cpu-release") - self.assertEqual(make_server.detect_backend(self.checkout), "cpu") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "cpu") def test_metal_maps_to_cpu(self): self._build("macos-metal-release") - self.assertEqual(make_server.detect_backend(self.checkout), "cpu") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "cpu") def test_multiple_backends_returns_none(self): self._build("linux-cuda-release") self._build("linux-cpu-release") - self.assertIsNone(make_server.detect_backend(self.checkout)) + self.assertIsNone(make_server.catalog.detect_backend(self.checkout)) def test_multiple_builds_same_backend_detected(self): self._build("linux-cuda-release") self._build("windows-cuda-debug") - self.assertEqual(make_server.detect_backend(self.checkout), "cuda") + self.assertEqual(make_server.catalog.detect_backend(self.checkout), "cuda") def test_build_dir_without_binary_ignored(self): (self.checkout / "build" / "linux-cuda-release").mkdir(parents=True) - self.assertIsNone(make_server.detect_backend(self.checkout)) + self.assertIsNone(make_server.catalog.detect_backend(self.checkout)) def test_non_matching_build_dir_name_ignored(self): self._build("linux-mybuild-release") - self.assertIsNone(make_server.detect_backend(self.checkout)) + self.assertIsNone(make_server.catalog.detect_backend(self.checkout)) class BackendOptionsTests(unittest.TestCase): """Aligned backend menu labels and the [auto-detected] default.""" def test_options_have_aligned_dashes(self): - options, default_index = make_server._backend_options() + options, default_index = make_server.catalog._backend_options() dash_columns = {label.index(" - ") for label, _ in options} self.assertEqual(len(dash_columns), 1) self.assertEqual(default_index, 0) def test_detected_backend_marked_and_defaulted(self): - options, default_index = make_server._backend_options("vulkan") + options, default_index = make_server.catalog._backend_options("vulkan") labels = [label for label, _ in options] self.assertEqual(default_index, labels.index(next( label for label, value in options @@ -545,22 +548,22 @@ class BackendOptionsTests(unittest.TestCase): self.assertEqual(options[default_index][1], "vulkan") def test_unknown_detected_backend_is_ignored(self): - options, default_index = make_server._backend_options("opencl") + options, default_index = make_server.catalog._backend_options("opencl") self.assertEqual(default_index, 0) self.assertFalse(any("[auto-detected]" in label for label, _ in options)) def test_labels_keep_backend_values(self): - options, _ = make_server._backend_options() + options, _ = make_server.catalog._backend_options() self.assertEqual([value for _, value in options], list(make_server.BACKENDS)) class BuildServerConfigTests(unittest.TestCase): def test_single_entry_without_voice_dir(self): - entry = make_server.build_model_entry( + entry = make_server.catalog.build_model_entry( "higgs_audio_tts", "higgs", "models/Higgs-GGUF") - cfg = make_server.build_server_config( + cfg = make_server.catalog.build_server_config( "127.0.0.1", 8080, "cuda", False, [entry]) self.assertEqual(cfg["host"], "127.0.0.1") self.assertEqual(cfg["port"], 8080) @@ -570,15 +573,15 @@ class BuildServerConfigTests(unittest.TestCase): self.assertNotIn("voice_dir", cfg) def test_voice_dir_added_when_given(self): - entry = make_server.build_model_entry("voxcpm2", "voxcpm2", "models/V") - cfg = make_server.build_server_config( + entry = make_server.catalog.build_model_entry("voxcpm2", "voxcpm2", "models/V") + cfg = make_server.catalog.build_server_config( "0.0.0.0", 9000, "cpu", True, [entry], voice_dir="/abs/voices") self.assertTrue(cfg["lazy_load"]) self.assertEqual(cfg["voice_dir"], "/abs/voices") def test_model_entry_shape(self): - entry = make_server.build_model_entry("index_tts2", "indextts2", "p") + entry = make_server.catalog.build_model_entry("index_tts2", "indextts2", "p") self.assertEqual(entry["id"], "indextts2") self.assertEqual(entry["family"], "index_tts2") self.assertEqual(entry["path"], "p") @@ -586,7 +589,7 @@ class BuildServerConfigTests(unittest.TestCase): self.assertEqual(entry["mode"], "offline") def test_model_entry_design_task(self): - entry = make_server.build_model_entry( + entry = make_server.catalog.build_model_entry( "qwen3_tts", "qwen-design", "p", task="vdes") self.assertEqual(entry["task"], "vdes") self.assertEqual(entry["mode"], "offline") @@ -612,9 +615,9 @@ class InstallModelsTests(unittest.TestCase): def test_declined_download_prints_commands_deduped(self): buf = io.StringIO() with redirect_stdout(buf), \ - patch.object(make_server.common, + patch.object(common, "run_console_subprocess") as run: - make_server._install_models(self.checkout, self.guidance, + make_server.models._install_models(self.checkout, self.guidance, download=False) out = buf.getvalue() self.assertEqual(out.count("install higgs_audio_tts_4b_q8_0"), 1) @@ -622,9 +625,9 @@ class InstallModelsTests(unittest.TestCase): run.assert_not_called() def test_accepted_download_runs_each_command(self): - with patch.object(make_server.common, + with patch.object(common, "run_console_subprocess", return_value=0) as run: - make_server._install_models(self.checkout, self.guidance, + make_server.models._install_models(self.checkout, self.guidance, download=True) self.assertEqual(run.call_count, 2) commands = [call[0][0] for call in run.call_args_list] @@ -641,9 +644,9 @@ class InstallModelsTests(unittest.TestCase): self.manager.unlink() buf = io.StringIO() with redirect_stdout(buf), \ - patch.object(make_server.common, + patch.object(common, "run_console_subprocess") as run: - make_server._install_models(self.checkout, self.guidance, + make_server.models._install_models(self.checkout, self.guidance, download=True) self.assertIn("install higgs_audio_tts_4b_q8_0", buf.getvalue()) run.assert_not_called() @@ -652,9 +655,9 @@ class InstallModelsTests(unittest.TestCase): results = iter([1, 0]) buf = io.StringIO() with redirect_stdout(buf), \ - patch.object(make_server.common, "run_console_subprocess", + patch.object(common, "run_console_subprocess", side_effect=lambda *a, **k: next(results)) as run: - make_server._install_models(self.checkout, self.guidance, + make_server.models._install_models(self.checkout, self.guidance, download=True) self.assertEqual(run.call_count, 2) self.assertIn("exited with code 1", buf.getvalue()) @@ -662,17 +665,17 @@ class InstallModelsTests(unittest.TestCase): def test_decide_download_skips_prompt_without_manager(self): self.manager.unlink() confirm = MagicMock() - self.assertFalse(make_server._decide_download(self.checkout, [], confirm)) + self.assertFalse(make_server.models._decide_download(self.checkout, [], confirm)) confirm.assert_not_called() def test_decide_download_asks_when_manager_present(self): confirm = MagicMock(return_value=True) - self.assertTrue(make_server._decide_download(self.checkout, [], confirm)) + self.assertTrue(make_server.models._decide_download(self.checkout, [], confirm)) confirm.assert_called_once() def test_decide_download_defaults_to_yes(self): confirm = MagicMock(return_value=True) - make_server._decide_download(self.checkout, [], confirm) + make_server.models._decide_download(self.checkout, [], confirm) self.assertIs(confirm.call_args[0][1], True) def test_decide_download_skips_prompt_when_all_models_present(self): @@ -680,7 +683,7 @@ class InstallModelsTests(unittest.TestCase): target.mkdir(parents=True) (target / "model.gguf").write_bytes(b"x") confirm = MagicMock() - self.assertFalse(make_server._decide_download( + self.assertFalse(make_server.models._decide_download( self.checkout, [{"path": "models/higgs"}], confirm)) confirm.assert_not_called() @@ -689,7 +692,7 @@ class InstallModelsTests(unittest.TestCase): target.mkdir(parents=True) (target / "model.gguf").write_bytes(b"x") confirm = MagicMock(return_value=True) - self.assertTrue(make_server._decide_download( + self.assertTrue(make_server.models._decide_download( self.checkout, [{"path": "models/higgs"}, {"path": "models/absent"}], confirm)) @@ -699,30 +702,30 @@ class InstallModelsTests(unittest.TestCase): target = self.checkout / "models" / "higgs" target.mkdir(parents=True) (target / "model.gguf").write_bytes(b"x") - self.assertTrue(make_server._all_models_present( + self.assertTrue(make_server.models._all_models_present( self.checkout, [{"path": "models/higgs"}])) def test_all_models_present_false_when_one_missing(self): target = self.checkout / "models" / "higgs" target.mkdir(parents=True) (target / "model.gguf").write_bytes(b"x") - self.assertFalse(make_server._all_models_present( + self.assertFalse(make_server.models._all_models_present( self.checkout, [{"path": "models/higgs"}, {"path": "models/absent"}])) def test_all_models_present_false_for_empty_selection(self): - self.assertFalse(make_server._all_models_present(self.checkout, [])) + self.assertFalse(make_server.models._all_models_present(self.checkout, [])) def test_all_models_present_honors_absolute_paths(self): target = self.checkout / "models" / "higgs" target.mkdir(parents=True) (target / "model.gguf").write_bytes(b"x") - self.assertTrue(make_server._all_models_present( + self.assertTrue(make_server.models._all_models_present( self.checkout, [{"path": str(target)}])) def test_all_models_present_false_for_empty_dir(self): (self.checkout / "models" / "higgs").mkdir(parents=True) - self.assertFalse(make_server._all_models_present( + self.assertFalse(make_server.models._all_models_present( self.checkout, [{"path": "models/higgs"}])) @@ -741,31 +744,31 @@ class TranscribeWavDirTests(unittest.TestCase): def test_transcribes_to_stem_map_with_absolute_paths(self): transcripts = {str(self.narrator): "First.", str(self.other): "Second."} - with patch.object(make_server, "transcribe_reference_audio", + with patch.object(make_server.voices, "transcribe_reference_audio", side_effect=lambda path, model_name="base": transcripts[path]): - result = make_server.transcribe_wav_dir( + result = make_server.voices.transcribe_wav_dir( [self.narrator, self.other], "base") self.assertEqual(list(result), ["narrator", "other"]) self.assertEqual(result["narrator"], "First.") def test_failed_transcription_keeps_empty_string(self): - with patch.object(make_server, "transcribe_reference_audio", + with patch.object(make_server.voices, "transcribe_reference_audio", return_value=None): - result = make_server.transcribe_wav_dir([self.narrator], "base") + result = make_server.voices.transcribe_wav_dir([self.narrator], "base") self.assertEqual(result["narrator"], "") def test_whisper_model_name_passed_through(self): - with patch.object(make_server, "transcribe_reference_audio", + with patch.object(make_server.voices, "transcribe_reference_audio", return_value="text") as mock_transcribe: - make_server.transcribe_wav_dir([self.narrator], "large-v3") + make_server.voices.transcribe_wav_dir([self.narrator], "large-v3") self.assertEqual(mock_transcribe.call_args.kwargs["model_name"], "large-v3") def test_write_prompt_text_format(self): - path = make_server.write_prompt_text( + path = common.write_prompt_text( self.folder, {"narrator": "Hello.", "other": "World."}) - self.assertEqual(path, self.folder / make_server.PROMPT_TEXT_FILENAME) + self.assertEqual(path, self.folder / common.PROMPT_TEXT_FILENAME) text = path.read_text(encoding="utf-8") self.assertIn("narrator|Hello.", text) self.assertIn("other|World.", text) @@ -775,21 +778,21 @@ class DesignPackageTests(unittest.TestCase): """Voice-design package detection.""" def test_detects_voicedesign_in_id(self): - self.assertTrue(make_server.is_design_package( + self.assertTrue(make_server.catalog.is_design_package( {"id": "qwen3_tts_1_7b_voicedesign_q8_0"})) def test_detects_voicedesign_in_directory(self): - self.assertTrue(make_server.is_design_package( + self.assertTrue(make_server.catalog.is_design_package( {"target_directory": "Foo-VoiceDesign-GGUF"})) def test_detects_separated_voice_design(self): - self.assertTrue(make_server.is_design_package( + self.assertTrue(make_server.catalog.is_design_package( {"display_name": "Voice Design Q8_0"})) def test_ignores_other_packages(self): - self.assertFalse(make_server.is_design_package( + self.assertFalse(make_server.catalog.is_design_package( {"id": "higgs_audio_tts_4b_q8_0"})) - self.assertFalse(make_server.is_design_package({})) + self.assertFalse(make_server.catalog.is_design_package({})) class PackageDirOptionsTests(unittest.TestCase): @@ -807,7 +810,7 @@ class PackageDirOptionsTests(unittest.TestCase): "target_directory": "VoiceDesign-GGUF"}, ], } - options = make_server.package_dir_options(entry) + options = make_server.catalog.package_dir_options(entry) self.assertEqual([o["target_directory"] for o in options], ["Base-GGUF", "VoiceDesign-GGUF"]) self.assertTrue(options[0]["recommended"]) @@ -826,7 +829,7 @@ class PackageDirOptionsTests(unittest.TestCase): "target_directory": "Default-GGUF"}, ], } - options = make_server.package_dir_options(entry) + options = make_server.catalog.package_dir_options(entry) self.assertEqual([o["target_directory"] for o in options], ["Default-GGUF", "Other-GGUF"]) @@ -848,25 +851,25 @@ class FindAudiocppServerBinTests(unittest.TestCase): (bin_dir / binary).write_bytes(b"x") def test_no_build_dir_returns_none(self): - self.assertIsNone(make_server.find_audiocpp_server_bin(self.checkout)) + self.assertIsNone(make_server.build.find_audiocpp_server_bin(self.checkout)) def test_finds_built_binary(self): self._build("linux-cuda-release") self.assertEqual( - make_server.find_audiocpp_server_bin(self.checkout), + make_server.build.find_audiocpp_server_bin(self.checkout), self.checkout / "build" / "linux-cuda-release" / "bin" / "audiocpp_server") def test_finds_windows_exe(self): self._build("windows-vulkan-debug", binary="audiocpp_server.exe") self.assertEqual( - make_server.find_audiocpp_server_bin(self.checkout).name, + make_server.build.find_audiocpp_server_bin(self.checkout).name, "audiocpp_server.exe") def test_build_dir_without_binary_returns_none(self): (self.checkout / "build" / "linux-cuda-release" / "bin").mkdir( parents=True) - self.assertIsNone(make_server.find_audiocpp_server_bin(self.checkout)) + self.assertIsNone(make_server.build.find_audiocpp_server_bin(self.checkout)) class BuiltServerBinaryTests(unittest.TestCase): @@ -889,24 +892,24 @@ class BuiltServerBinaryTests(unittest.TestCase): self._build("linux-cuda-release") self._build("linux-cpu-release") self.assertEqual( - make_server.built_server_binary(self.checkout, "cpu"), + make_server.build.built_server_binary(self.checkout, "cpu"), self.checkout / "build" / "linux-cpu-release" / "bin" / "audiocpp_server") def test_returns_none_for_unbuilt_backend(self): self._build("linux-cuda-release") self.assertIsNone( - make_server.built_server_binary(self.checkout, "vulkan")) + make_server.build.built_server_binary(self.checkout, "vulkan")) def test_metal_counts_as_cpu(self): self._build("macos-metal-release") self.assertEqual( - make_server.built_server_binary(self.checkout, "cpu"), + make_server.build.built_server_binary(self.checkout, "cpu"), self.checkout / "build" / "macos-metal-release" / "bin" / "audiocpp_server") def test_no_build_dir_returns_none(self): - self.assertIsNone(make_server.built_server_binary(self.checkout, "cpu")) + self.assertIsNone(make_server.build.built_server_binary(self.checkout, "cpu")) class BuildAudiocppTests(unittest.TestCase): @@ -921,7 +924,7 @@ class BuildAudiocppTests(unittest.TestCase): (self.scripts / "build_linux.sh").write_text("#!/bin/sh\n", encoding="utf-8") self.log_dir = Path(self._td.name) / "logs" - self.addCleanup(make_server.common.drain_post_tui_notices) + self.addCleanup(common.drain_post_tui_notices) def tearDown(self): self._td.cleanup() @@ -938,9 +941,9 @@ class BuildAudiocppTests(unittest.TestCase): return sorted(self.log_dir.glob("audiocpp_build_*.log")) def test_runs_build_script_with_backend_and_target(self): - with patch.object(make_server.common, "run_console_subprocess", + with patch.object(common, "run_console_subprocess", return_value=0) as run: - rc = make_server.build_audiocpp(self.checkout, "cuda") + rc = make_server.build.build_audiocpp(self.checkout, "cuda") self.assertEqual(rc, 0) argv = run.call_args[0][0] self.assertEqual(argv[:3], ["sh", str(self.scripts / "build_linux.sh"), @@ -954,24 +957,24 @@ class BuildAudiocppTests(unittest.TestCase): def test_missing_script_returns_nonzero(self): for f in self.scripts.iterdir(): f.unlink() - rc = make_server.build_audiocpp(self.checkout, "cuda") + rc = make_server.build.build_audiocpp(self.checkout, "cuda") self.assertNotEqual(rc, 0) def test_console_path_writes_no_log_and_no_notice(self): - with patch.object(make_server.common, "LOG_DIR", self.log_dir), \ - patch.object(make_server.common, "run_console_subprocess", + with patch.object(common, "LOG_DIR", self.log_dir), \ + patch.object(common, "run_console_subprocess", return_value=0): - rc = make_server.build_audiocpp(self.checkout, "cuda") + rc = make_server.build.build_audiocpp(self.checkout, "cuda") self.assertEqual(rc, 0) self.assertEqual(self._log_files(), []) - self.assertEqual(make_server.common.drain_post_tui_notices(), []) + self.assertEqual(common.drain_post_tui_notices(), []) def test_tui_success_writes_log_and_no_notice(self): emitted, emit = self._emit() - with patch.object(make_server.common, "LOG_DIR", self.log_dir), \ - patch.object(make_server.common, "run_console_subprocess", + with patch.object(common, "LOG_DIR", self.log_dir), \ + patch.object(common, "run_console_subprocess", return_value=0): - rc = make_server.build_audiocpp(self.checkout, "cuda", + rc = make_server.build.build_audiocpp(self.checkout, "cuda", emit=emit) self.assertEqual(rc, 0) self.assertEqual(len(self._log_files()), 1) @@ -979,21 +982,21 @@ class BuildAudiocppTests(unittest.TestCase): self.assertIn("[INFO] Building audiocpp_server", log_text) self.assertIn("--backend cuda", log_text) self.assertTrue(emitted) - self.assertEqual(make_server.common.drain_post_tui_notices(), []) + self.assertEqual(common.drain_post_tui_notices(), []) def test_tui_failure_writes_log_and_records_notice(self): emitted, emit = self._emit() - with patch.object(make_server.common, "LOG_DIR", self.log_dir), \ - patch.object(make_server.common, "run_console_subprocess", + with patch.object(common, "LOG_DIR", self.log_dir), \ + patch.object(common, "run_console_subprocess", return_value=3): - rc = make_server.build_audiocpp(self.checkout, "cuda", + rc = make_server.build.build_audiocpp(self.checkout, "cuda", emit=emit) self.assertEqual(rc, 3) logs = self._log_files() self.assertEqual(len(logs), 1) log_text = logs[0].read_text(encoding="utf-8") self.assertIn("failed (exit code 3)", log_text) - notices = make_server.common.drain_post_tui_notices() + notices = common.drain_post_tui_notices() self.assertEqual(len(notices), 1) notice = notices[0] self.assertIn("failed (exit code 3)", notice) @@ -1010,25 +1013,25 @@ class BuildAudiocppTests(unittest.TestCase): emitted, emit = self._emit() cancel = threading.Event() cancel.set() - with patch.object(make_server.common, "LOG_DIR", self.log_dir), \ - patch.object(make_server.common, "run_console_subprocess", + with patch.object(common, "LOG_DIR", self.log_dir), \ + patch.object(common, "run_console_subprocess", return_value=130): - rc = make_server.build_audiocpp(self.checkout, "cuda", + rc = make_server.build.build_audiocpp(self.checkout, "cuda", emit=emit, cancel=cancel) self.assertEqual(rc, 130) self.assertEqual(len(self._log_files()), 1) - self.assertEqual(make_server.common.drain_post_tui_notices(), []) + self.assertEqual(common.drain_post_tui_notices(), []) def test_tui_missing_script_records_guidance_notice(self): for f in self.scripts.iterdir(): f.unlink() emitted, emit = self._emit() - with patch.object(make_server.common, "LOG_DIR", self.log_dir): - rc = make_server.build_audiocpp(self.checkout, "cuda", + with patch.object(common, "LOG_DIR", self.log_dir): + rc = make_server.build.build_audiocpp(self.checkout, "cuda", emit=emit) self.assertNotEqual(rc, 0) self.assertEqual(self._log_files(), []) - notices = make_server.common.drain_post_tui_notices() + notices = common.drain_post_tui_notices() self.assertEqual(len(notices), 1) self.assertIn("No build script found", notices[0]) @@ -1045,18 +1048,18 @@ class AudiocppDetectTests(unittest.TestCase): self._td.cleanup() def test_not_cloned(self): - with patch.object(make_server, "find_local_checkout", return_value=None): - status = make_server.detect() + with patch.object(make_server.build, "find_local_checkout", return_value=None): + status = make_server.status.detect() self.assertFalse(status.installed) self.assertFalse(status.configured) self.assertIn("not cloned", status.details[0]) def test_cloned_not_built_not_configured(self): - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=self.checkout), \ - patch.object(make_server, "find_audiocpp_server_bin", + patch.object(make_server.build, "find_audiocpp_server_bin", return_value=None): - status = make_server.detect() + status = make_server.status.detect() self.assertFalse(status.installed) self.assertFalse(status.configured) self.assertEqual(status.launch_hint, "") @@ -1069,9 +1072,9 @@ class AudiocppDetectTests(unittest.TestCase): binary.write_bytes(b"x") server_json = self.checkout / "server.json" server_json.write_text('{"models":[]}', encoding="utf-8") - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=self.checkout): - status = make_server.detect() + status = make_server.status.detect() self.assertTrue(status.installed) self.assertTrue(status.configured) self.assertIn(str(binary), status.launch_hint) @@ -1083,9 +1086,9 @@ class AudiocppDetectTests(unittest.TestCase): / "audiocpp_server" binary.parent.mkdir(parents=True) binary.write_bytes(b"x") - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=self.checkout): - status = make_server.detect() + status = make_server.status.detect() self.assertTrue(status.installed) self.assertFalse(status.configured) self.assertEqual(status.partial, "built (not configured)") @@ -1104,11 +1107,11 @@ class NonInteractiveMainTests(unittest.TestCase): # Isolate config.py rewrites so no test touches the real one. self.fake_config = self.root / "config.py" self.fake_config.write_text(FAKE_CONFIG, encoding="utf-8") - patcher = patch.object(make_server, "CONFIG_PATH", self.fake_config) + patcher = patch.object(make_server.configsync, "CONFIG_PATH", self.fake_config) patcher.start() self.addCleanup(patcher.stop) # Tests run without a tty -> main() takes the non-interactive path. - patcher = patch.object(make_server, "_interactive", return_value=False) + patcher = patch.object(make_server.wizard, "_interactive", return_value=False) patcher.start() self.addCleanup(patcher.stop) @@ -1121,14 +1124,14 @@ class NonInteractiveMainTests(unittest.TestCase): transcribe_effect = transcribe if transcribe is not None \ else MagicMock() with patch.object(sys, "argv", argv), \ - patch.object(make_server, "find_local_checkout", + patch.object(make_server.build, "find_local_checkout", return_value=None if no_checkout else self.checkout), \ - patch.object(make_server, "transcribe_reference_audio", + patch.object(make_server.voices, "transcribe_reference_audio", side_effect=transcribe_effect), \ - patch.object(make_server, "whisper_backend_available", + patch.object(make_server.voices, "whisper_backend_available", return_value=whisper): - return make_server.main() + return make_server.wizard.main() def _args(self, *extra): return ["--wavs", str(self.folder), "--output", str(self.output)] \ @@ -1140,7 +1143,7 @@ class NonInteractiveMainTests(unittest.TestCase): self.assertEqual(exit_code, 0) data = json.loads(self.output.read_text(encoding="utf-8")) self.assertEqual(data["host"], "127.0.0.1") - self.assertEqual(data["port"], make_server.config_port()) + self.assertEqual(data["port"], make_server.configsync.config_port()) self.assertEqual(data["backend"], "cuda") self.assertTrue(data["lazy_load"]) self.assertEqual([m["id"] for m in data["models"]], @@ -1192,7 +1195,7 @@ class NonInteractiveMainTests(unittest.TestCase): "Higgs-Audio-v3-TTS-4B-GGUF"]) self.assertTrue(data["lazy_load"]) self.assertEqual(data["voice_dir"], str(self.folder.resolve())) - prompt = (self.folder / make_server.PROMPT_TEXT_FILENAME).read_text( + prompt = (self.folder / common.PROMPT_TEXT_FILENAME).read_text( encoding="utf-8") self.assertIn("narrator|a transcript", prompt) @@ -1282,8 +1285,8 @@ class FetchServerEndpointsTests(unittest.TestCase): "data": [{"id": "qwen", "family": "qwen3_tts", "task": "tts"}, {"id": "legacy"}], }).encode("utf-8")]) - with patch.object(make_server.urllib.request, "urlopen", urlopen): - models = make_server.fetch_server_models("http://127.0.0.1:8080") + with patch("urllib.request.urlopen", urlopen): + models = make_server.remote.fetch_server_models("http://127.0.0.1:8080") # Missing fields mirror the converter's client: empty strings. self.assertEqual(models, [ {"id": "qwen", "family": "qwen3_tts", "task": "tts"}, @@ -1294,36 +1297,36 @@ class FetchServerEndpointsTests(unittest.TestCase): def test_fetch_models_trailing_slash_url(self): urlopen, calls = self._urlopen_responding( [b'{"data": [{"id": "m"}]}']) - with patch.object(make_server.urllib.request, "urlopen", urlopen): - make_server.fetch_server_models("http://host:8080/") + with patch("urllib.request.urlopen", urlopen): + make_server.remote.fetch_server_models("http://host:8080/") self.assertEqual(calls, ["http://host:8080/v1/models"]) def test_fetch_models_connection_error_returns_none(self): import urllib.error urlopen, _ = self._urlopen_responding( [], errors=[urllib.error.URLError("Connection refused")]) - with patch.object(make_server.urllib.request, "urlopen", urlopen): + with patch("urllib.request.urlopen", urlopen): self.assertIsNone( - make_server.fetch_server_models("http://127.0.0.1:8080")) + make_server.remote.fetch_server_models("http://127.0.0.1:8080")) def test_fetch_models_non_json_body_returns_none(self): # A port answering TCP but not speaking audiocpp_server JSON. urlopen, _ = self._urlopen_responding([b"<html>not json</html>"]) - with patch.object(make_server.urllib.request, "urlopen", urlopen): + with patch("urllib.request.urlopen", urlopen): self.assertIsNone( - make_server.fetch_server_models("http://127.0.0.1:8080")) + make_server.remote.fetch_server_models("http://127.0.0.1:8080")) def test_fetch_models_unexpected_document_yields_empty_list(self): urlopen, _ = self._urlopen_responding([b'{"foo": 1}']) - with patch.object(make_server.urllib.request, "urlopen", urlopen): + with patch("urllib.request.urlopen", urlopen): self.assertEqual( - make_server.fetch_server_models("http://127.0.0.1:8080"), []) + make_server.remote.fetch_server_models("http://127.0.0.1:8080"), []) def test_fetch_voices_parses_names_and_encodes_model(self): urlopen, calls = self._urlopen_responding( [b'{"voices": ["narrator", "obama"]}']) - with patch.object(make_server.urllib.request, "urlopen", urlopen): - voices = make_server.fetch_server_voices( + with patch("urllib.request.urlopen", urlopen): + voices = make_server.remote.fetch_server_voices( "http://127.0.0.1:8080", "qwen") self.assertEqual(voices, ["narrator", "obama"]) self.assertEqual(calls, @@ -1333,15 +1336,15 @@ class FetchServerEndpointsTests(unittest.TestCase): import urllib.error urlopen, _ = self._urlopen_responding( [], errors=[urllib.error.URLError("boom")]) - with patch.object(make_server.urllib.request, "urlopen", urlopen): + with patch("urllib.request.urlopen", urlopen): self.assertIsNone( - make_server.fetch_server_voices("http://h", "qwen")) + make_server.remote.fetch_server_voices("http://h", "qwen")) def test_fetch_voices_non_list_shape_returns_none(self): urlopen, _ = self._urlopen_responding([b'{"voices": 5}']) - with patch.object(make_server.urllib.request, "urlopen", urlopen): + with patch("urllib.request.urlopen", urlopen): self.assertIsNone( - make_server.fetch_server_voices("http://h", "qwen")) + make_server.remote.fetch_server_voices("http://h", "qwen")) class MissingModelEntriesTests(unittest.TestCase): @@ -1366,29 +1369,29 @@ class MissingModelEntriesTests(unittest.TestCase): {"id": "a", "path": "models/present"}, {"id": "b", "path": "models/absent"}, ]) - missing = make_server.missing_model_entries(path) + missing = make_server.models.missing_model_entries(path) self.assertEqual([m["id"] for m in missing], ["b"]) def test_empty_directory_counts_as_missing(self): (self.dir / "models" / "empty").mkdir(parents=True) path = self._server_json([{"id": "a", "path": "models/empty"}]) - self.assertEqual(len(make_server.missing_model_entries(path)), 1) + self.assertEqual(len(make_server.models.missing_model_entries(path)), 1) def test_absolute_paths_honored(self): target = self.dir / "absolute" target.mkdir() (target / "m.gguf").write_bytes(b"x") path = self._server_json([{"id": "a", "path": str(target)}]) - self.assertEqual(make_server.missing_model_entries(path), []) + self.assertEqual(make_server.models.missing_model_entries(path), []) def test_unreadable_json_returns_empty(self): path = self.dir / "server.json" path.write_text("not json", encoding="utf-8") - self.assertEqual(make_server.missing_model_entries(path), []) + self.assertEqual(make_server.models.missing_model_entries(path), []) def test_no_models_returns_empty(self): path = self._server_json([]) - self.assertEqual(make_server.missing_model_entries(path), []) + self.assertEqual(make_server.models.missing_model_entries(path), []) class ModelInstallHintsTests(unittest.TestCase): @@ -1409,7 +1412,7 @@ class ModelInstallHintsTests(unittest.TestCase): }], }), encoding="utf-8") missing = [{"id": "qwen", "rel": "models/Qwen3-TTS-12Hz-0.6B-Base-GGUF"}] - hints = make_server.model_install_hints(checkout, missing) + hints = make_server.models.model_install_hints(checkout, missing) self.assertEqual(len(hints), 1) self.assertIn("qwen3_tts_0_6b_base_q8_0", hints[0]) @@ -1418,7 +1421,7 @@ class ModelInstallHintsTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: checkout = Path(td) (checkout / "model_specs").mkdir() - hints = make_server.model_install_hints( + hints = make_server.models.model_install_hints( checkout, [{"id": "x", "rel": "models/nope"}]) self.assertIn("models/nope", hints[0]) self.assertNotIn("install", hints[0]) @@ -1443,11 +1446,11 @@ class DetectServerSpecTests(unittest.TestCase): def test_spec_has_cwd_and_identity(self): checkout = self._checkout() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ - patch.object(make_server, "_detect_remote", + patch.object(make_server.status, "_detect_remote", return_value=(False, {})): - status = make_server.detect() + status = make_server.status.detect() self.assertEqual(len(status.servers), 1) spec = status.servers[0] self.assertEqual(spec.cwd, checkout) @@ -1456,11 +1459,11 @@ class DetectServerSpecTests(unittest.TestCase): def test_models_missing_flag_and_details(self): checkout = self._checkout() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ - patch.object(make_server, "_detect_remote", + patch.object(make_server.status, "_detect_remote", return_value=(False, {})): - status = make_server.detect() + status = make_server.status.detect() self.assertTrue(status.models_missing) self.assertTrue(any("not downloaded" in line for line in status.details)) @@ -1488,13 +1491,13 @@ class InstalledModelEntriesTests(unittest.TestCase): {"id": "a", "path": "models/present"}, {"id": "b", "path": "models/absent"}, ]) - installed = make_server.installed_model_entries(path) + installed = make_server.models.installed_model_entries(path) self.assertEqual([m["id"] for m in installed], ["a"]) def test_unreadable_json_returns_empty(self): path = self.dir / "server.json" path.write_text("not json", encoding="utf-8") - self.assertEqual(make_server.installed_model_entries(path), []) + self.assertEqual(make_server.models.installed_model_entries(path), []) class MissingModelInstallGuidanceTests(unittest.TestCase): @@ -1517,7 +1520,7 @@ class MissingModelInstallGuidanceTests(unittest.TestCase): {"id": "qwen", "rel": "models/Qwen3-TTS-12Hz-0.6B-Base-GGUF"}, {"id": "x", "rel": "models/nope"}, ] - guidance = make_server.missing_model_install_guidance( + guidance = make_server.models.missing_model_install_guidance( checkout, missing) self.assertEqual(guidance, [("qwen", "qwen3_tts_0_6b_base_q8_0")]) @@ -1537,22 +1540,22 @@ class LoadServerConfigTests(unittest.TestCase): path = self.dir / "server.json" path.write_text(json.dumps({"host": "0.0.0.0", "models": []}), encoding="utf-8") - self.assertEqual(make_server.load_server_config(path), + self.assertEqual(make_server.catalog.load_server_config(path), {"host": "0.0.0.0", "models": []}) def test_missing_file_returns_none(self): - self.assertIsNone(make_server.load_server_config( + self.assertIsNone(make_server.catalog.load_server_config( self.dir / "nope.json")) def test_unreadable_json_returns_none(self): path = self.dir / "server.json" path.write_text("not json", encoding="utf-8") - self.assertIsNone(make_server.load_server_config(path)) + self.assertIsNone(make_server.catalog.load_server_config(path)) def test_non_dict_document_returns_none(self): path = self.dir / "server.json" path.write_text("[1, 2, 3]", encoding="utf-8") - self.assertIsNone(make_server.load_server_config(path)) + self.assertIsNone(make_server.catalog.load_server_config(path)) class ServerConfigSelectionsTests(unittest.TestCase): @@ -1561,7 +1564,7 @@ class ServerConfigSelectionsTests(unittest.TestCase): def setUp(self): self._tmp = tempfile.TemporaryDirectory() self.checkout = _make_checkout(Path(self._tmp.name)) - self.catalog = make_server.load_model_catalog(self.checkout) + self.catalog = make_server.catalog.load_model_catalog(self.checkout) def tearDown(self): self._tmp.cleanup() @@ -1576,7 +1579,7 @@ class ServerConfigSelectionsTests(unittest.TestCase): {"id": "higgs", "family": "higgs_audio_tts", "path": "models/Higgs-Audio-v3-TTS-4B-GGUF", "task": "tts"}, ]} - selected, tasks = make_server.server_config_selections(config, + selected, tasks = make_server.catalog.server_config_selections(config, self.catalog) self.assertEqual(selected["qwen3_tts"], ["Qwen3-TTS-12Hz-1.7B-Base-GGUF", @@ -1593,7 +1596,7 @@ class ServerConfigSelectionsTests(unittest.TestCase): config = {"models": [ {"id": "x", "family": "not_a_family", "path": "models/x"}, ]} - selected, tasks = make_server.server_config_selections(config, + selected, tasks = make_server.catalog.server_config_selections(config, self.catalog) self.assertEqual(selected, {}) self.assertEqual(tasks, {}) @@ -1603,13 +1606,13 @@ class ServerConfigSelectionsTests(unittest.TestCase): {"id": "qwen", "family": "qwen3_tts", "path": "/abs/Qwen3-TTS-12Hz-1.7B-Base-GGUF", "task": "tts"}, ]} - selected, tasks = make_server.server_config_selections(config, + selected, tasks = make_server.catalog.server_config_selections(config, self.catalog) self.assertEqual(selected["qwen3_tts"], ["/abs/Qwen3-TTS-12Hz-1.7B-Base-GGUF"]) def test_empty_models_yield_empty_selections(self): - selected, tasks = make_server.server_config_selections({"models": []}, + selected, tasks = make_server.catalog.server_config_selections({"models": []}, self.catalog) self.assertEqual(selected, {}) self.assertEqual(tasks, {}) @@ -1641,7 +1644,7 @@ class UnusedInstalledEntriesTests(unittest.TestCase): {"id": "dropped", "path": "models/dropped"}, {"id": "missing", "path": "models/missing"}, ]) - unused = make_server.unused_installed_entries( + unused = make_server.models.unused_installed_entries( path, {"models/kept"}) self.assertEqual([entry["id"] for entry in unused], ["dropped"]) @@ -1649,7 +1652,7 @@ class UnusedInstalledEntriesTests(unittest.TestCase): path = self._server_json([ {"id": "kept", "path": "models/kept"}, ]) - unused = make_server.unused_installed_entries( + unused = make_server.models.unused_installed_entries( path, {"models/kept"}) self.assertEqual(unused, []) @@ -1678,7 +1681,7 @@ class DeleteModelFilesTests(unittest.TestCase): self._tmp.cleanup() def test_removes_dirs_and_counts(self): - removed = make_server.delete_model_files( + removed = make_server.models.delete_model_files( self.server_json, [{"id": "a", "rel": "models/a"}, {"id": "b", "rel": "models/b"}]) self.assertEqual(removed, 2) @@ -1687,14 +1690,14 @@ class DeleteModelFilesTests(unittest.TestCase): self.assertTrue((self.dir / "models" / "c").exists()) def test_missing_paths_ignored(self): - removed = make_server.delete_model_files( + removed = make_server.models.delete_model_files( self.server_json, [{"id": "ghost", "rel": "models/ghost"}]) self.assertEqual(removed, 0) def test_removes_single_file(self): file_path = self.dir / "models" / "single.gguf" file_path.write_bytes(b"x") - removed = make_server.delete_model_files( + removed = make_server.models.delete_model_files( self.server_json, [{"id": "s", "rel": "models/single.gguf"}]) self.assertEqual(removed, 1) self.assertFalse(file_path.exists()) @@ -1703,7 +1706,7 @@ class DeleteModelFilesTests(unittest.TestCase): target = self.dir / "absolute" target.mkdir() (target / "m.gguf").write_bytes(b"x") - removed = make_server.delete_model_files( + removed = make_server.models.delete_model_files( self.server_json, [{"id": "a", "rel": str(target)}]) self.assertEqual(removed, 1) self.assertFalse(target.exists()) @@ -1716,8 +1719,8 @@ class InstallModelsApiTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: checkout = Path(td) guidance = [("qwen", "qwen3_tts_0_6b_base_q8_0")] - with patch.object(make_server, "_install_models") as mk: - make_server.install_models(checkout, guidance) + with patch.object(make_server.models, "_install_models") as mk: + make_server.models.install_models(checkout, guidance) mk.assert_called_once_with(checkout, guidance, download=True, emit=None, cancel=None) @@ -1728,7 +1731,7 @@ class HandInstallGuidanceTests(unittest.TestCase): def test_lists_each_model_and_its_path(self): with tempfile.TemporaryDirectory() as td: checkout = Path(td) - message = make_server.hand_install_guidance(checkout, [ + message = make_server.models.hand_install_guidance(checkout, [ {"id": "qwen", "rel": "models/Qwen3-TTS-12Hz-0.6B-Base-GGUF"}, {"id": "higgs", "rel": "models/Higgs-Audio-4B-GGUF"}, ]) @@ -1743,7 +1746,7 @@ class WizardNavigationTests(unittest.TestCase): """Esc in the audio.cpp wizard goes back one screen (via tui.Wizard).""" def _args(self): - return make_server.build_parser().parse_args([]) + return make_server.wizard.build_parser().parse_args([]) def _checkout(self): tmp = tempfile.TemporaryDirectory() @@ -1754,12 +1757,12 @@ class WizardNavigationTests(unittest.TestCase): # Configure audio.cpp (modify flow): the families tree is the first # screen, so Esc on it must abort the wizard — not re-show itself. checkout = self._checkout() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ patch.object(tui, "checkbox_tree", - return_value=make_server._GO_BACK): - settings = make_server._wizard(None, self._args(), - make_server.build_parser()) + return_value=make_server.wizard._GO_BACK): + settings = make_server.wizard._wizard(None, self._args(), + make_server.wizard.build_parser()) self.assertIsNone(settings) def test_modify_flow_offers_build_when_not_built(self): @@ -1771,7 +1774,7 @@ class WizardNavigationTests(unittest.TestCase): (checkout / "server.json").write_text( json.dumps({"models": [], "backend": "vulkan"}), encoding="utf-8") - catalog = make_server.load_model_catalog(checkout) + catalog = make_server.catalog.load_model_catalog(checkout) supertonic = next(i for i, entry in enumerate(catalog) if entry["family"] == "supertonic") confirm_questions = [] @@ -1793,14 +1796,14 @@ class WizardNavigationTests(unittest.TestCase): confirm_questions.append(question) return False # decline the build - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ patch.object(tui, "checkbox_tree", side_effect=fake_tree), \ patch.object(tui, "line_edit", side_effect=fake_line_edit), \ patch.object(tui, "menu", side_effect=fake_menu), \ patch.object(tui, "confirm", side_effect=fake_confirm): - settings = make_server._wizard(None, self._args(), - make_server.build_parser()) + settings = make_server.wizard._wizard(None, self._args(), + make_server.wizard.build_parser()) self.assertIsNotNone(settings) self.assertEqual(settings["backend"], "vulkan") self.assertFalse(settings["build"]) @@ -1813,11 +1816,11 @@ class WizardNavigationTests(unittest.TestCase): # Esc on "Bind host" must fall back to the model-family tree, then # re-selecting proceeds through the rest of the wizard. checkout = self._checkout() - catalog = make_server.load_model_catalog(checkout) + catalog = make_server.catalog.load_model_catalog(checkout) supertonic = next(i for i, entry in enumerate(catalog) if entry["family"] == "supertonic") tree_calls = [] - hosts = iter([make_server._GO_BACK, "127.0.0.1"]) + hosts = iter([make_server.wizard._GO_BACK, "127.0.0.1"]) def fake_tree(*args, **kwargs): tree_calls.append(1) @@ -1830,7 +1833,7 @@ class WizardNavigationTests(unittest.TestCase): return "8080" return default - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ patch.object(tui, "checkbox_tree", side_effect=fake_tree), \ @@ -1838,8 +1841,8 @@ class WizardNavigationTests(unittest.TestCase): side_effect=fake_line_edit), \ patch.object(tui, "menu", return_value="cuda"), \ patch.object(tui, "confirm", return_value=True): - settings = make_server._wizard(None, self._args(), - make_server.build_parser()) + settings = make_server.wizard._wizard(None, self._args(), + make_server.wizard.build_parser()) self.assertIsNotNone(settings) # The tree was re-shown after the host screen's Esc. self.assertEqual(len(tree_calls), 2) @@ -1855,12 +1858,12 @@ class UninstallTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: checkout = Path(td) / "audio.cpp" checkout.mkdir() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ - patch.object(make_server.servers, "pid_for", + patch.object(servers, "pid_for", return_value=1234), \ - patch.object(make_server.servers, "stop") as mk_stop: - rc = make_server.uninstall() + patch.object(servers, "stop") as mk_stop: + rc = make_server.build.uninstall() self.assertEqual(rc, 0) self.assertFalse(checkout.exists()) mk_stop.assert_called_once_with("audiocpp") @@ -1868,12 +1871,12 @@ class UninstallTests(unittest.TestCase): def test_skips_stop_without_a_pid_file(self): # No pid file: the server was never started by this tool, so # stop (and its "stop it manually" noise) is skipped. - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=None), \ - patch.object(make_server.servers, "pid_for", + patch.object(servers, "pid_for", return_value=None), \ - patch.object(make_server.servers, "stop") as mk_stop: - rc = make_server.uninstall() + patch.object(servers, "stop") as mk_stop: + rc = make_server.build.uninstall() self.assertEqual(rc, 0) mk_stop.assert_not_called() @@ -1883,12 +1886,12 @@ class UninstallTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: checkout = Path(td) / "audio.cpp" checkout.mkdir() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ - patch.object(make_server.servers, "pid_for", + patch.object(servers, "pid_for", return_value=1234), \ - patch.object(make_server.servers, "stop"): - rc = make_server.uninstall(emit=lambda line: None, + patch.object(servers, "stop"): + rc = make_server.build.uninstall(emit=lambda line: None, cancel=None) self.assertEqual(rc, 0) self.assertFalse(checkout.exists()) @@ -1901,12 +1904,12 @@ class UninstallTests(unittest.TestCase): checkout.mkdir() cancel = threading.Event() cancel.set() - with patch.object(make_server, "find_local_checkout", + with patch.object(make_server.build, "find_local_checkout", return_value=checkout), \ - patch.object(make_server.servers, "pid_for", + patch.object(servers, "pid_for", return_value=1234), \ - patch.object(make_server.servers, "stop"): - rc = make_server.uninstall(cancel=cancel) + patch.object(servers, "stop"): + rc = make_server.build.uninstall(cancel=cancel) self.assertEqual(rc, 130) self.assertTrue(checkout.exists()) @@ -1920,23 +1923,23 @@ class SetupScreenTests(unittest.TestCase): in-TUI task view (two parallel lanes on a fresh install).""" def test_abort_returns_one_without_executing(self): - with patch.object(make_server, "_wizard", return_value=None) as mk_wizard, \ - patch.object(make_server, "_execute_lanes") as mk_lanes: - rc = make_server.setup_screen(None) + with patch.object(make_server.wizard, "_wizard", return_value=None) as mk_wizard, \ + patch.object(make_server.wizard, "_execute_lanes") as mk_lanes: + rc = make_server.wizard.setup_screen(None) self.assertEqual(rc, 1) mk_wizard.assert_called_once() mk_lanes.assert_not_called() def test_success_runs_the_tail_in_the_task_view(self): settings = {"audiocpp_dir": Path("/x")} - lanes = [make_server.taskview.TaskLane( - "Build", [make_server.taskview.TaskStep("t", lambda emit, cancel: 0)])] - with patch.object(make_server, "_wizard", return_value=settings), \ - patch.object(make_server, "_execute_lanes", + lanes = [taskview.TaskLane( + "Build", [taskview.TaskStep("t", lambda emit, cancel: 0)])] + with patch.object(make_server.wizard, "_wizard", return_value=settings), \ + patch.object(make_server.wizard, "_execute_lanes", return_value=lanes) as mk_lanes, \ - patch.object(make_server.taskview, "run_lanes", + patch.object(taskview, "run_lanes", return_value=0) as mk_run: - rc = make_server.setup_screen(None) + rc = make_server.wizard.setup_screen(None) self.assertEqual(rc, 0) mk_lanes.assert_called_once() self.assertIs(mk_lanes.call_args[0][0], settings) @@ -1973,8 +1976,8 @@ class ExecuteLanesTests(unittest.TestCase): return settings def test_two_lanes_when_building(self): - args = make_server.build_parser().parse_args([]) - lanes = make_server._execute_lanes(self._settings(), args) + args = make_server.wizard.build_parser().parse_args([]) + lanes = make_server.wizard._execute_lanes(self._settings(), args) self.assertEqual([lane.title for lane in lanes], ["Build", "Configure & download"]) self.assertEqual([s.title for s in lanes[0].steps], @@ -1985,15 +1988,15 @@ class ExecuteLanesTests(unittest.TestCase): "Download models"]) def test_single_lane_when_not_building(self): - args = make_server.build_parser().parse_args([]) - lanes = make_server._execute_lanes( + args = make_server.wizard.build_parser().parse_args([]) + lanes = make_server.wizard._execute_lanes( self._settings(build=False), args) self.assertEqual([lane.title for lane in lanes], ["Configure & download"]) def test_flattened_console_steps_keep_the_build_first(self): - args = make_server.build_parser().parse_args([]) - steps = make_server._execute_steps(self._settings(), args) + args = make_server.wizard.build_parser().parse_args([]) + steps = make_server.wizard._execute_steps(self._settings(), args) self.assertEqual([s.title for s in steps], ["Build audiocpp_server (cuda)", "Transcribe reference voices", @@ -2001,11 +2004,11 @@ class ExecuteLanesTests(unittest.TestCase): "Download models"]) def test_download_step_prints_the_launch_hint(self): - args = make_server.build_parser().parse_args([]) - lanes = make_server._execute_lanes(self._settings(), args) + args = make_server.wizard.build_parser().parse_args([]) + lanes = make_server.wizard._execute_lanes(self._settings(), args) install_step = lanes[1].steps[2] - with patch.object(make_server, "_install_models"), \ - patch.object(make_server, "_print_launch_hint") as mk_hint: + with patch.object(make_server.models, "_install_models"), \ + patch.object(make_server.build, "_print_launch_hint") as mk_hint: install_step.work(lambda line: None, threading.Event()) mk_hint.assert_called_once_with(Path("/x"), Path("/x/server.json")) @@ -2016,9 +2019,9 @@ class LaunchHintTests(unittest.TestCase): def _capture(self, audiocpp_dir, output_path, binary=None): buf = io.StringIO() with redirect_stdout(buf), \ - patch.object(make_server, "find_audiocpp_server_bin", + patch.object(make_server.build, "find_audiocpp_server_bin", return_value=binary): - make_server._print_launch_hint(audiocpp_dir, output_path) + make_server.build._print_launch_hint(audiocpp_dir, output_path) return buf.getvalue() def test_built_server_prints_nothing(self): diff --git a/app/tests/test_backends_faster.py b/app/tests/test_backends_faster.py index 55d617c..800acb0 100644 --- a/app/tests/test_backends_faster.py +++ b/app/tests/test_backends_faster.py @@ -173,7 +173,8 @@ class MainTests(unittest.TestCase): return_value=False) patcher.start() self.addCleanup(patcher.stop) - patcher = patch.object(make_voices, "_interactive", return_value=False) + patcher = patch.object(make_voices.setup, "interactive", + return_value=False) patcher.start() self.addCleanup(patcher.stop) diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py index 9f72ad9..d8a21bc 100644 --- a/app/tests/test_hub.py +++ b/app/tests/test_hub.py @@ -1972,7 +1972,7 @@ class AudiocppServerConfigTests(unittest.TestCase): import json with tempfile.TemporaryDirectory() as td: mod, checkout, server_json = self._make_checkout(td, port=8080) - with patch.object(mod, "find_local_checkout", + with patch.object(mod.build, "find_local_checkout", return_value=checkout): self.assertTrue(mod.update_server_config_port(9090)) data = json.loads(server_json.read_text(encoding="utf-8")) @@ -1986,16 +1986,17 @@ class AudiocppServerConfigTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: mod, checkout, server_json = self._make_checkout(td, port=8080) before = server_json.read_text(encoding="utf-8") - with patch.object(mod, "find_local_checkout", + with patch.object(mod.build, "find_local_checkout", return_value=checkout): self.assertTrue(mod.update_server_config_port(8080)) self.assertEqual(server_json.read_text(encoding="utf-8"), before) def test_false_when_no_checkout(self): from backends import audiocpp as audiocpp_backend - with patch.object(audiocpp_backend, "find_local_checkout", + with patch.object(audiocpp_backend.build, "find_local_checkout", return_value=None): - self.assertFalse(audiocpp_backend.update_server_config_port(9090)) + self.assertFalse( + audiocpp_backend.update_server_config_port(9090)) class ConfigureBackendsDispatchTests(unittest.TestCase): |
