mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 03:18:14 +08:00
134 lines
4.2 KiB
Python
134 lines
4.2 KiB
Python
"""
|
|
已加载原生发行包的磁盘替换检测。
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
import app.runtime.dependencies.native as native_dependencies
|
|
|
|
|
|
class _Distribution:
|
|
"""
|
|
提供 importlib.metadata.Distribution 的最小文件契约。
|
|
"""
|
|
|
|
def __init__(self, root: Path, *, version: str) -> None:
|
|
self.root = root
|
|
self.version = version
|
|
self.metadata = {"Name": "Native_Demo"}
|
|
self.files = (
|
|
Path("native_demo/__init__.py"),
|
|
Path("native_demo/extension.cpython-314-darwin.so"),
|
|
Path("native_demo/.libs/libdemo.2.dylib"),
|
|
)
|
|
|
|
def locate_file(self, path: Path) -> Path:
|
|
"""
|
|
把发行包相对路径定位到测试根目录。
|
|
"""
|
|
return self.root / path
|
|
|
|
|
|
def _write_distribution(root: Path) -> tuple[Path, Path]:
|
|
"""
|
|
创建一个扩展模块及其旁加载本地库。
|
|
"""
|
|
extension = root / "native_demo/extension.cpython-314-darwin.so"
|
|
library = root / "native_demo/.libs/libdemo.2.dylib"
|
|
extension.parent.mkdir(parents=True)
|
|
library.parent.mkdir(parents=True)
|
|
(root / "native_demo/__init__.py").write_text("", encoding="utf-8")
|
|
extension.write_bytes(b"extension-v1")
|
|
library.write_bytes(b"library-v1")
|
|
return extension, library
|
|
|
|
|
|
def test_detects_changed_sibling_library_for_loaded_extension(tmp_path, monkeypatch):
|
|
"""
|
|
扩展已加载时,同发行包旁加载库被替换也必须要求新进程激活。
|
|
"""
|
|
extension, library = _write_distribution(tmp_path)
|
|
baseline_distribution = _Distribution(tmp_path, version="1.0.0")
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"_iter_installed_distributions",
|
|
lambda: (baseline_distribution,),
|
|
)
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"_loaded_native_paths",
|
|
lambda: {native_dependencies._path_key(extension)},
|
|
)
|
|
|
|
baseline = native_dependencies.capture_loaded_native_dependencies()
|
|
library.write_bytes(b"library-version-two")
|
|
current_distribution = _Distribution(tmp_path, version="2.0.0")
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"distribution",
|
|
lambda _name: current_distribution,
|
|
)
|
|
|
|
changes = native_dependencies.detect_changed_native_dependencies(baseline)
|
|
|
|
assert len(changes) == 1
|
|
assert changes[0].distribution == "native-demo"
|
|
assert changes[0].previous_version == "1.0.0"
|
|
assert changes[0].current_version == "2.0.0"
|
|
assert changes[0].artifacts == ("libdemo.2.dylib",)
|
|
|
|
|
|
def test_ignores_native_distribution_that_is_not_loaded(tmp_path, monkeypatch):
|
|
"""
|
|
尚未加载的原生包首次安装或更新不需要提示重启。
|
|
"""
|
|
_write_distribution(tmp_path)
|
|
installed_distribution = _Distribution(tmp_path, version="1.0.0")
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"_iter_installed_distributions",
|
|
lambda: (installed_distribution,),
|
|
)
|
|
monkeypatch.setattr(native_dependencies, "_loaded_native_paths", set)
|
|
|
|
baseline = native_dependencies.capture_loaded_native_dependencies()
|
|
|
|
assert baseline.distributions == ()
|
|
|
|
|
|
def test_unchanged_loaded_native_distribution_does_not_require_restart(
|
|
tmp_path,
|
|
monkeypatch,
|
|
):
|
|
"""
|
|
依赖安装未改变原生文件时不得产生误报。
|
|
"""
|
|
extension, _ = _write_distribution(tmp_path)
|
|
installed_distribution = _Distribution(tmp_path, version="1.0.0")
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"_iter_installed_distributions",
|
|
lambda: (installed_distribution,),
|
|
)
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"_loaded_native_paths",
|
|
lambda: {native_dependencies._path_key(extension)},
|
|
)
|
|
monkeypatch.setattr(
|
|
native_dependencies,
|
|
"distribution",
|
|
lambda _name: installed_distribution,
|
|
)
|
|
|
|
baseline = native_dependencies.capture_loaded_native_dependencies()
|
|
|
|
assert native_dependencies.detect_changed_native_dependencies(baseline) == ()
|
|
|
|
|
|
def test_recognizes_versioned_shared_object_names():
|
|
"""
|
|
Linux 常见的 libname.so.N 旁加载库属于原生载荷。
|
|
"""
|
|
assert native_dependencies._is_native_file("/venv/site-packages/demo/libdemo.so.3")
|