v0.31.7
This commit is contained in:
1 parent
4cc994b3bc
commit
79fd198949
48 files changed
+922
-202
No files matched your search
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""0.31.7 offline update-retention regression without systemd or root privileges."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
UPDATER = ROOT / "update.sh"
|
||||
|
||||
|
||||
def mkdir_age(path: Path, days: int) -> None:
|
||||
path.mkdir(parents=True)
|
||||
stamp = time.time() - days * 86400
|
||||
os.utime(path, (stamp, stamp))
|
||||
|
||||
|
||||
def call(update_prefix: Path, cargo_target: Path, mockbin: Path, *, fail: bool = False, plan: bool = False) -> subprocess.CompletedProcess[str]:
|
||||
env = os.environ.copy()
|
||||
env["PATH"] = f"{mockbin}:{env.get('PATH', '')}"
|
||||
env["CARGO_TARGET_DIR"] = str(cargo_target)
|
||||
env["RP_TEST_UPDATE_FAIL"] = "1" if fail else "0"
|
||||
args = ["bash", str(UPDATER), "--prefix", str(update_prefix)]
|
||||
if plan:
|
||||
args.append("--plan")
|
||||
return subprocess.run(args, env=env, capture_output=True, text=True, timeout=15, check=False)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
subprocess.run(["bash", "-n", str(UPDATER)], check=True)
|
||||
with tempfile.TemporaryDirectory(prefix="rp-release-0317-") as tmp:
|
||||
root = Path(tmp)
|
||||
prefix = root / "installed rustproxy"
|
||||
releases = prefix / "releases"
|
||||
backups = prefix / "backups"
|
||||
releases.mkdir(parents=True)
|
||||
backups.mkdir()
|
||||
for name, age in [("r-new", 0), ("r-second", 2), ("r-live", 8), ("r-ancient", 30), ("r-older extra", 40)]:
|
||||
mkdir_age(releases / name, age)
|
||||
(prefix / "current").symlink_to(releases / "r-live", target_is_directory=True)
|
||||
for days in range(1, 6):
|
||||
mkdir_age(backups / f"before-{days}", days)
|
||||
target = root / "target"
|
||||
for profile in ["release", "debug"]:
|
||||
(target / profile / "deps").mkdir(parents=True)
|
||||
(target / profile / ".fingerprint").mkdir()
|
||||
(target / profile / "build").mkdir()
|
||||
(target / profile / "rust-proxy").write_text("compiled binary")
|
||||
mkdir_age(target / profile / "incremental" / "old", 50)
|
||||
mkdir_age(target / profile / "incremental" / "new", 1)
|
||||
mockbin = root / "bin"
|
||||
mockbin.mkdir()
|
||||
stub = mockbin / "python3"
|
||||
stub.write_text("#!/bin/sh\n[ \"${RP_TEST_UPDATE_FAIL:-0}\" != 1 ] || exit 17\nexit 0\n")
|
||||
stub.chmod(0o755)
|
||||
|
||||
result = call(prefix, target, mockbin, fail=True)
|
||||
assert result.returncode == 17, result.stderr
|
||||
assert (releases / "r-older extra").exists(), "failed update cleaned releases"
|
||||
assert (target / "release" / "incremental" / "old").exists(), "failed update cleaned target"
|
||||
|
||||
result = call(prefix, target, mockbin, plan=True)
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert (releases / "r-older extra").exists(), "planned update cleaned releases"
|
||||
|
||||
result = call(prefix, target, mockbin)
|
||||
assert result.returncode == 0, (result.stdout, result.stderr)
|
||||
assert sorted(path.name for path in releases.iterdir()) == ["r-live", "r-new"], result.stdout
|
||||
assert sorted(path.name for path in backups.iterdir()) == ["before-1", "before-2", "before-3"], result.stdout
|
||||
assert (prefix / "current").resolve() == releases / "r-live", "current symlink changed"
|
||||
for profile in ["debug", "release"]:
|
||||
assert not (target / profile / "incremental" / "old").exists(), "old incremental retained"
|
||||
assert (target / profile / "incremental" / "new").exists(), "recent incremental removed"
|
||||
for artifact in ["deps", ".fingerprint", "build", "rust-proxy", ".cargo-lock"]:
|
||||
assert (target / profile / artifact).exists(), f"removed Cargo artifact: {profile}/{artifact}"
|
||||
|
||||
# Safety: do not touch target if a parent directory is a symlink.
|
||||
target_symlink_root = root / "symlink"
|
||||
target_symlink_root.symlink_to(target, target_is_directory=True)
|
||||
mkdir_age(target / "release" / "incremental" / "symlink-test", 50)
|
||||
result = call(prefix, target_symlink_root, mockbin)
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert (target / "release" / "incremental" / "symlink-test").exists(), "followed symlinked target"
|
||||
|
||||
# Static source contracts for the managed-update cache handoff.
|
||||
deploy = (ROOT / "scripts/deploy/deploy_runtime.py").read_text()
|
||||
runtime = (ROOT / "src/main/admin_runtime.rs").read_text()
|
||||
demote = (ROOT / "src/cache/cold/demotion.rs").read_text()
|
||||
assert "stop_for_managed_update(data)" in deploy
|
||||
assert "run(['systemctl', 'stop', SERVICE])" in deploy
|
||||
assert "data_dir.join(\".managed-update\").is_file()" in runtime
|
||||
assert "state.cache.flush_hot_to_cold_for_update()" in runtime
|
||||
assert "self.flush_hot_to_cold_inner(true).await" in demote
|
||||
print("PASS: 0.31.7 failed/plan/successful update, two releases + three backups, Cargo safety/symlink guards, managed-update flush wiring.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user