"""A failed update lookup is not a current result or permission to apply.""" import importlib from argparse import Namespace import pytest from pm import cli, paths, registry from pm.lock import Lockfile from pm.package import Package from pm.store import current_target class UpdateFixture(Package): def __init__(self, name, versions): self.name = name self.versions = versions self.lookups = 0 def missing_reason(self, target): return None if target == current_target() else "not a fixture target" def latest_versions(self, target, locked=None): self.lookups += 1 if isinstance(self.versions, Exception): raise self.versions return self.versions def prepare(tmp_path, monkeypatch, packages): lock = Lockfile(tmp_path / "lock.json") for package in packages: lock.set_pin(package.name, "1.0", {}) monkeypatch.setitem(registry._packages, package.name, package) lock.save() monkeypatch.setattr(paths, "lockfile_path", lambda: lock.path) monkeypatch.setattr(paths, "repo_root", lambda: tmp_path) monkeypatch.setenv("HERMES_HOME", str(tmp_path / "home")) monkeypatch.setenv("HERMES_RUNTIME_DIR", str(tmp_path / "tools")) def forbidden(*args, **kwargs): pytest.fail("lookup-only result reached a mutation or dependency refresh") for name in ("_pin_artifacts", "_install_names", "_run_live", "lock_project"): monkeypatch.setattr(cli, name, forbidden) monkeypatch.setattr(importlib.import_module("pm.install"), "sync_venv", forbidden) return lock @pytest.mark.parametrize("check", [True, False]) @pytest.mark.parametrize("mixed", [True, False]) def test_failed_resolution_stops_every_apply_path(tmp_path, monkeypatch, capsys, check, mixed): failed = UpdateFixture("failed-lookup", TimeoutError("fixture index unavailable")) healthy = UpdateFixture("healthy-lookup", ["2.0"]) packages = [failed, healthy] if mixed else [failed] lock = prepare(tmp_path, monkeypatch, packages) before = lock.path.read_bytes() args = Namespace(names=[p.name for p in packages], target=None, check=check, uv=True, npm=True, termux=False) assert cli.cmd_update(args) == 1 assert "fixture index unavailable" in capsys.readouterr().out assert lock.path.read_bytes() == before assert not (tmp_path / "tools").exists() if mixed: assert healthy.lookups == 1 @pytest.mark.parametrize("versions", [["1.0"], []]) def test_current_and_manual_results_are_successful_without_writes(tmp_path, monkeypatch, versions): package = UpdateFixture("no-update", versions) lock = prepare(tmp_path, monkeypatch, [package]) before = lock.path.read_bytes() for check in (True, False): args = Namespace(names=[package.name], target=None, check=check, uv=False, npm=False, termux=False) assert cli.cmd_update(args) == 0 assert lock.path.read_bytes() == before assert not (tmp_path / "tools").exists()