Files
flow/tests/test_service_packages.py
2026-03-16 08:06:25 +02:00

133 lines
4.9 KiB
Python

"""Tests for PackageService."""
import io
import tarfile
from pathlib import Path
import pytest
from flow.core.config import AppConfig, FlowContext
from flow.core.console import Console
from flow.core.errors import FlowError
from flow.core.platform import PlatformInfo
from flow.core.runtime import SystemRuntime
from flow.core import paths
from flow.domain.packages.models import InstalledPackage, InstalledState
from flow.services.packages import PackageService
def _make_ctx(tmp_path, manifest=None):
return FlowContext(
config=AppConfig(),
manifest=manifest or {},
platform=PlatformInfo(),
console=Console(color=False),
runtime=SystemRuntime(),
)
class TestPackageService:
def test_list_empty(self, tmp_path, monkeypatch, capsys):
monkeypatch.setattr(paths, "INSTALLED_STATE", tmp_path / "installed.json")
ctx = _make_ctx(tmp_path)
svc = PackageService(ctx)
svc.list_packages()
assert "No packages" in capsys.readouterr().out
def test_list_shows_installed(self, tmp_path, monkeypatch, capsys):
state = InstalledState(packages={
"fd": InstalledPackage(name="fd", version="10.2", type="pkg"),
})
state_path = tmp_path / "installed.json"
import json
state_path.parent.mkdir(parents=True, exist_ok=True)
with open(state_path, "w") as f:
json.dump(state.as_dict(), f)
monkeypatch.setattr(paths, "INSTALLED_STATE", state_path)
ctx = _make_ctx(tmp_path)
svc = PackageService(ctx)
svc.list_packages()
output = capsys.readouterr().out
assert "fd" in output
assert "10.2" in output
def test_remove_not_installed(self, tmp_path, monkeypatch, capsys):
monkeypatch.setattr(paths, "INSTALLED_STATE", tmp_path / "installed.json")
ctx = _make_ctx(tmp_path)
svc = PackageService(ctx)
svc.remove(["missing"])
assert "No matching" in capsys.readouterr().out
def test_install_requires_args(self, tmp_path, monkeypatch):
monkeypatch.setattr(paths, "INSTALLED_STATE", tmp_path / "installed.json")
ctx = _make_ctx(tmp_path)
svc = PackageService(ctx)
with pytest.raises(FlowError, match="Specify"):
svc.install()
def test_list_all_known_packages(self, tmp_path, monkeypatch, capsys):
monkeypatch.setattr(paths, "INSTALLED_STATE", tmp_path / "installed.json")
manifest = {"packages": [{"name": "fd", "type": "pkg"}]}
ctx = _make_ctx(tmp_path, manifest)
svc = PackageService(ctx)
svc.list_packages(show_all=True)
assert "fd" in capsys.readouterr().out
def test_install_binary_honors_declared_install_map(self, tmp_path, monkeypatch):
home = tmp_path / "home"
home.mkdir()
monkeypatch.setenv("HOME", str(home))
monkeypatch.setattr(paths, "DATA_DIR", tmp_path / "data")
monkeypatch.setattr(paths, "INSTALLED_STATE", tmp_path / "installed.json")
archive = io.BytesIO()
with tarfile.open(fileobj=archive, mode="w:gz") as tar:
files = {
"nvim-linux64/bin/nvim": b"#!/bin/sh\n",
"nvim-linux64/share/nvim/runtime.txt": b"runtime\n",
"nvim-linux64/share/man/man1/nvim.1": b"manpage\n",
}
for name, content in files.items():
info = tarfile.TarInfo(name=name)
info.size = len(content)
tar.addfile(info, io.BytesIO(content))
archive_bytes = archive.getvalue()
class FakeResponse:
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
def read(self):
return archive_bytes
monkeypatch.setattr("flow.services.packages.urllib.request.urlopen", lambda *args, **kwargs: FakeResponse())
manifest = {
"packages": [{
"name": "neovim",
"type": "binary",
"source": "github:neovim/neovim",
"version": "0.10.4",
"asset-pattern": "nvim-{{os}}-{{arch}}.tar.gz",
"platform-map": {"linux-x64": {"os": "linux", "arch": "x64"}},
"extract-dir": "nvim-{{os}}64",
"install": {
"bin": ["bin/nvim"],
"share": ["share/nvim"],
"man": ["share/man/man1/nvim.1"],
},
}],
}
ctx = _make_ctx(tmp_path, manifest)
svc = PackageService(ctx)
packages = svc.resolve_install_packages(package_names=["neovim"])
svc.install(packages)
assert (home / ".local" / "bin" / "nvim").exists()
assert (home / ".local" / "share" / "nvim" / "runtime.txt").exists()
assert (home / ".local" / "share" / "man" / "man1" / "nvim.1").exists()