The reconciliation merge b681f0c50e dropped the branch's gateway startup block:
the daemon never passes through the CLI dispatch, so it takes the same passive
PM verdict (check_runtime), the record-gated boot bootstrap, and the due-gated
plugin update check as a housekeeping chore from its first tick.
56 lines
2.1 KiB
Python
56 lines
2.1 KiB
Python
"""A real bootstrap reader pins its generation before GC can select victims."""
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def test_bootstrap_lease_survives_selection_change(tmp_path, monkeypatch):
|
|
from pm.environments import install_state_dir, runtime_facts_path, site_packages
|
|
from hermes_cli.runtime_state import collect_generations
|
|
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir()
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "home"))
|
|
state = install_state_dir(repo)
|
|
for name in ("first", "second", "unused"):
|
|
venv = state / "environments" / name / "venv"
|
|
venv.mkdir(parents=True)
|
|
# pyvenv.cfg first: the layout keys its site-packages path off the recorded version.
|
|
(venv / "pyvenv.cfg").write_text("version = 3.11")
|
|
site_packages(venv).mkdir(parents=True)
|
|
(venv.parent / ".lease-managed").touch()
|
|
legacy = state / "environments" / "old-unleased"
|
|
legacy.mkdir()
|
|
|
|
def select(name):
|
|
environment = state / "environments" / name / "venv"
|
|
runtime_facts_path(repo).write_text(json.dumps({"packages": {"venv": {"environment": str(environment)}}}))
|
|
return environment
|
|
|
|
first = select("first")
|
|
code = '''
|
|
import sys
|
|
from pathlib import Path
|
|
from pm.environments import activate_dependencies
|
|
activate_dependencies(Path(sys.argv[1]))
|
|
print("ready", flush=True)
|
|
sys.stdin.readline()
|
|
'''
|
|
child = subprocess.Popen([sys.executable, "-c", code, str(repo)], env=dict(os.environ),
|
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
try:
|
|
assert child.stdout.readline().strip() == "ready"
|
|
select("second")
|
|
collect_generations(repo, min_age_seconds=0)
|
|
assert first.is_dir()
|
|
assert not (state / "environments" / "unused").exists()
|
|
assert legacy.is_dir()
|
|
finally:
|
|
child.communicate("done\n", timeout=15)
|
|
assert child.returncode == 0
|
|
collect_generations(repo, min_age_seconds=0)
|
|
assert not first.exists()
|
|
assert (state / "environments" / "second").is_dir()
|
|
assert legacy.is_dir()
|