104 lines
4.1 KiB
Python
104 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""The agent and its supervisor must mean the same thing by "here".
|
|
|
|
python3 tests/test_vm_working_directory.py
|
|
|
|
WHY
|
|
|
|
A Windows session was asked to write a PowerShell script, test it, and
|
|
keep it. It did all three, perfectly, and the session was reported as a
|
|
failure.
|
|
|
|
The agent's `run` inherited whatever directory the guest agent happened to
|
|
start in - on Windows, `C:\\Windows\\system32`. So `Set-Content
|
|
Get-SystemInfo.ps1`, `Get-Content .\\Get-SystemInfo.ps1` and
|
|
`powershell .\\Get-SystemInfo.ps1` all agreed with each other and all
|
|
passed. The supervisor then re-ran the verification from the PROJECT
|
|
folder, because that is the only place work survives, and found nothing
|
|
there. The model read the failure, worked out what had happened, and spent
|
|
a second whole session redoing it - roughly four minutes of machine time
|
|
to move a file.
|
|
|
|
Two rules come out of that, and this file holds both:
|
|
|
|
1. There is ONE definition of where a command runs, and both sides call
|
|
it. Two copies of this logic is exactly how they came to disagree.
|
|
2. It is the project folder, because that is the only thing that
|
|
outlives the machine. A file written anywhere else is deleted with
|
|
the disk.
|
|
"""
|
|
|
|
import ast
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
VMD = os.path.join(HERE, "..", "vm", "vmd")
|
|
sys.path.insert(0, VMD)
|
|
|
|
FAILS: list[str] = []
|
|
|
|
|
|
def check(label: str, condition: bool, detail: str = "") -> None:
|
|
if condition:
|
|
print(f"ok {label}")
|
|
else:
|
|
FAILS.append(label)
|
|
print(f"FAIL {label}\n {detail}")
|
|
|
|
|
|
import verify # noqa: E402
|
|
|
|
|
|
class FakeSession:
|
|
def __init__(self, os_name, share):
|
|
self.os_name = os_name
|
|
self.share = share
|
|
|
|
|
|
# --- the prelude itself --------------------------------------------------
|
|
linux = verify.working_directory_prelude(FakeSession("ubuntu", "/Pool/vmprojects/x"))
|
|
windows = verify.working_directory_prelude(FakeSession("windows", "/Pool/vmprojects/x"))
|
|
|
|
check("a Linux command starts in the project folder", "/mnt/project" in linux, linux)
|
|
check("a Windows command starts in the project folder", "Z:\\" in windows, windows)
|
|
check("the Windows prelude is PowerShell, not shell",
|
|
"Set-Location" in windows and "||" not in windows,
|
|
"PowerShell has no ||; this exact mistake reported correct work as a claim")
|
|
check("the Linux prelude is shell", "cd " in linux)
|
|
check("neither prelude can fail the command it prefixes",
|
|
"SilentlyContinue" in windows and "2>/dev/null" in linux,
|
|
"a missing share must not turn every command into an error")
|
|
|
|
# With no project folder there is nowhere to keep anything, but a command
|
|
# still has to run somewhere predictable.
|
|
check("a session with no project folder still lands somewhere definite",
|
|
"C:\\" in verify.working_directory_prelude(FakeSession("windows", None))
|
|
and "/root" in verify.working_directory_prelude(FakeSession("ubuntu", None)))
|
|
|
|
# --- and both sides use it -----------------------------------------------
|
|
vmd_src = open(os.path.join(VMD, "vmd.py"), encoding="utf-8").read()
|
|
verify_src = open(os.path.join(VMD, "verify.py"), encoding="utf-8").read()
|
|
|
|
tree = ast.parse(vmd_src)
|
|
run_verb = next(n for n in ast.walk(tree)
|
|
if isinstance(n, ast.FunctionDef) and n.name == "v_run")
|
|
run_src = ast.get_source_segment(vmd_src, run_verb) or ""
|
|
check("the agent's own run is given the prelude",
|
|
"working_directory_prelude" in run_src,
|
|
"this is the half that was missing, and it cost a whole extra session")
|
|
check("the supervisor's re-run is given the same prelude",
|
|
"working_directory_prelude" in verify_src)
|
|
|
|
# One definition, not two. The duplicate is how they drifted apart.
|
|
check("the directory is decided in exactly one place",
|
|
verify_src.count('Set-Location -LiteralPath') == 1
|
|
and vmd_src.count("Set-Location") == 0,
|
|
"a second copy is how the agent and the supervisor came to disagree")
|
|
|
|
print()
|
|
if FAILS:
|
|
print(f"FAILED {len(FAILS)}")
|
|
raise SystemExit(1)
|
|
print("the agent and its supervisor start in the same place, and it is the one that survives")
|