"""The Space must stay installable the way Voyager's README says. Upstream documents a specific install: `pip install -e .`, Python >= 3.9, Node.js >= 16.13.0, and a dependency list in requirements.txt. This deployment keeps a local inference server and a shared Bedrock world, so it deviates in places, but the parts that are pure installation must not drift silently. """ from __future__ import annotations import re import subprocess import sys from pathlib import Path import voyager_stack as stack ROOT = Path(__file__).resolve().parents[1] UPSTREAM_REQUIREMENTS = Path( r"C:\Users\PCGAME~1\AppData\Local\Temp\kilo\voyager-upstream-ref\requirements.txt" ) def _requirement_names(text: str) -> set[str]: names = set() for line in text.splitlines(): line = line.split("#", 1)[0].strip() if not line or line.startswith("-"): continue name = re.split(r"[<>=!~\[]", line, maxsplit=1)[0].strip().lower() if name: names.add(name.replace("_", "-")) return names def test_space_requirements_cover_every_upstream_dependency(): space = _requirement_names((ROOT / "requirements.txt").read_text(encoding="utf-8")) upstream = _requirement_names(UPSTREAM_REQUIREMENTS.read_text(encoding="utf-8")) # cchardet is upstream's optional chardet accelerator. It is only reached when # chromadb can build it, and building it needs libchardet headers that are not # available on the Space image, so requiring it would fail the whole build. deliberately_skipped = {"cchardet"} missing = upstream - space - deliberately_skipped assert missing == set(), f"upstream dependencies missing from requirements.txt: {missing}" # chromadb is pinned differently on purpose: the Space resolves langchain # 0.0.350, and upstream's 0.3.29 predates it. assert "chromadb" in space def test_python_floor_matches_the_readme(): assert stack.MIN_PYTHON == (3, 9) assert stack._require_python_version() == ".".join( str(part) for part in sys.version_info[:3] ) def test_node_floor_is_enforced(monkeypatch): assert stack.MIN_NODE == (16, 13, 0) class _Result: def __init__(self, stdout, returncode=0): self.stdout = stdout self.returncode = returncode def fake_run(args, **kwargs): assert args == ["node", "--version"] return _Result(fake_run.reported) monkeypatch.setattr(stack.subprocess, "run", fake_run) fake_run.reported = "v16.13.0\n" assert stack._require_node_version() == "16.13.0" fake_run.reported = "v18.20.4\n" assert stack._require_node_version() == "18.20.4" fake_run.reported = "v16.12.0\n" try: stack._require_node_version() except RuntimeError as exc: assert "16.13.0" in str(exc) else: raise AssertionError("Node.js below the README minimum was accepted") fake_run.reported = "not-a-version\n" try: stack._require_node_version() except RuntimeError: pass else: raise AssertionError("unreadable Node.js version was accepted") def test_editable_install_is_run_and_verified(monkeypatch, tmp_path): monkeypatch.setattr(stack, "ROOT", tmp_path) commands: list[list[str]] = [] def fake_run(args, cwd, env=None, timeout=900): commands.append(list(args)) monkeypatch.setattr(stack, "_run", fake_run) class _Probe: def __init__(self, returncode=0, stdout="0.1\n"): self.returncode = returncode self.stdout = stdout probes: list[_Probe] = [_Probe()] monkeypatch.setattr(stack.subprocess, "run", lambda *a, **k: probes[0]) stack.VoyagerStack()._ensure_python_package() assert len(commands) == 1, commands install = commands[0] assert install[1:6] == ["-m", "pip", "install", "-e", "."] # --no-deps keeps the Space's pinned inference stack authoritative. assert "--no-deps" in install # --no-build-isolation stops pip from fetching a different setuptools at boot. assert "--no-build-isolation" in install assert (tmp_path / ".voyager-installed").exists() # A second boot inside the same container must not reinstall. stack.VoyagerStack()._ensure_python_package() assert len(commands) == 1 # An install that did not take effect is an error, never a silent fallback. probes[0] = _Probe(returncode=1, stdout="No module named 'voyager'") try: stack.VoyagerStack()._ensure_python_package() except RuntimeError as exc: assert "editable install" in str(exc) else: raise AssertionError("a missing editable install was accepted") def test_boot_runs_the_documented_install_in_order(): source = (ROOT / "voyager_stack.py").read_text(encoding="utf-8") gates = source.index("_require_python_version()") node = source.index("_require_node_version()") clone = source.index("self._ensure_source()") install = source.index("self._ensure_python_package()") node_tree = source.index("node_path = self._ensure_node()") assert gates < clone < install < node_tree if __name__ == "__main__": test_space_requirements_cover_every_upstream_dependency() test_python_floor_matches_the_readme() test_node_floor_is_enforced(lambda *a, **k: None) test_boot_runs_the_documented_install_in_order() print("PASS documented Voyager installation") def test_the_bedrock_movement_correction_mod_is_installed(): # Measured: the Bedrock player received ~100 "moved too quickly" corrections # in under a minute, with a single delta of -3556 blocks, so the server kept # snapping their position back. Geyser translates Bedrock movement to Java and # the two disagree; GeyserMC/Geyser#3407 is still open and the Spigot/Paper # thresholds it mentions do not exist on a Fabric server. TooFast is the # server-side mixin that removes the vanilla speed check. import minecraft_stack as mc assert mc.TOO_FAST_URL.endswith("toofast-1.19-1.0.0.jar") assert len(mc.TOO_FAST_SHA256) == 64 assert all(c in "0123456789abcdef" for c in mc.TOO_FAST_SHA256) source = (Path(__file__).resolve().parents[1] / "minecraft_stack.py").read_text( encoding="utf-8" ) assert '("toofast-1.19-1.0.0.jar", TOO_FAST_URL, TOO_FAST_SHA256)' in source, ( "the jar must be downloaded into the Fabric mods directory like the others" ) # It is a local addition, and the log has to say so rather than list it as # part of the official Voyager set. assert "not an upstream requirement" in source assert "TooFast 1.0.0 (local" in source