Files
VoiceStudio/tests/test_audiocpp_runtime_install.py
T

94 lines
3.0 KiB
Python

import hashlib
import io
import os
from pathlib import Path
import zipfile
import pytest
from engines.audiocpp import bootstrap
from services import audiocpp_runtime_install as installer
def test_managed_runtime_participates_in_binary_resolution(monkeypatch, tmp_path):
monkeypatch.setattr(bootstrap, "managed_runtime_dir", lambda: tmp_path)
assert tmp_path / bootstrap.binary_name() in bootstrap._probe_paths()
def test_runtime_status_recognizes_matching_managed_cli(monkeypatch, tmp_path):
server = tmp_path / bootstrap.binary_name()
cli = tmp_path / ("audiocpp_cli.exe" if os.name == "nt" else "audiocpp_cli")
server.write_bytes(b"server")
cli.write_bytes(b"cli")
cli.chmod(0o700)
monkeypatch.setattr(bootstrap, "resolve_server_binary", lambda: server)
monkeypatch.setattr(bootstrap, "managed_runtime_dir", lambda: tmp_path)
status = installer.status()
assert status["installed"] is True
assert status["managed"] is True
assert status["version"] == bootstrap.VERSION
def test_runtime_status_does_not_guess_user_managed_version(monkeypatch, tmp_path):
user_dir = tmp_path / "user-runtime"
managed_dir = tmp_path / "managed-runtime"
user_dir.mkdir()
server = user_dir / bootstrap.binary_name()
cli = user_dir / ("audiocpp_cli.exe" if os.name == "nt" else "audiocpp_cli")
server.write_bytes(b"server")
cli.write_bytes(b"cli")
cli.chmod(0o700)
monkeypatch.setattr(bootstrap, "resolve_server_binary", lambda: server)
monkeypatch.setattr(bootstrap, "managed_runtime_dir", lambda: managed_dir)
status = installer.status()
assert status["installed"] is True
assert status["managed"] is False
assert status["version"] is None
def test_runtime_download_verifies_size_and_digest(monkeypatch, tmp_path):
payload = b"checksummed runtime"
class Response(io.BytesIO):
headers = {"Content-Length": str(len(payload))}
monkeypatch.setattr(
installer.urllib.request,
"urlopen",
lambda *_args, **_kwargs: Response(payload),
)
destination = tmp_path / "runtime.zip"
installer._download(
"https://github.com/example/runtime.zip",
destination,
hashlib.sha256(payload).hexdigest(),
len(payload),
)
assert destination.read_bytes() == payload
def test_runtime_zip_rejects_parent_traversal(tmp_path):
archive = tmp_path / "runtime.zip"
with zipfile.ZipFile(archive, "w") as bundle:
bundle.writestr("../outside.exe", b"unsafe")
with pytest.raises(RuntimeError, match="unsafe path"):
installer._extract(archive, tmp_path / "target")
assert not (tmp_path / "outside.exe").exists()
def test_pinned_runtime_assets_have_published_sizes_and_sha256():
assert set(bootstrap._ASSETS) == set(bootstrap._ASSET_SIZES)
for slug, (filename, digest) in bootstrap._ASSETS.items():
assert bootstrap.VERSION.removeprefix("v") in filename
assert len(digest) == 64 and set(digest) <= set("0123456789abcdef")
assert bootstrap._ASSET_SIZES[slug] > 20_000_000