package kvm import ( "encoding/xml" "strings" "testing" "time" ) func testDomainParams() domainParams { return domainParams{ Name: "proxy-abc123def456ghij", UID: "11111111-2222-3333-4444-555555555555", CreatedAt: time.Date(2026, 9, 4, 12, 0, 0, 0, time.UTC), VCPUs: 2, MemoryMiB: 2048, Pool: "default", Bridge: "br0", DiskVol: "proxy-abc123def456ghij.qcow2", SeedVol: "proxy-abc123def456ghij-seed.iso", } } func TestBuildDomainXML_fieldByField(t *testing.T) { t.Parallel() raw, err := buildDomainXML(testDomainParams()) if err != nil { t.Fatalf("buildDomainXML() error = %v", err) } var d domainXML if err := xml.Unmarshal([]byte(raw), &d); err != nil { t.Fatalf("output is not well-formed XML: %v\n%s", err, raw) } if d.Type != "kvm" || d.Name != "proxy-abc123def456ghij" { t.Errorf("type/name = %s/%s", d.Type, d.Name) } if d.VCPU != 2 || d.Memory.Value != 2048 || d.Memory.Unit != "MiB" { t.Errorf("vcpu/memory = %d/%d %s, want 2/2048 MiB", d.VCPU, d.Memory.Value, d.Memory.Unit) } if d.OS.Type.Value != "hvm" || d.OS.Type.Arch != "x86_64" || d.OS.Type.Machine != "q35" || d.OS.Boot.Dev != "hd" { t.Errorf("os = %+v", d.OS) } if d.Features.ACPI == nil || d.Features.APIC == nil { t.Errorf("features = %+v, want acpi and apic", d.Features) } if d.CPU.Mode != "host-passthrough" { t.Errorf("cpu mode = %q", d.CPU.Mode) } if d.OnPoweroff != "destroy" || d.OnReboot != "restart" || d.OnCrash != "destroy" { t.Errorf("lifecycle = %s/%s/%s", d.OnPoweroff, d.OnReboot, d.OnCrash) } m := d.Metadata.Instance if !m.managed() || m.UID != "11111111-2222-3333-4444-555555555555" || m.CreatedAt != "2026-09-04T12:00:00Z" { t.Errorf("metadata = %+v", m) } if !strings.Contains(raw, `xmlns="`+metadataURI+`"`) { t.Errorf("metadata element is not namespaced; libvirt rejects that:\n%s", raw) } if len(d.Devices.Disks) != 2 { t.Fatalf("disks = %d, want 2", len(d.Devices.Disks)) } disk, seed := d.Devices.Disks[0], d.Devices.Disks[1] if disk.Type != "volume" || disk.Device != "disk" || disk.Driver.Type != "qcow2" || disk.Source.Pool != "default" || disk.Source.Volume != "proxy-abc123def456ghij.qcow2" || disk.Target.Dev != "vda" || disk.Target.Bus != "virtio" || disk.ReadOnly != nil { t.Errorf("overlay disk = %+v", disk) } if seed.Type != "volume" || seed.Device != "cdrom" || seed.Driver.Type != "raw" || seed.Source.Pool != "default" || seed.Source.Volume != "proxy-abc123def456ghij-seed.iso" || seed.Target.Bus != "sata" || seed.ReadOnly == nil { t.Errorf("seed cdrom = %+v", seed) } if len(d.Devices.Interfaces) != 1 { t.Fatalf("interfaces = %d, want 1", len(d.Devices.Interfaces)) } if nic := d.Devices.Interfaces[0]; nic.Type != "bridge" || nic.Source.Bridge != "br0" || nic.Model.Type != "virtio" { t.Errorf("interface = %+v", nic) } if len(d.Devices.Channels) != 1 || d.Devices.Channels[0].Target.Name != guestAgentChannel || d.Devices.Channels[0].Target.Type != "virtio" { t.Errorf("channels = %+v, want one virtio %s channel", d.Devices.Channels, guestAgentChannel) } if len(d.Devices.Serials) != 1 || len(d.Devices.Consoles) != 1 || d.Devices.Consoles[0].Target.Type != "serial" { t.Errorf("serial/console = %+v/%+v", d.Devices.Serials, d.Devices.Consoles) } if d.Devices.RNG.Model != "virtio" || d.Devices.RNG.Backend.Value != "/dev/urandom" { t.Errorf("rng = %+v", d.Devices.RNG) } if strings.Contains(raw, "