Files
wehub-resource-sync 0af812490d
CI / python (push) Failing after 0s
CI / javascript (push) Failing after 1s
CI / dotnet (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:12:36 +08:00

199 lines
7.9 KiB
Python

"""Unit tests for Widevine CDM hint-file seeding (cloakbrowser/widevine.py)."""
import json
import pytest
from cloakbrowser import widevine
from cloakbrowser.widevine import resolve_widevine_cdm_dir, seed_widevine_hint
_HINT = "WidevineCdm/latest-component-updated-widevine-cdm"
@pytest.fixture(autouse=True)
def _force_linux(monkeypatch, tmp_path):
"""Run as if on Linux unless a test overrides it (seeding is Linux-only)."""
monkeypatch.setattr(widevine.platform, "system", lambda: "Linux")
monkeypatch.delenv("CLOAKBROWSER_WIDEVINE", raising=False)
monkeypatch.delenv("CLOAKBROWSER_WIDEVINE_CDM", raising=False)
# Isolate the cache-root fallback from any real ~/.cloakbrowser on the host.
monkeypatch.setenv("CLOAKBROWSER_CACHE_DIR", str(tmp_path / "_isolated_cache"))
def _make_cdm(dirpath):
"""Create a fake WidevineCdm dir with a manifest.json."""
dirpath.mkdir(parents=True, exist_ok=True)
(dirpath / "manifest.json").write_text('{"version": "4.10.3050.0"}')
return dirpath
def _binary(tmp_path):
"""Return a fake chrome binary path inside its own dir."""
bdir = tmp_path / "bin"
bdir.mkdir(parents=True, exist_ok=True)
return bdir / "chrome"
def test_seeds_hint_next_to_binary(tmp_path):
"""CDM in <binary dir>/WidevineCdm -> hint file written with abs Path."""
binary = _binary(tmp_path)
cdm = _make_cdm(binary.parent / "WidevineCdm")
profile = tmp_path / "profile"
seed_widevine_hint(profile, binary)
hint = profile / _HINT
assert hint.is_file()
assert json.loads(hint.read_text())["Path"] == str(cdm.resolve())
def test_seeds_hint_from_env_var(tmp_path, monkeypatch):
"""CLOAKBROWSER_WIDEVINE_CDM takes priority and is used as the Path."""
cdm = _make_cdm(tmp_path / "custom_cdm")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(cdm))
profile = tmp_path / "profile"
seed_widevine_hint(profile, _binary(tmp_path))
assert json.loads((profile / _HINT).read_text())["Path"] == str(cdm.resolve())
def test_no_cdm_no_file(tmp_path):
"""No CDM present -> nothing written, no exception."""
profile = tmp_path / "profile"
seed_widevine_hint(profile, _binary(tmp_path))
assert not (profile / _HINT).exists()
def test_kill_switch_disables(tmp_path, monkeypatch):
"""CLOAKBROWSER_WIDEVINE=0 disables seeding even when a CDM exists."""
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(_make_cdm(tmp_path / "custom_cdm")))
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE", "0")
profile = tmp_path / "profile"
seed_widevine_hint(profile, _binary(tmp_path))
assert not (profile / _HINT).exists()
def test_idempotent(tmp_path, monkeypatch):
"""Seeding twice leaves the same correct content and doesn't error."""
cdm = _make_cdm(tmp_path / "custom_cdm")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(cdm))
profile = tmp_path / "profile"
binary = _binary(tmp_path)
seed_widevine_hint(profile, binary)
seed_widevine_hint(profile, binary)
assert json.loads((profile / _HINT).read_text())["Path"] == str(cdm.resolve())
def test_noop_on_non_linux(tmp_path, monkeypatch):
"""On non-Linux, seeding is a no-op even with a CDM present."""
monkeypatch.setattr(widevine.platform, "system", lambda: "Windows")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(_make_cdm(tmp_path / "cdm")))
profile = tmp_path / "profile"
seed_widevine_hint(profile, _binary(tmp_path))
assert not (profile / _HINT).exists()
def test_resolve_requires_manifest(tmp_path, monkeypatch):
"""A WidevineCdm dir without manifest.json is not treated as a CDM."""
bogus = tmp_path / "custom_cdm"
bogus.mkdir()
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(bogus))
assert resolve_widevine_cdm_dir(_binary(tmp_path)) is None
def test_env_var_is_exclusive(tmp_path, monkeypatch):
"""An invalid CLOAKBROWSER_WIDEVINE_CDM skips seeding — no fallback to binary dir."""
binary = _binary(tmp_path)
_make_cdm(binary.parent / "WidevineCdm") # valid CDM next to binary
bogus = tmp_path / "bogus"
bogus.mkdir() # set but no manifest.json
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(bogus))
assert resolve_widevine_cdm_dir(binary) is None
def test_resolve_falls_back_to_cache_root(tmp_path, monkeypatch):
"""No CDM next to the binary -> auto-detect falls back to <cache>/WidevineCdm.
Simulates the Pro case: a Pro binary sits in its own chromium-<ver>-pro dir
with no adjacent CDM, while the Docker auto-fetch left one at the cache root.
"""
cache = tmp_path / "cache"
monkeypatch.setenv("CLOAKBROWSER_CACHE_DIR", str(cache))
cdm = _make_cdm(cache / "WidevineCdm")
pro_binary = tmp_path / "chromium-148.0-pro" / "chrome"
pro_binary.parent.mkdir(parents=True) # binary dir exists, but has no CDM
assert resolve_widevine_cdm_dir(pro_binary) == cdm.resolve()
def test_resolve_binary_dir_wins_over_cache_root(tmp_path, monkeypatch):
"""A manual sideload next to the binary takes precedence over the cache root."""
cache = tmp_path / "cache"
monkeypatch.setenv("CLOAKBROWSER_CACHE_DIR", str(cache))
_make_cdm(cache / "WidevineCdm") # cache-root CDM present...
binary = _binary(tmp_path)
next_to = _make_cdm(binary.parent / "WidevineCdm") # ...but sideload wins
assert resolve_widevine_cdm_dir(binary) == next_to.resolve()
def test_seeds_hint_from_cache_root_fallback(tmp_path, monkeypatch):
"""End-to-end: a cache-root CDM seeds the hint for a binary with none adjacent."""
cache = tmp_path / "cache"
monkeypatch.setenv("CLOAKBROWSER_CACHE_DIR", str(cache))
cdm = _make_cdm(cache / "WidevineCdm")
profile = tmp_path / "profile"
seed_widevine_hint(profile, _binary(tmp_path)) # binary has no adjacent CDM
assert json.loads((profile / _HINT).read_text())["Path"] == str(cdm.resolve())
def test_empty_env_var_is_exclusive(tmp_path, monkeypatch):
"""An empty (but set) CLOAKBROWSER_WIDEVINE_CDM resolves to None — and must NOT
pick up a stray manifest.json in the working directory (``Path("")`` -> ``.``)."""
binary = _binary(tmp_path)
_make_cdm(binary.parent / "WidevineCdm") # valid CDM next to binary
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", "")
cwd = tmp_path / "cwd"
cwd.mkdir()
(cwd / "manifest.json").write_text("{}") # stray manifest in CWD must be ignored
monkeypatch.chdir(cwd)
assert resolve_widevine_cdm_dir(binary) is None
def test_empty_user_data_dir_skips(tmp_path, monkeypatch):
"""Empty user_data_dir (ephemeral profile) -> no CWD pollution, no seeding."""
cdm = _make_cdm(tmp_path / "custom_cdm")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(cdm))
monkeypatch.chdir(tmp_path)
seed_widevine_hint("", _binary(tmp_path))
assert not (tmp_path / "WidevineCdm").exists()
def test_never_raises_on_write_failure(tmp_path, monkeypatch):
"""A write failure (hint dir path is a file) must not raise — launch must not break."""
cdm = _make_cdm(tmp_path / "custom_cdm")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(cdm))
profile = tmp_path / "profile"
profile.mkdir()
# Block mkdir of <profile>/WidevineCdm by occupying that path with a file.
(profile / "WidevineCdm").write_text("not a dir")
seed_widevine_hint(profile, _binary(tmp_path)) # must not raise
def test_rewrites_corrupt_existing_hint(tmp_path, monkeypatch):
"""A non-UTF8 / mismatched existing hint is overwritten, without raising."""
cdm = _make_cdm(tmp_path / "custom_cdm")
monkeypatch.setenv("CLOAKBROWSER_WIDEVINE_CDM", str(cdm))
profile = tmp_path / "profile"
hint = profile / "WidevineCdm" / _HINT.split("/")[-1]
hint.parent.mkdir(parents=True)
hint.write_bytes(b"\xff\xfe not valid utf-8")
seed_widevine_hint(profile, _binary(tmp_path)) # must not raise
# corrupt content replaced with a valid hint pointing at the CDM
assert json.loads(hint.read_text())["Path"] == str(cdm.resolve())