mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-11 02:32:20 +02:00
* fix(cookbook): record real Windows pid for local serve so Stop kills the model The Windows-local serve runner recorded Git Bash's `$$`, which is the MSYS/Cygwin pid, not the Windows pid. Win32 tooling (taskkill, Get-CimInstance ParentProcessId, Stop-Process) can't match an MSYS pid, so the frontend Stop-Tree walk found nothing and the llama-server child survived after Stop, leaving the model loaded and the GPU pinned. Record the serving shell's true Win32 pid via `/proc/$$/winpid`, falling back to the outer proc.pid already written from Python when the map is unavailable. The existing pid-tracking test asserted the buggy `$$` literal at the source level, so it passed while the feature was broken; update it to the winpid behavior and add a focused regression test. * fix(cookbook): make Windows serve pid handoff deterministic --------- Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com> Co-authored-by: Alexandre Teixeira <alexandremagteixeira@gmail.com>
181 lines
4.9 KiB
Python
181 lines
4.9 KiB
Python
"""Behavioral regression coverage for Windows-local Cookbook PID recording."""
|
|
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from routes.cookbook_routes import _windows_local_pid_record_line
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
COOKBOOK_ROUTES = ROOT / "routes" / "cookbook_routes.py"
|
|
|
|
|
|
def _fake_cat(tmp_path: Path, body: str) -> Path:
|
|
fake_bin = tmp_path / "bin"
|
|
fake_bin.mkdir()
|
|
cat = fake_bin / "cat"
|
|
cat.write_text("#!/bin/sh\n" + body + "\n", encoding="utf-8")
|
|
cat.chmod(0o755)
|
|
return fake_bin
|
|
|
|
|
|
def _env_for(fake_bin: Path, **extra: str) -> dict[str, str]:
|
|
env = dict(os.environ)
|
|
env["PATH"] = str(fake_bin) + os.pathsep + env.get("PATH", "")
|
|
env.update(extra)
|
|
return env
|
|
|
|
|
|
def _run_pid_line(
|
|
pid_path: Path,
|
|
ready_path: Path,
|
|
fake_bin: Path,
|
|
**extra_env: str,
|
|
) -> subprocess.CompletedProcess:
|
|
return subprocess.run(
|
|
["bash", "-c", _windows_local_pid_record_line(pid_path, ready_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
env=_env_for(fake_bin, **extra_env),
|
|
timeout=10,
|
|
)
|
|
|
|
|
|
def test_windows_local_pid_line_records_numeric_winpid_after_fallback(tmp_path):
|
|
pid_path = tmp_path / "serve.pid"
|
|
ready_path = tmp_path / "serve.pid.ready"
|
|
|
|
pid_path.write_text("11111", encoding="utf-8")
|
|
ready_path.touch()
|
|
|
|
cat_arg = tmp_path / "cat-arg.txt"
|
|
fake_bin = _fake_cat(
|
|
tmp_path,
|
|
'printf "%s\\n" "$1" > "$FAKE_CAT_ARG"\n'
|
|
'printf "%s\\n" "$FAKE_WINPID"',
|
|
)
|
|
|
|
result = _run_pid_line(
|
|
pid_path,
|
|
ready_path,
|
|
fake_bin,
|
|
FAKE_CAT_ARG=str(cat_arg),
|
|
FAKE_WINPID="42324",
|
|
)
|
|
|
|
assert result.returncode == 0, result.stderr
|
|
assert pid_path.read_text(encoding="utf-8").strip() == "42324"
|
|
assert not ready_path.exists()
|
|
|
|
proc_path = cat_arg.read_text(encoding="utf-8").strip()
|
|
parts = proc_path.strip("/").split("/")
|
|
assert len(parts) == 3
|
|
assert parts[0] == "proc"
|
|
assert parts[1].isdigit()
|
|
assert parts[2] == "winpid"
|
|
|
|
|
|
def test_windows_local_pid_line_waits_for_python_fallback_before_replacing(tmp_path):
|
|
pid_path = tmp_path / "serve.pid"
|
|
ready_path = tmp_path / "serve.pid.ready"
|
|
|
|
fake_bin = _fake_cat(
|
|
tmp_path,
|
|
'printf "%s\\n" "$FAKE_WINPID"',
|
|
)
|
|
|
|
proc = subprocess.Popen(
|
|
[
|
|
"bash",
|
|
"-c",
|
|
_windows_local_pid_record_line(pid_path, ready_path),
|
|
],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
env=_env_for(fake_bin, FAKE_WINPID="42324"),
|
|
)
|
|
|
|
# The inner shell has started, but Python has not published its fallback yet.
|
|
time.sleep(0.05)
|
|
assert proc.poll() is None
|
|
assert not pid_path.exists()
|
|
|
|
# Simulate the post-Popen Python publication order.
|
|
pid_path.write_text("31100", encoding="utf-8")
|
|
ready_path.touch()
|
|
|
|
stdout, stderr = proc.communicate(timeout=10)
|
|
|
|
assert proc.returncode == 0, stderr or stdout
|
|
assert pid_path.read_text(encoding="utf-8").strip() == "42324"
|
|
assert not ready_path.exists()
|
|
|
|
|
|
def test_windows_local_pid_line_preserves_outer_pid_when_mapping_missing(tmp_path):
|
|
pid_path = tmp_path / "serve.pid"
|
|
ready_path = tmp_path / "serve.pid.ready"
|
|
|
|
pid_path.write_text("31100", encoding="utf-8")
|
|
ready_path.touch()
|
|
|
|
fake_bin = _fake_cat(tmp_path, "exit 1")
|
|
|
|
result = _run_pid_line(
|
|
pid_path,
|
|
ready_path,
|
|
fake_bin,
|
|
)
|
|
|
|
assert result.returncode == 0, result.stderr
|
|
assert pid_path.read_text(encoding="utf-8").strip() == "31100"
|
|
assert not ready_path.exists()
|
|
|
|
|
|
def test_windows_local_pid_line_rejects_malformed_mapping(tmp_path):
|
|
pid_path = tmp_path / "serve.pid"
|
|
ready_path = tmp_path / "serve.pid.ready"
|
|
|
|
pid_path.write_text("31100", encoding="utf-8")
|
|
ready_path.touch()
|
|
|
|
fake_bin = _fake_cat(
|
|
tmp_path,
|
|
'printf "not-a-win32-pid\\n"',
|
|
)
|
|
|
|
result = _run_pid_line(
|
|
pid_path,
|
|
ready_path,
|
|
fake_bin,
|
|
)
|
|
|
|
assert result.returncode == 0, result.stderr
|
|
assert pid_path.read_text(encoding="utf-8").strip() == "31100"
|
|
assert not ready_path.exists()
|
|
|
|
|
|
def test_local_windows_launcher_publishes_fallback_before_releasing_inner_runner():
|
|
source = COOKBOOK_ROUTES.read_text(encoding="utf-8")
|
|
start = source.index(" def _launch_local_detached(")
|
|
end = source.index(
|
|
' @router.post("/api/model/download")',
|
|
start,
|
|
)
|
|
launcher = source[start:end]
|
|
|
|
assert "_windows_local_pid_record_line(pid_path, pid_ready_path)" in launcher
|
|
assert "pid_ready_path.unlink(missing_ok=True)" in launcher
|
|
|
|
fallback = launcher.index(
|
|
'pid_path.write_text(str(proc.pid), encoding="utf-8")'
|
|
)
|
|
release = launcher.index("pid_ready_path.touch()")
|
|
|
|
assert fallback < release
|
|
|
|
# Never write Git Bash's bare MSYS $$ to the session pid file.
|
|
assert '\\"$$\\" > {pp}' not in launcher
|