feat: add guest IP retrieval functions and enhance VM preparation logic
Lint / pssa (push) Successful in 9s
Lint / python (push) Successful in 21s

This commit is contained in:
2026-05-27 23:34:37 +02:00
parent 3eb29b404f
commit 4c80ff2528
2 changed files with 135 additions and 4 deletions
+91 -3
View File
@@ -1148,7 +1148,7 @@ def test_prepare_win_cleanup_only_fails(
# template deploy-linux — helper unit tests
# ═══════════════════════════════════════════════════════════════════════════
from ci_orchestrator.config import BackendConfig, Config, IpPoolConfig, Paths # noqa: E402
from ci_orchestrator.config import BackendConfig, Config, Paths # noqa: E402
def _deploy_config(tmp_path: Path) -> Config:
@@ -1292,9 +1292,60 @@ def test_build_seed_iso_no_tool_raises(
tmpl_mod._build_seed_iso(tmp_path, tmp_path / "seed.iso")
# ── _read_guestinfo_ip ────────────────────────────────────────────────────────
def test_read_guestinfo_ip_valid(monkeypatch: pytest.MonkeyPatch) -> None:
import subprocess as _sub
monkeypatch.setattr(
tmpl_mod.subprocess, "run",
lambda cmd, **kw: _sub.CompletedProcess(cmd, 0, "10.0.0.5\n", ""),
)
assert tmpl_mod._read_guestinfo_ip("/vmrun", "/vm.vmx") == "10.0.0.5"
def test_read_guestinfo_ip_empty(monkeypatch: pytest.MonkeyPatch) -> None:
import subprocess as _sub
monkeypatch.setattr(
tmpl_mod.subprocess, "run",
lambda cmd, **kw: _sub.CompletedProcess(cmd, 0, "", ""),
)
assert tmpl_mod._read_guestinfo_ip("/vmrun", "/vm.vmx") is None
def test_read_guestinfo_ip_timeout(monkeypatch: pytest.MonkeyPatch) -> None:
import subprocess as _sub
def raise_timeout(cmd: list[str], **kw: object) -> _sub.CompletedProcess[str]:
raise _sub.TimeoutExpired(cmd, 10)
monkeypatch.setattr(tmpl_mod.subprocess, "run", raise_timeout)
assert tmpl_mod._read_guestinfo_ip("/vmrun", "/vm.vmx") is None
# ── _poll_guest_ip_deploy ─────────────────────────────────────────────────────
def test_poll_guest_ip_uses_guestinfo_first(monkeypatch: pytest.MonkeyPatch) -> None:
"""If ci-report-ip has written guestinfo.ci-ip, return it without getGuestIPAddress."""
called: list[list[str]] = []
import subprocess as _sub
def fake_run(cmd: list[str], **kw: object) -> _sub.CompletedProcess[str]:
called.append(list(cmd))
if "readVariable" in cmd:
return _sub.CompletedProcess(cmd, 0, "10.0.1.50", "")
return _sub.CompletedProcess(cmd, 0, "", "")
monkeypatch.setattr(tmpl_mod.subprocess, "run", fake_run)
monkeypatch.setattr(tmpl_mod.time, "sleep", lambda _: None)
result = tmpl_mod._poll_guest_ip_deploy("/vmrun", "/vm.vmx", 60.0)
assert result == "10.0.1.50"
assert not any("getGuestIPAddress" in " ".join(c) for c in called)
def test_poll_guest_ip_returns_valid(monkeypatch: pytest.MonkeyPatch) -> None:
import subprocess as _sub
@@ -1492,7 +1543,7 @@ def test_deploy_linux_step5_vmx_content(
lambda cmd, **kw: _sub.CompletedProcess(list(cmd), 0, "Total running VMs: 0\n", ""),
)
result = CliRunner().invoke(
CliRunner().invoke(
cli,
[
"template", "deploy-linux",
@@ -1522,7 +1573,7 @@ def test_deploy_linux_step5_guestinfo_skipped_when_step2_skipped(
lambda cmd, **kw: _sub.CompletedProcess(list(cmd), 0, "Total running VMs: 0\n", ""),
)
result = CliRunner().invoke(
CliRunner().invoke(
cli,
[
"template", "deploy-linux",
@@ -1956,6 +2007,43 @@ def test_prepare_linux_happy_path_with_vmx(
assert "192.168.1.200" in result.output
def test_prepare_linux_zombie_vm_restarts(
prepare_env: dict, monkeypatch: pytest.MonkeyPatch
) -> None:
"""VM process alive but guest powered off → quick probe fails → stop+restart."""
_stub_prepare(monkeypatch, prepare_env)
# First _poll call (quick probe, 30s) returns None; second (full 300s) returns IP.
poll_calls: list[float] = []
def fake_poll(vmrun: str, vmx: str, timeout: float) -> str | None:
poll_calls.append(timeout)
return None if timeout == 30.0 else "192.168.1.200"
monkeypatch.setattr(tmpl_mod, "_poll_guest_ip_deploy", fake_poll)
backend_m = MagicMock()
backend_m.is_running.side_effect = [True, True, False] # already running; post-stop checks
backend_m.list_snapshots.return_value = []
monkeypatch.setattr(tmpl_mod, "WorkstationVmrunBackend", lambda **kw: backend_m)
import subprocess as _sub
monkeypatch.setattr(
tmpl_mod.subprocess, "run",
lambda cmd, **kw: _sub.CompletedProcess(list(cmd), 0, "", ""),
)
result = CliRunner().invoke(
cli,
["template", "prepare-linux", "--vmx", str(prepare_env["vmx"])],
)
assert result.exit_code == 0, result.output
assert "restarting" in result.output
backend_m.stop.assert_called_once()
backend_m.start.assert_called()
assert 30.0 in poll_calls
def test_prepare_linux_happy_path_skip_flags(
prepare_env: dict, monkeypatch: pytest.MonkeyPatch
) -> None: