T-585 Chrome 路径自动检测
This commit is contained in:
+170
-1
@@ -12,7 +12,7 @@ sys.path.insert(0, os.path.dirname(__file__))
|
||||
|
||||
from _helpers import TempDirMixin
|
||||
|
||||
from app import chrome
|
||||
from app import appconfig, chrome
|
||||
from app import config as account_config
|
||||
|
||||
|
||||
@@ -51,6 +51,175 @@ class ChromeTests(TempDirMixin, unittest.TestCase):
|
||||
sock.close()
|
||||
return port
|
||||
|
||||
def make_executable(self, root, *parts):
|
||||
path = os.path.join(root, *parts)
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as fh:
|
||||
fh.write("chrome")
|
||||
return path
|
||||
|
||||
def test_registry_candidates_prioritize_current_user_and_all_views(self):
|
||||
class FakeKey:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
class FakeWinreg:
|
||||
HKEY_CURRENT_USER = "HKCU"
|
||||
HKEY_LOCAL_MACHINE = "HKLM"
|
||||
KEY_READ = 1
|
||||
KEY_WOW64_64KEY = 16
|
||||
KEY_WOW64_32KEY = 32
|
||||
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
self.values = {
|
||||
(self.HKEY_CURRENT_USER, self.KEY_READ | self.KEY_WOW64_32KEY): "user-chrome.exe",
|
||||
(self.HKEY_LOCAL_MACHINE, self.KEY_READ): "machine-chrome.exe",
|
||||
}
|
||||
|
||||
def OpenKey(self, hive, sub_key, _reserved, access):
|
||||
self.calls.append((hive, sub_key, access))
|
||||
try:
|
||||
return FakeKey(self.values[(hive, access)])
|
||||
except KeyError as exc:
|
||||
raise FileNotFoundError() from exc
|
||||
|
||||
@staticmethod
|
||||
def QueryValueEx(key, name):
|
||||
self.assertEqual("", name)
|
||||
return key.value, 1
|
||||
|
||||
fake = FakeWinreg()
|
||||
with mock.patch("app.chrome._load_winreg", return_value=fake):
|
||||
candidates = list(chrome._registry_chrome_candidates())
|
||||
|
||||
self.assertEqual(["user-chrome.exe", "machine-chrome.exe"], candidates)
|
||||
self.assertEqual("HKCU", fake.calls[0][0])
|
||||
self.assertEqual(chrome.CHROME_APP_PATHS_KEY, fake.calls[0][1])
|
||||
self.assertIn(("HKCU", chrome.CHROME_APP_PATHS_KEY, 1 | 16), fake.calls)
|
||||
self.assertIn(("HKCU", chrome.CHROME_APP_PATHS_KEY, 1 | 32), fake.calls)
|
||||
self.assertIn(("HKLM", chrome.CHROME_APP_PATHS_KEY, 1), fake.calls)
|
||||
|
||||
def test_detect_chrome_path_normalizes_registry_value(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
executable = self.make_executable(temp_dir, "Chrome", "chrome.exe")
|
||||
environment_name = "CMSHOPEE_TEST_CHROME"
|
||||
registry_value = f'"%{environment_name}%"'
|
||||
|
||||
with mock.patch.dict(os.environ, {environment_name: executable}, clear=False), \
|
||||
mock.patch(
|
||||
"app.chrome._registry_chrome_candidates",
|
||||
return_value=[registry_value],
|
||||
), \
|
||||
mock.patch("app.chrome._standard_chrome_candidates", return_value=[]), \
|
||||
mock.patch("app.chrome.shutil.which", return_value=None):
|
||||
detected = chrome.detect_chrome_path()
|
||||
|
||||
self.assertEqual(os.path.abspath(executable), detected)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_detect_chrome_path_uses_local_app_data_without_registry(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
executable = self.make_executable(
|
||||
temp_dir,
|
||||
"Google",
|
||||
"Chrome",
|
||||
"Application",
|
||||
"chrome.exe",
|
||||
)
|
||||
with mock.patch.dict(os.environ, {"LOCALAPPDATA": temp_dir}, clear=True), \
|
||||
mock.patch("app.chrome._registry_chrome_candidates", return_value=[]), \
|
||||
mock.patch("app.chrome.shutil.which", return_value=None):
|
||||
detected = chrome.detect_chrome_path()
|
||||
|
||||
self.assertEqual(os.path.abspath(executable), detected)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_detect_chrome_path_never_uses_edge_and_handles_missing_registry(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
self.make_executable(
|
||||
temp_dir,
|
||||
"Microsoft",
|
||||
"Edge",
|
||||
"Application",
|
||||
"msedge.exe",
|
||||
)
|
||||
with mock.patch("app.chrome._load_winreg", return_value=None), \
|
||||
mock.patch.dict(os.environ, {"LOCALAPPDATA": temp_dir}, clear=True), \
|
||||
mock.patch("app.chrome.shutil.which", return_value=None):
|
||||
detected = chrome.detect_chrome_path()
|
||||
|
||||
self.assertEqual("", detected)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_ensure_configured_chrome_path_persists_only_when_invalid(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config_path = os.path.join(temp_dir, "config.json")
|
||||
detected = self.make_executable(temp_dir, "Chrome", "chrome.exe")
|
||||
config = appconfig.load_config(config_path)
|
||||
|
||||
with mock.patch("app.chrome.detect_chrome_path", return_value=detected):
|
||||
first = chrome.ensure_configured_chrome_path(config)
|
||||
|
||||
self.assertTrue(first["changed"])
|
||||
self.assertEqual(os.path.abspath(detected), first["config"]["chrome_path"])
|
||||
self.assertIn("已自动定位 Chrome", first["message"])
|
||||
self.assertEqual(
|
||||
os.path.abspath(detected),
|
||||
appconfig.load_config(config_path)["chrome_path"],
|
||||
)
|
||||
|
||||
missing = os.path.join(temp_dir, "missing", "chrome.exe")
|
||||
invalid = appconfig.save_config(
|
||||
{"chrome_path": missing},
|
||||
path=config_path,
|
||||
)
|
||||
with mock.patch("app.chrome.detect_chrome_path", return_value=detected):
|
||||
repaired = chrome.ensure_configured_chrome_path(invalid)
|
||||
self.assertTrue(repaired["changed"])
|
||||
self.assertEqual(os.path.abspath(detected), repaired["config"]["chrome_path"])
|
||||
|
||||
custom = self.make_executable(temp_dir, "Portable", "chrome.exe")
|
||||
valid = appconfig.save_config(
|
||||
{"chrome_path": custom},
|
||||
path=config_path,
|
||||
)
|
||||
with mock.patch("app.chrome.detect_chrome_path") as detect:
|
||||
unchanged = chrome.ensure_configured_chrome_path(valid)
|
||||
self.assertFalse(unchanged["changed"])
|
||||
self.assertEqual(custom, unchanged["config"]["chrome_path"])
|
||||
detect.assert_not_called()
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_ensure_configured_chrome_path_preserves_path_command_and_no_match(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config_path = os.path.join(temp_dir, "config.json")
|
||||
config = appconfig.save_config(
|
||||
{"chrome_path": "chrome.exe"},
|
||||
path=config_path,
|
||||
)
|
||||
resolved_path = self.make_executable(temp_dir, "PATH", "chrome.exe")
|
||||
|
||||
with mock.patch("app.chrome.shutil.which", return_value=resolved_path), \
|
||||
mock.patch("app.chrome.detect_chrome_path") as detect:
|
||||
unchanged = chrome.ensure_configured_chrome_path(config)
|
||||
self.assertFalse(unchanged["changed"])
|
||||
detect.assert_not_called()
|
||||
|
||||
empty = appconfig.save_config({"chrome_path": ""}, path=config_path)
|
||||
with mock.patch("app.chrome.detect_chrome_path", return_value=""), \
|
||||
mock.patch("app.chrome.appconfig.save_config") as save:
|
||||
no_match = chrome.ensure_configured_chrome_path(empty)
|
||||
self.assertFalse(no_match["changed"])
|
||||
self.assertEqual("", no_match["message"])
|
||||
save.assert_not_called()
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_build_launch_args_includes_required_flags(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = {
|
||||
|
||||
Reference in New Issue
Block a user