message / tests /test_browser_mcp_binary_locator.py
hunian
refactor(plugins): 插件短名并统一 MCP tool 为 {plugin}-{tool}
cc826a1
Raw
History Blame Contribute Delete
4.46 kB
"""binary_locator.py 探测逻辑测试。
用 monkeypatch 模拟环境变量、PATH、可执行性检查,覆盖 env/path/common/wsl/全失败分支。
"""
import os
import platform
from pathlib import Path
from unittest.mock import patch
import pytest
from plugins.browser.browser import binary_locator
def _make_executable(tmp_path: Path, name: str = "lightpanda") -> Path:
"""在 tmp_path 下造一个可执行文件。"""
p = tmp_path / name
p.write_text("#!/bin/sh\n")
p.chmod(0o755)
return p
def test_env_path_detected(tmp_path, monkeypatch):
"""LIGHTPANDA_BINARY 指向可执行文件时 source=env。"""
binp = _make_executable(tmp_path)
monkeypatch.setenv("LIGHTPANDA_BINARY", str(binp))
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_read_version", lambda b: "0.2.0")
r = binary_locator.locate_lightpanda()
assert r.available is True
assert r.path == str(binp)
assert r.source == "env"
assert r.version == "0.2.0"
def test_env_path_not_executable_falls_through(tmp_path, monkeypatch):
"""LIGHTPANDA_BINARY 指向不可执行文件时不命中。
注:Windows 不用 Unix 权限位判定可执行性,故直接 mock _check_path_executable
返回 False 来模拟"存在但不可执行"。
"""
p = tmp_path / "lightpanda"
p.write_text("not executable")
monkeypatch.setenv("LIGHTPANDA_BINARY", str(p))
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
monkeypatch.setattr(binary_locator, "_check_path_executable", lambda path: False)
r = binary_locator.locate_lightpanda()
assert r.available is False
def test_path_detected(tmp_path, monkeypatch):
"""shutil.which 找到可执行文件时 source=path。"""
binp = _make_executable(tmp_path)
monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: str(binp))
monkeypatch.setattr(binary_locator, "_read_version", lambda b: "0.2.0")
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
r = binary_locator.locate_lightpanda()
assert r.available is True
assert r.source == "path"
def test_all_fail_returns_unavailable(monkeypatch):
"""全部探测失败时 available=False 且 source=none。"""
monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)
r = binary_locator.locate_lightpanda()
assert r.available is False
assert r.source == "none"
assert r.error
assert r.install_hints # 必须带安装提示
def test_install_hints_contain_docker_and_wsl(monkeypatch):
"""install_hints 总是包含 docker 和 wsl 备选。"""
monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)
r = binary_locator.locate_lightpanda()
assert "docker" in r.install_hints
assert "wsl" in r.install_hints
def test_to_dict_serializable(monkeypatch):
"""to_dict 返回可 JSON 序列化的 dict。"""
import json
monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)
r = binary_locator.locate_lightpanda()
d = r.to_dict()
json.dumps(d) # 不抛即 OK
assert d["available"] is False
def test_is_binary_available_consistent(monkeypatch):
"""is_binary_available 与 locate_lightpanda().available 一致。"""
monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)
assert binary_locator.is_binary_available() is False