from __future__ import annotations import base64 import importlib.util import json import os import tempfile import unittest from pathlib import Path from unittest.mock import patch ROOT = Path(__file__).resolve().parents[1] class NekoConfigTests(unittest.TestCase): def test_browser_launch_cleanup_script_still_prunes_profile_bloat(self) -> None: script_path = ROOT / "services" / "neko" / "browser-launch.sh" self.assertTrue(os.access(script_path, os.X_OK)) script = script_path.read_text(encoding="utf-8") self.assertIn("arch=\"$(uname -m", script) self.assertIn("--disable-software-rasterizer", script) self.assertIn("--use-gl=swiftshader", script) self.assertIn("NEKO_BROWSER_RENDER_MODE", script) self.assertIn("--start-maximized", script) self.assertIn("--disable-background-mode", script) self.assertNotIn("--disable-background-networking", script) self.assertNotIn("--disable-extensions", script) self.assertIn('ui["developer_mode"] = True', script) self.assertIn('"Local State"', script) self.assertIn('browser_class="google-chrome"', script) self.assertIn('xdotool search --onlyvisible --class "$browser_class"', script) self.assertIn('prune_path "$profile_dir/BrowserMetrics"', script) self.assertIn('prune_path "$profile_dir/Crash Reports"', script) self.assertIn('prune_path "$profile_dir/SingletonLock"', script) self.assertIn('prune_path "$profile_dir/Default/Code Cache"', script) def test_browser_policies_default_to_allowed_permissions(self) -> None: policies = json.loads((ROOT / "services" / "neko" / "policies" / "policies.json").read_text(encoding="utf-8")) self.assertEqual(policies["DefaultNotificationsSetting"], 1) self.assertEqual(policies["DefaultGeolocationSetting"], 1) self.assertTrue(policies["VideoCaptureAllowed"]) self.assertTrue(policies["AudioCaptureAllowed"]) self.assertEqual(policies["DeveloperToolsAvailability"], 1) self.assertNotIn("ExtensionInstallAllowlist", policies) tm_policy = policies["3rdparty"]["extensions"]["dhdgffkkebhmkfjojejmpbldmpobfkfo"]["jsonImport"][0] self.assertEqual(tm_policy["url"], "http://127.0.0.1:18080/tampermonkey-provisioning.json") self.assertTrue(tm_policy["hash"].startswith("1:")) self.assertFalse(tm_policy["installAsSystemScripts"]) def test_google_chrome_supervisor_uses_direct_stable_command(self) -> None: conf = (ROOT / "services" / "neko" / "google-chrome.conf").read_text(encoding="utf-8") self.assertIn("command=/etc/neko/browser-launch.sh google-chrome", conf) self.assertNotIn("--bwsi", conf) self.assertIn("autorestart=true", conf) self.assertIn("[program:tampermonkey-provisioning]", conf) self.assertIn("127.0.0.1:18080", conf) self.assertIn("[program:openbox]", conf) self.assertIn("/usr/bin/openbox --config-file /etc/neko/openbox.xml", conf) script = (ROOT / "services" / "neko" / "browser-launch.sh").read_text(encoding="utf-8") self.assertIn('profile_dir="/home/neko/.config/google-chrome"', script) self.assertIn('--user-data-dir="$profile_dir"', script) def test_chromium_supervisor_uses_direct_stable_command(self) -> None: conf = (ROOT / "services" / "neko" / "chromium.conf").read_text(encoding="utf-8") self.assertIn("command=/etc/neko/browser-launch.sh chromium", conf) self.assertNotIn("--bwsi", conf) self.assertIn("autorestart=true", conf) self.assertIn("[program:tampermonkey-provisioning]", conf) self.assertIn("127.0.0.1:18080", conf) self.assertIn("[program:openbox]", conf) script = (ROOT / "services" / "neko" / "browser-launch.sh").read_text(encoding="utf-8") self.assertIn('profile_dir="/home/neko/.config/chromium"', script) self.assertIn('--user-data-dir="$profile_dir"', script) def test_legacy_neko_compose_template_mounts_only_selected_supervisor_conf(self) -> None: compose = (ROOT / "services" / "neko" / "docker-compose.yml").read_text(encoding="utf-8") self.assertIn("./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro", compose) self.assertIn("./browser-launch.sh:/etc/neko/browser-launch.sh:ro", compose) self.assertIn("./provisioning:/var/www/provisioning:ro", compose) self.assertIn("container_name: live-neko-1", compose) self.assertIn("container_name: live-neko-2", compose) self.assertIn("container_name: live-neko-3", compose) self.assertIn("${NEKO_HTTP_PORT_1}:8080", compose) self.assertIn("${NEKO_HTTP_PORT_2}:8080", compose) self.assertIn("${NEKO_HTTP_PORT_3}:8080", compose) self.assertNotIn("/etc/neko/supervisord/browser.conf:ro", compose) def test_dynamic_neko_compose_renderer_supports_more_than_three_instances(self) -> None: spec = importlib.util.spec_from_file_location( "render_neko_compose", ROOT / "tools" / "render_neko_compose.py", ) self.assertIsNotNone(spec) module = importlib.util.module_from_spec(spec) assert spec and spec.loader spec.loader.exec_module(module) with tempfile.TemporaryDirectory() as tmp: with patch.dict( os.environ, { "NEKO_IMAGE": "test-image", "NEKO_PROFILE_HOST_DIR": f"{tmp}/profile", "NEKO_BROWSER_SUPERVISOR_CONF": "google-chrome.conf", }, clear=False, ): rendered = module.render(4) self.assertIn("container_name: live-neko-4", rendered) self.assertIn('"9203:8080"', rendered) self.assertIn('"52303:52303/tcp"', rendered) self.assertIn('"52400-52499:52400-52499/udp"', rendered) self.assertIn(f'"{tmp}/profile-4:/home/neko/.config/google-chrome"', rendered) def test_neko_runtime_scripts_use_generated_compose(self) -> None: service_ctl = (ROOT / "scripts" / "linux" / "service_ctl.sh").read_text(encoding="utf-8") common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8") for script in (service_ctl, common): self.assertIn("render_neko_compose_file()", script) self.assertIn("tools/render_neko_compose.py", script) self.assertIn("docker-compose.generated.yml", script) self.assertIn("compose_file=\"$(render_neko_compose_file)\"", script) self.assertIn("NEKO_MAX_INSTANCE_COUNT:-64", script) def test_supervisor_uses_browser_launch_script(self) -> None: chrome = (ROOT / "services" / "neko" / "google-chrome.conf").read_text(encoding="utf-8") chromium = (ROOT / "services" / "neko" / "chromium.conf").read_text(encoding="utf-8") self.assertIn("command=/etc/neko/browser-launch.sh google-chrome", chrome) self.assertIn("command=/etc/neko/browser-launch.sh chromium", chromium) self.assertNotIn("--start-maximized", chrome) self.assertNotIn("--start-maximized", chromium) def test_tampermonkey_provisioning_matches_policy_hash(self) -> None: provisioning_path = ROOT / "services" / "neko" / "provisioning" / "tampermonkey-provisioning.json" userscript_path = ROOT / "services" / "neko" / "provisioning" / "youtube-studio-auto-dismiss.user.js" payload = json.loads(provisioning_path.read_text(encoding="utf-8")) self.assertEqual(payload["version"], "1") self.assertEqual(payload["settings"]["runtime_content_mode"], "content") self.assertEqual(payload["scripts"][0]["file_url"], "https://greasyfork.org/scripts/557378-youtube-studio-auto-dismiss/code/YouTube%20Studio%20Auto%20Dismiss.user.js") self.assertEqual(payload["scripts"][0]["options"], {}) decoded_source = base64.b64decode(payload["scripts"][0]["source"]).decode("utf-8") self.assertEqual(decoded_source, userscript_path.read_text(encoding="utf-8")) spec = importlib.util.spec_from_file_location( "render_tampermonkey_provisioning", ROOT / "tools" / "render_tampermonkey_provisioning.py", ) self.assertIsNotNone(spec) module = importlib.util.module_from_spec(spec) assert spec and spec.loader spec.loader.exec_module(module) policies = json.loads((ROOT / "services" / "neko" / "policies" / "policies.json").read_text(encoding="utf-8")) tm_import = policies["3rdparty"]["extensions"]["dhdgffkkebhmkfjojejmpbldmpobfkfo"]["jsonImport"][0] self.assertFalse(tm_import["installAsSystemScripts"]) expected_hash = tm_import["hash"] self.assertEqual(expected_hash, f"1:{module.tm_hash(payload)}") def test_neko_scripts_use_family_specific_profile_dirs(self) -> None: service_ctl = (ROOT / "scripts" / "linux" / "service_ctl.sh").read_text(encoding="utf-8") common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8") self.assertIn("resolve_neko_profile_dir()", service_ctl) self.assertIn('${family}-profile-v2', service_ctl) self.assertIn("resolve_neko_profile_dir()", common) self.assertIn('${family}-profile-v2', common) self.assertIn("resolve_neko_profile_dir_for_instance()", service_ctl) self.assertIn("seed_neko_tampermonkey_profile()", service_ctl) self.assertIn("Local Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo", service_ctl) self.assertIn("NEKO_HTTP_PORT_2", service_ctl) self.assertIn("NEKO_WEBRTC_UDP_RANGE_3", service_ctl) self.assertIn("resolve_neko_profile_dir_for_instance()", common) self.assertIn("seed_neko_tampermonkey_profile()", common) self.assertIn("Local Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo", common) self.assertIn("NEKO_HTTP_PORT_2", common) self.assertIn("NEKO_WEBRTC_UDP_RANGE_3", common) def test_neko_ip_watcher_is_installed_and_restarts_on_drift(self) -> None: common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8") watcher = (ROOT / "scripts" / "linux" / "neko_ip_watch.sh").read_text(encoding="utf-8") upgrade = (ROOT / "scripts" / "linux" / "upgrade_live_console.sh").read_text(encoding="utf-8") uninstall = (ROOT / "scripts" / "linux" / "uninstall_stack.sh").read_text(encoding="utf-8") stack_env = (ROOT / "config" / "system-stack.env.example").read_text(encoding="utf-8") self.assertIn("install_neko_ip_watch_service()", common) self.assertIn("live-neko-ip-watch.service", common) self.assertIn("ExecStart=/bin/bash", common) self.assertIn("scripts/linux/neko_ip_watch.sh", common) self.assertIn("detect_preferred_lan_ip", watcher) self.assertIn('bash "$SERVICE_CTL" neko restart', watcher) self.assertIn("NEKO_IP_WATCH_INTERVAL", watcher) self.assertIn("install_neko_ip_watch_service", upgrade) self.assertIn("live-neko-ip-watch.service", uninstall) self.assertIn("NEKO_IP_WATCH_INTERVAL=15", stack_env) def test_local_browser_prefers_chrome_on_x86_and_chromium_elsewhere(self) -> None: script = (ROOT / "scripts" / "linux" / "launch_browser.sh").read_text(encoding="utf-8") self.assertIn("x86_64|amd64", script) x86_branch = script.split("x86_64|amd64)", 1)[1].split(";;", 1)[0] other_branch = script.split("*)", 1)[1].split(";;", 1)[0] self.assertLess(x86_branch.find("google-chrome"), x86_branch.find("chromium")) self.assertLess(other_branch.find("chromium"), other_branch.find("google-chrome")) if __name__ == "__main__": unittest.main()