from __future__ import annotations import json from dataclasses import dataclass, field from pathlib import Path from typing import Any from pyro_mcp.vm_firecracker import build_launch_plan from pyro_mcp.vm_network import NetworkConfig @dataclass class StubInstance: vm_id: str vcpu_count: int mem_mib: int workdir: Path metadata: dict[str, str] = field(default_factory=dict) network: Any = None def test_build_launch_plan_writes_expected_files(tmp_path: Path) -> None: instance = StubInstance( vm_id="abcdef123456", vcpu_count=2, mem_mib=2048, workdir=tmp_path, metadata={ "kernel_image": "/bundle/profiles/debian-git/vmlinux", "rootfs_image": "/bundle/profiles/debian-git/rootfs.ext4", }, network=NetworkConfig( vm_id="abcdef123456", tap_name="pyroabcdef12", guest_ip="172.29.100.2", gateway_ip="172.29.100.1", subnet_cidr="172.29.100.0/24", mac_address="06:00:ab:cd:ef:12", ), ) plan = build_launch_plan(instance) assert plan.config_path.exists() assert plan.guest_network_path.exists() assert plan.guest_exec_path.exists() rendered = json.loads(plan.config_path.read_text(encoding="utf-8")) assert rendered["machine-config"]["vcpu_count"] == 2 assert rendered["network-interfaces"][0]["host_dev_name"] == "pyroabcdef12" assert "acpi=off" in rendered["boot-source"]["boot_args"] assert "init=/opt/pyro/bin/pyro-init" in rendered["boot-source"]["boot_args"] assert "pyro.guest_ip=172.29.100.2" in rendered["boot-source"]["boot_args"] assert "pyro.gateway_ip=172.29.100.1" in rendered["boot-source"]["boot_args"] guest_exec = json.loads(plan.guest_exec_path.read_text(encoding="utf-8")) assert guest_exec["transport"] == "vsock"