import json import os import socket import sys import threading import unittest from http.server import BaseHTTPRequestHandler, HTTPServer from types import SimpleNamespace from unittest import mock sys.path.insert(0, os.path.dirname(__file__)) from _helpers import TempDirMixin from app import chrome from app import config as account_config class JsonVersionHandler(BaseHTTPRequestHandler): def do_GET(self): if self.path != "/json/version": self.send_response(404) self.end_headers() return body = json.dumps({"Browser": "Chrome/Test"}).encode("utf-8") self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, format, *args): return class ChromeTests(TempDirMixin, unittest.TestCase): def start_json_version_server(self): server = HTTPServer(("127.0.0.1", 0), JsonVersionHandler) thread = threading.Thread(target=server.serve_forever) thread.daemon = True thread.start() self.addCleanup(server.server_close) self.addCleanup(server.shutdown) self.addCleanup(thread.join, 2) return server.server_address[1] def unused_port(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("127.0.0.1", 0)) port = sock.getsockname()[1] sock.close() return port def test_build_launch_args_includes_required_flags(self): with self.make_temp_dir() as temp_dir: cfg = { "chrome_path": r"C:\Program Files\Google\Chrome\Application\chrome.exe", "user_data_root": temp_dir, } account = {"alias": "alias", "debug_port": "9222"} args = chrome.build_launch_args(account, config=cfg) slug = account_config.make_slug("alias") user_data_dir = os.path.abspath(os.path.join(temp_dir, slug)) self.assertEqual(cfg["chrome_path"], args[0]) self.assertIn("--remote-debugging-port=9222", args) self.assertIn("--remote-allow-origins=*", args) self.assertIn(f"--user-data-dir={user_data_dir}", args) self.assertTrue(os.path.isdir(user_data_dir)) self.assert_removed(temp_dir) def test_build_launch_args_accepts_account_object_user_data_dir(self): with self.make_temp_dir() as temp_dir: user_data_dir = os.path.join(temp_dir, "custom") account = SimpleNamespace(debug_port=9333, user_data_dir=user_data_dir) args = chrome.build_launch_args( account, config={"chrome_path": "chrome.exe"}, ) self.assertIn("--remote-debugging-port=9333", args) self.assertIn(f"--user-data-dir={os.path.abspath(user_data_dir)}", args) self.assertTrue(os.path.isdir(user_data_dir)) self.assert_removed(temp_dir) def test_build_launch_args_rejects_invalid_account(self): with self.assertRaises(chrome.ChromeLaunchError): chrome.build_launch_args( {"alias": "alias", "debug_port": 0}, config={"chrome_path": "chrome.exe"}, ) def test_launch_chrome_uses_subprocess_popen(self): with self.make_temp_dir() as temp_dir: account = {"alias": "alias", "debug_port": 9222} cfg = {"chrome_path": "chrome.exe", "user_data_root": temp_dir} process = object() with mock.patch("app.chrome.subprocess.Popen", return_value=process) as popen: result = chrome.launch_chrome(account, config=cfg) self.assertIs(process, result) popen.assert_called_once() args = popen.call_args[0][0] self.assertEqual("chrome.exe", args[0]) self.assertIn("--remote-debugging-port=9222", args) self.assertIn("--remote-allow-origins=*", args) self.assert_removed(temp_dir) def test_create_shortcut_writes_lnk_with_required_chrome_arguments(self): with self.make_temp_dir() as temp_dir: chrome_path = os.path.join(temp_dir, "Chrome App", "chrome.exe") shortcut_path = os.path.join(temp_dir, "Desktop", "主店.lnk") account = { "alias": "alias", "debug_port": 9222, "user_data_dir": os.path.join(temp_dir, "profile with space"), } cfg = {"chrome_path": chrome_path} with mock.patch("app.chrome.subprocess.run") as run: result = chrome.create_shortcut( account, shortcut_path=shortcut_path, config=cfg, ) self.assertEqual(os.path.abspath(shortcut_path), result) run.assert_called_once() command = run.call_args[0][0] self.assertEqual("powershell", command[0]) script = command[-1] self.assertIn("$shortcut.TargetPath", script) self.assertIn(chrome_path, script) self.assertIn("--remote-debugging-port=9222", script) self.assertIn("--remote-allow-origins=*", script) self.assertIn("--user-data-dir=", script) self.assertIn("profile with space", script) self.assert_removed(temp_dir) def test_is_running_and_wait_debug_ready(self): port = self.start_json_version_server() self.assertTrue(chrome.is_running(port)) self.assertTrue(chrome.wait_debug_ready(port, timeout=1)) self.assertFalse(chrome.is_running(self.unused_port())) if __name__ == "__main__": unittest.main()