/*
 * This file is part of the libvirt-go-xml project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Copyright (C) 2016 Red Hat, Inc.
 *
 */

package libvirtxml

import (
	"reflect"
	"strings"
	"testing"
)

type PCIAddress struct {
	Domain   uint
	Bus      uint
	Slot     uint
	Function uint
}

type DriveAddress struct {
	Controller uint
	Bus        uint
	Target     uint
	Unit       uint
}

type ISAAddress struct {
	IOBase uint
}

var domainID int = 3

var uhciIndex uint = 0
var uhciAddr = PCIAddress{0, 0, 1, 2}
var nvmeAddr = PCIAddress{0, 1, 3, 0}
var pciIndex uint = 0
var pciTargetChassisNr uint = 7
var pciTargetChassis uint = 23
var pciTargetPort uint = 78
var pciTargetBusNr uint = 2
var pciTargetIndex uint = 3
var pciTargetNUMANode uint = 2
var scsiIndex uint = 0
var scsiQueues uint = 3
var scsiCmdPerLUN uint = 8
var scsiMaxSectors uint = 512

var usbHostBus uint = 14
var usbHostDevice uint = 6

var pciHostDomain uint = 0
var pciHostBus uint = 3
var pciHostSlot uint = 14
var pciHostFunction uint = 5

var diskAddr = PCIAddress{0, 0, 3, 0}
var ifaceAddr = PCIAddress{0, 0, 4, 0}
var videoAddr = PCIAddress{0, 0, 5, 0}
var fsAddr = PCIAddress{0, 0, 6, 0}
var balloonAddr = PCIAddress{0, 0, 7, 0}
var panicAddr = ISAAddress{0x505}
var duplexAddr = PCIAddress{0, 0, 8, 0}
var watchdogAddr = PCIAddress{0, 0, 8, 0}
var rngAddr = PCIAddress{0, 0, 9, 0}
var hostdevSCSI = DriveAddress{0, 0, 3, 0}

var serialPort uint = 0
var parallelPort uint = 0
var tabletBus uint = 0
var tabletPort string = "1.1"

var nicAverage int = 1000
var nicBurst int = 10000

var vcpuId0 uint = 0
var vcpuOrder0 uint = 1
var vcpuId1 uint = 1

var memorydevAddressSlot uint = 0
var memorydevAddressBase uint64 = 4294967296

var rebootTimeout int = 0
var cellID0 uint = 0
var cellID1 uint = 1

var ipv6Prefix uint = 24

var iothreadPriority int = -3
var vcpuPriority int = -5

var vepaManagerID uint = 5
var vepaTypeID uint = 3
var vepaTypeIDVersion uint = 12
var vepaInstanceID = "c7bb5ab2-d42f-4690-89d6-f590eb199d0f"

var vntagProfileID = "c7bb5ab2-d42f-4690-89d6-f590eb199d0f"

var ovsProfileID = "c7bb5ab2-d42f-4690-89d6-f590eb199d0f"
var ovsInterfaceID = "73728ac4-53d9-44de-8438-8d8f90beca00"

var midoInterfaceID = "73728ac4-53d9-44de-8438-8d8f90beca00"

var nvramReg uint64 = 0x4000

var smartcardController uint = 0
var smartcardSlot uint = 7

var redirBus uint = 0
var redirPort string = "3"

var redirfilterClass uint = 0x08
var redirfilterProduct uint = 0x2007
var redirfilterVendor uint = 0x15e1

var domainTestData = []struct {
	Object   Document
	Expected []string
}{
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			ID:   &domainID,
		},
		Expected: []string{
			`<domain type="kvm" id="3">`,
			`  <name>test</name>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type:        "kvm",
			Name:        "test",
			Title:       "Test",
			Description: "A test guest config",
			Metadata: &DomainMetadata{
				XML: "<myvalue xmlns='http://myapp.com/schemeas/my/1.0'><widget name='foo'/></myvalue>" +
					"<myothervalue xmlns='http://myotherapp.com/schemeas/my/1.0'><gizmo name='foo'/></myothervalue>",
			},
			Devices: &DomainDeviceList{
				Disks: []DomainDisk{
					DomainDisk{
						Device: "cdrom",
						Driver: &DomainDiskDriver{
							Name: "qemu",
							Type: "qcow2",
						},
						Source: &DomainDiskSource{
							File: &DomainDiskSourceFile{
								File: "/var/lib/libvirt/images/demo.qcow2",
							},
						},
						Target: &DomainDiskTarget{
							Dev: "vda",
							Bus: "virtio",
						},
						Serial: "fishfood",
						Boot: &DomainDeviceBoot{
							Order: 1,
						},
					},
					DomainDisk{
						Device: "disk",
						Driver: &DomainDiskDriver{
							Name: "qemu",
							Type: "raw",
						},
						Source: &DomainDiskSource{
							Block: &DomainDiskSourceBlock{
								Dev: "/dev/sda1",
							},
						},
						Target: &DomainDiskTarget{
							Dev: "vdb",
							Bus: "virtio",
						},
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &diskAddr.Domain,
								Bus:      &diskAddr.Bus,
								Slot:     &diskAddr.Slot,
								Function: &diskAddr.Function,
							},
						},
					},
					DomainDisk{
						Device: "disk",
						Auth: &DomainDiskAuth{
							Username: "fred",
							Secret: &DomainDiskSecret{
								Type: "ceph",
								UUID: "e49f09c9-119e-43fd-b5a9-000d41e65493",
							},
						},
						Source: &DomainDiskSource{
							Network: &DomainDiskSourceNetwork{
								Protocol: "rbd",
								Name:     "somepool/somevol",
								Hosts: []DomainDiskSourceHost{
									DomainDiskSourceHost{
										Transport: "tcp",
										Name:      "rbd1.example.com",
										Port:      "3000",
									},
									DomainDiskSourceHost{
										Transport: "tcp",
										Name:      "rbd2.example.com",
										Port:      "3000",
									},
								},
							},
						},
						Target: &DomainDiskTarget{
							Dev: "vdc",
							Bus: "virtio",
						},
					},
					DomainDisk{
						Device: "disk",
						Source: &DomainDiskSource{
							Network: &DomainDiskSourceNetwork{
								Protocol: "nbd",
								Hosts: []DomainDiskSourceHost{
									DomainDiskSourceHost{
										Transport: "unix",
										Socket:    "/var/run/nbd.sock",
									},
								},
							},
						},
						Target: &DomainDiskTarget{
							Dev: "vdd",
							Bus: "virtio",
						},
						Shareable: &DomainDiskShareable{},
					},
					DomainDisk{
						Device: "cdrom",
						Driver: &DomainDiskDriver{
							Cache:       "none",
							IO:          "native",
							ErrorPolicy: "stop",
						},
						Source: &DomainDiskSource{
							Volume: &DomainDiskSourceVolume{
								Pool:   "default",
								Volume: "myvolume",
							},
						},
						Target: &DomainDiskTarget{
							Dev: "vde",
							Bus: "virtio",
						},
						ReadOnly: &DomainDiskReadOnly{},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <title>Test</title>`,
			`  <description>A test guest config</description>`,
			`  <metadata>` +
				`<myvalue xmlns='http://myapp.com/schemeas/my/1.0'><widget name='foo'/></myvalue>` +
				`<myothervalue xmlns='http://myotherapp.com/schemeas/my/1.0'><gizmo name='foo'/></myothervalue>` +
				`</metadata>`,
			`  <devices>`,
			`    <disk type="file" device="cdrom">`,
			`      <driver name="qemu" type="qcow2"></driver>`,
			`      <source file="/var/lib/libvirt/images/demo.qcow2"></source>`,
			`      <target dev="vda" bus="virtio"></target>`,
			`      <serial>fishfood</serial>`,
			`      <boot order="1"></boot>`,
			`    </disk>`,
			`    <disk type="block" device="disk">`,
			`      <driver name="qemu" type="raw"></driver>`,
			`      <source dev="/dev/sda1"></source>`,
			`      <target dev="vdb" bus="virtio"></target>`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x0"></address>`,
			`    </disk>`,
			`    <disk type="network" device="disk">`,
			`      <auth username="fred">`,
			`        <secret type="ceph" uuid="e49f09c9-119e-43fd-b5a9-000d41e65493"></secret>`,
			`      </auth>`,
			`      <source protocol="rbd" name="somepool/somevol">`,
			`        <host transport="tcp" name="rbd1.example.com" port="3000"></host>`,
			`        <host transport="tcp" name="rbd2.example.com" port="3000"></host>`,
			`      </source>`,
			`      <target dev="vdc" bus="virtio"></target>`,
			`    </disk>`,
			`    <disk type="network" device="disk">`,
			`      <source protocol="nbd">`,
			`        <host transport="unix" socket="/var/run/nbd.sock"></host>`,
			`      </source>`,
			`      <target dev="vdd" bus="virtio"></target>`,
			`      <shareable></shareable>`,
			`    </disk>`,
			`    <disk type="volume" device="cdrom">`,
			`      <driver cache="none" error_policy="stop" io="native"></driver>`,
			`      <source pool="default" volume="myvolume"></source>`,
			`      <target dev="vde" bus="virtio"></target>`,
			`      <readonly></readonly>`,
			`    </disk>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Inputs: []DomainInput{
					DomainInput{
						Type: "tablet",
						Bus:  "usb",
						Address: &DomainAddress{
							USB: &DomainAddressUSB{
								Bus:  &tabletBus,
								Port: tabletPort,
							},
						},
					},
					DomainInput{
						Type: "keyboard",
						Bus:  "ps2",
					},
				},
				Videos: []DomainVideo{
					DomainVideo{
						Model: DomainVideoModel{
							Type:   "cirrus",
							Heads:  1,
							Ram:    4096,
							VRam:   8192,
							VGAMem: 256,
						},
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &videoAddr.Domain,
								Bus:      &videoAddr.Bus,
								Slot:     &videoAddr.Slot,
								Function: &videoAddr.Function,
							},
						},
					},
				},
				TPMs: []DomainTPM{
					DomainTPM{
						Model: "tpm-tis",
						Backend: &DomainTPMBackend{
							Passthrough: &DomainTPMBackendPassthrough{
								Device: &DomainTPMBackendDevice{
									Path: "/dev/tpm0",
								},
							},
						},
					},
				},
				Graphics: []DomainGraphic{
					DomainGraphic{
						VNC: &DomainGraphicVNC{},
					},
				},
				MemBalloon: &DomainMemBalloon{
					Model: "virtio",
					Address: &DomainAddress{
						PCI: &DomainAddressPCI{
							Domain:   &balloonAddr.Domain,
							Bus:      &balloonAddr.Bus,
							Slot:     &balloonAddr.Slot,
							Function: &balloonAddr.Function,
						},
					},
				},
				Panics: []DomainPanic{
					DomainPanic{
						Model: "hyperv",
					},
					DomainPanic{
						Model: "isa",
						Address: &DomainAddress{
							ISA: &DomainAddressISA{
								IOBase: &panicAddr.IOBase,
							},
						},
					},
				},
				Consoles: []DomainConsole{
					DomainConsole{
						Source: &DomainChardevSource{
							Pty: &DomainChardevSourcePty{},
						},
						Target: &DomainConsoleTarget{
							Type: "virtio",
							Port: &serialPort,
						},
					},
				},
				Serials: []DomainSerial{
					DomainSerial{
						Source: &DomainChardevSource{
							Pty: &DomainChardevSourcePty{},
						},
						Target: &DomainSerialTarget{
							Type: "isa",
							Port: &serialPort,
						},
					},
					DomainSerial{
						Source: &DomainChardevSource{
							File: &DomainChardevSourceFile{
								Path:   "/tmp/serial.log",
								Append: "off",
							},
						},
						Target: &DomainSerialTarget{
							Port: &serialPort,
						},
					},
					DomainSerial{
						Source: &DomainChardevSource{
							TCP: &DomainChardevSourceTCP{
								Mode:    "bind",
								Host:    "127.0.0.1",
								Service: "1234",
								TLS:     "yes",
							},
						},
						Protocol: &DomainChardevProtocol{
							Type: "telnet",
						},
						Target: &DomainSerialTarget{
							Port: &serialPort,
						},
					},
				},
				Channels: []DomainChannel{
					DomainChannel{
						Source: &DomainChardevSource{
							Pty: &DomainChardevSourcePty{},
						},
						Target: &DomainChannelTarget{
							VirtIO: &DomainChannelTargetVirtIO{
								Name:  "org.redhat.spice",
								State: "connected",
							},
						},
					},
				},
				Sounds: []DomainSound{
					DomainSound{
						Model: "ich6",
						Codec: []DomainSoundCodec{
							DomainSoundCodec{
								Type: "duplex",
							},
						},
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &duplexAddr.Domain,
								Bus:      &duplexAddr.Bus,
								Slot:     &duplexAddr.Slot,
								Function: &duplexAddr.Function,
							},
						},
					},
				},
				RedirDevs: []DomainRedirDev{
					DomainRedirDev{
						Bus: "usb",
						Source: &DomainChardevSource{
							SpiceVMC: &DomainChardevSourceSpiceVMC{},
						},
						Address: &DomainAddress{
							USB: &DomainAddressUSB{
								Bus:  &redirBus,
								Port: redirPort,
							},
						},
					},
				},
				RedirFilters: []DomainRedirFilter{
					DomainRedirFilter{
						USB: []DomainRedirFilterUSB{
							DomainRedirFilterUSB{
								Class:   &redirfilterClass,
								Product: &redirfilterProduct,
								Vendor:  &redirfilterVendor,
								Version: "1.10",
								Allow:   "yes",
							},
							DomainRedirFilterUSB{
								Version: "1.10",
								Allow:   "no",
							},
							DomainRedirFilterUSB{
								Allow: "yes",
							},
						},
					},
				},
				RNGs: []DomainRNG{
					DomainRNG{
						Model: "virtio",
						Rate: &DomainRNGRate{
							Period: 2000,
							Bytes:  1234,
						},
						Backend: &DomainRNGBackend{
							EGD: &DomainRNGBackendEGD{
								Source: &DomainChardevSource{
									Dev: &DomainChardevSourceDev{
										Path: "/dev/ttyS0",
									},
								},
								Protocol: &DomainChardevProtocol{
									Type: "raw",
								},
							},
						},
					},
				},
				Memorydevs: []DomainMemorydev{
					DomainMemorydev{
						Model:  "dimm",
						Access: "private",
						Target: &DomainMemorydevTarget{
							Size: &DomainMemorydevTargetSize{
								Value: 1,
								Unit:  "GiB",
							},
							Node: &DomainMemorydevTargetNode{
								Value: 0,
							},
						},
						Address: &DomainAddress{
							DIMM: &DomainAddressDIMM{
								Slot: &memorydevAddressSlot,
								Base: &memorydevAddressBase,
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <serial type="pty">`,
			`      <target type="isa" port="0"></target>`,
			`    </serial>`,
			`    <serial type="file">`,
			`      <source path="/tmp/serial.log" append="off"></source>`,
			`      <target port="0"></target>`,
			`    </serial>`,
			`    <serial type="tcp">`,
			`      <source mode="bind" host="127.0.0.1" service="1234" tls="yes"></source>`,
			`      <protocol type="telnet"></protocol>`,
			`      <target port="0"></target>`,
			`    </serial>`,
			`    <console type="pty">`,
			`      <target type="virtio" port="0"></target>`,
			`    </console>`,
			`    <channel type="pty">`,
			`      <target type="virtio" name="org.redhat.spice" state="connected"></target>`,
			`    </channel>`,
			`    <input type="tablet" bus="usb">`,
			`      <address type="usb" bus="0" port="1.1"></address>`,
			`    </input>`,
			`    <input type="keyboard" bus="ps2"></input>`,
			`    <tpm model="tpm-tis">`,
			`      <backend type="passthrough">`,
			`        <device path="/dev/tpm0"></device>`,
			`      </backend>`,
			`    </tpm>`,
			`    <graphics type="vnc"></graphics>`,
			`    <sound model="ich6">`,
			`      <codec type="duplex"></codec>`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x08" function="0x0"></address>`,
			`    </sound>`,
			`    <video>`,
			`      <model type="cirrus" heads="1" ram="4096" vram="8192" vgamem="256"></model>`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x05" function="0x0"></address>`,
			`    </video>`,
			`    <redirdev type="spicevmc" bus="usb">`,
			`      <address type="usb" bus="0" port="3"></address>`,
			`    </redirdev>`,
			`    <redirfilter>`,
			`      <usbdev class="0x08" vendor="0x15e1" product="0x2007" version="1.10" allow="yes"></usbdev>`,
			`      <usbdev version="1.10" allow="no"></usbdev>`,
			`      <usbdev allow="yes"></usbdev>`,
			`    </redirfilter>`,
			`    <memballoon model="virtio">`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x07" function="0x0"></address>`,
			`    </memballoon>`,
			`    <rng model="virtio">`,
			`      <rate bytes="1234" period="2000"></rate>`,
			`      <backend model="egd" type="dev">`,
			`        <source path="/dev/ttyS0"></source>`,
			`        <protocol type="raw"></protocol>`,
			`      </backend>`,
			`    </rng>`,
			`    <panic model="hyperv"></panic>`,
			`    <panic model="isa">`,
			`      <address type="isa" iobase="0x505"></address>`,
			`    </panic>`,
			`    <memory model="dimm" access="private">`,
			`      <target>`,
			`        <size unit="GiB">1</size>`,
			`        <node>0</node>`,
			`      </target>`,
			`      <address type="dimm" slot="0" base="0x100000000"></address>`,
			`    </memory>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Memory: &DomainMemory{
				Unit:     "KiB",
				Value:    8192,
				DumpCore: "yes",
			},
			CurrentMemory: &DomainCurrentMemory{
				Unit:  "KiB",
				Value: 4096,
			},
			MaximumMemory: &DomainMaxMemory{
				Unit:  "KiB",
				Value: 16384,
				Slots: 2,
			},
			MemoryBacking: &DomainMemoryBacking{
				MemoryHugePages: &DomainMemoryHugepages{
					Hugepages: []DomainMemoryHugepage{
						{
							Size:    1,
							Unit:    "G",
							Nodeset: "0-3,5",
						},
						{
							Size:    2,
							Unit:    "M",
							Nodeset: "4",
						},
					},
				},
				MemoryNosharepages: &DomainMemoryNosharepages{},
				MemoryLocked:       &DomainMemoryLocked{},
				MemorySource: &DomainMemorySource{
					Type: "file",
				},
				MemoryAccess: &DomainMemoryAccess{
					Mode: "shared",
				},
				MemoryAllocation: &DomainMemoryAllocation{
					Mode: "immediate",
				},
			},
			OS: &DomainOS{
				Type: &DomainOSType{
					Arch:    "x86_64",
					Machine: "pc",
					Type:    "hvm",
				},
				BootDevices: []DomainBootDevice{
					DomainBootDevice{
						Dev: "hd",
					},
				},
				Loader: &DomainLoader{
					Readonly: "yes",
					Secure:   "no",
					Type:     "rom",
					Path:     "/loader",
				},
				DTB: "/some/path",
				ACPI: &DomainACPI{
					Tables: []DomainACPITable{
						DomainACPITable{
							Type: "slic",
							Path: "/some/data",
						},
					},
				},
				SMBios: &DomainSMBios{
					Mode: "sysinfo",
				},
				BIOS: &DomainBIOS{
					UseSerial:     "yes",
					RebootTimeout: &rebootTimeout,
				},
				Init: "/bin/systemd",
				InitArgs: []string{
					"--unit",
					"emergency.service",
				},
				InitEnv: []DomainOSInitEnv{
					DomainOSInitEnv{
						Name:  "HOME",
						Value: "/home/fred",
					},
					DomainOSInitEnv{
						Name:  "USER",
						Value: "fred",
					},
				},
				InitUser:  "fred",
				InitGroup: "fred",
				InitDir:   "/home/fred",
			},
			SysInfo: []DomainSysInfo{
				DomainSysInfo{
					SMBIOS: &DomainSysInfoSMBIOS{
						BIOS: &DomainSysInfoBIOS{
							Entry: []DomainSysInfoEntry{
								DomainSysInfoEntry{
									Name:  "vendor",
									Value: "vendor",
								},
							},
						},
						System: &DomainSysInfoSystem{
							Entry: []DomainSysInfoEntry{
								DomainSysInfoEntry{
									Name:  "manufacturer",
									Value: "manufacturer",
								},
								DomainSysInfoEntry{
									Name:  "product",
									Value: "product",
								},
								DomainSysInfoEntry{
									Name:  "version",
									Value: "version",
								},
							},
						},
						BaseBoard: []DomainSysInfoBaseBoard{
							DomainSysInfoBaseBoard{
								Entry: []DomainSysInfoEntry{
									DomainSysInfoEntry{
										Name:  "manufacturer",
										Value: "manufacturer",
									},
									DomainSysInfoEntry{
										Name:  "product",
										Value: "product",
									},
									DomainSysInfoEntry{
										Name:  "version",
										Value: "version",
									},
									DomainSysInfoEntry{
										Name:  "serial",
										Value: "serial",
									},
								},
							},
						},
					},
				},
				DomainSysInfo{
					FWCfg: &DomainSysInfoFWCfg{
						Entry: []DomainSysInfoEntry{
							DomainSysInfoEntry{
								Name:  "vendor",
								Value: "vendor",
							},
							DomainSysInfoEntry{
								Name: "installer",
								File: "/some/path.cfg",
							},
						},
					},
				},
			},
			Clock: &DomainClock{
				Offset:     "variable",
				Basis:      "utc",
				Adjustment: "28794",
				TimeZone:   "Europe/Paris",
				Timer: []DomainTimer{
					DomainTimer{
						Name:       "rtc",
						Track:      "boot",
						TickPolicy: "catchup",
						CatchUp: &DomainTimerCatchUp{
							Threshold: 123,
							Slew:      120,
							Limit:     10000,
						},
						Frequency: 120,
						Mode:      "auto",
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <maxMemory unit="KiB" slots="2">16384</maxMemory>`,
			`  <memory unit="KiB" dumpCore="yes">8192</memory>`,
			`  <currentMemory unit="KiB">4096</currentMemory>`,
			`  <memoryBacking>`,
			`    <hugepages>`,
			`      <page size="1" unit="G" nodeset="0-3,5"></page>`,
			`      <page size="2" unit="M" nodeset="4"></page>`,
			`    </hugepages>`,
			`    <nosharepages></nosharepages>`,
			`    <locked></locked>`,
			`    <source type="file"></source>`,
			`    <access mode="shared"></access>`,
			`    <allocation mode="immediate"></allocation>`,
			`  </memoryBacking>`,
			`  <sysinfo type="smbios">`,
			`    <bios>`,
			`      <entry name="vendor">vendor</entry>`,
			`    </bios>`,
			`    <system>`,
			`      <entry name="manufacturer">manufacturer</entry>`,
			`      <entry name="product">product</entry>`,
			`      <entry name="version">version</entry>`,
			`    </system>`,
			`    <baseBoard>`,
			`      <entry name="manufacturer">manufacturer</entry>`,
			`      <entry name="product">product</entry>`,
			`      <entry name="version">version</entry>`,
			`      <entry name="serial">serial</entry>`,
			`    </baseBoard>`,
			`  </sysinfo>`,
			`  <sysinfo type="fwcfg">`,
			`    <entry name="vendor">vendor</entry>`,
			`    <entry name="installer" file="/some/path.cfg"></entry>`,
			`  </sysinfo>`,
			`  <os>`,
			`    <type arch="x86_64" machine="pc">hvm</type>`,
			`    <init>/bin/systemd</init>`,
			`    <initarg>--unit</initarg>`,
			`    <initarg>emergency.service</initarg>`,
			`    <initenv name="HOME">/home/fred</initenv>`,
			`    <initenv name="USER">fred</initenv>`,
			`    <initdir>/home/fred</initdir>`,
			`    <inituser>fred</inituser>`,
			`    <initgroup>fred</initgroup>`,
			`    <loader readonly="yes" secure="no" type="rom">/loader</loader>`,
			`    <dtb>/some/path</dtb>`,
			`    <acpi>`,
			`      <table type="slic">/some/data</table>`,
			`    </acpi>`,
			`    <boot dev="hd"></boot>`,
			`    <bios useserial="yes" rebootTimeout="0"></bios>`,
			`    <smbios mode="sysinfo"></smbios>`,
			`  </os>`,
			`  <clock offset="variable" basis="utc" adjustment="28794" timezone="Europe/Paris">`,
			`    <timer name="rtc" track="boot" tickpolicy="catchup" frequency="120" mode="auto">`,
			`      <catchup threshold="123" slew="120" limit="10000"></catchup>`,
			`    </timer>`,
			`  </clock>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Clock: &DomainClock{
				Offset:     "variable",
				Basis:      "utc",
				Adjustment: "reset",
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <clock offset="variable" basis="utc" adjustment="reset"></clock>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			OS: &DomainOS{
				NVRam: &DomainNVRam{
					Template: "/t.fd",
					NVRam:    "/vars.fd",
				},
				BootMenu: &DomainBootMenu{
					Enable:  "yes",
					Timeout: "3000",
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <os>`,
			`    <nvram template="/t.fd">/vars.fd</nvram>`,
			`    <bootmenu enable="yes" timeout="3000"></bootmenu>`,
			`  </os>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			BlockIOTune: &DomainBlockIOTune{
				Weight: 900,
				Device: []DomainBlockIOTuneDevice{
					DomainBlockIOTuneDevice{
						Path:          "/dev/sda",
						Weight:        500,
						ReadIopsSec:   300,
						WriteIopsSec:  200,
						ReadBytesSec:  3000,
						WriteBytesSec: 2000,
					},
					DomainBlockIOTuneDevice{
						Path:          "/dev/sdb",
						Weight:        600,
						ReadIopsSec:   100,
						WriteIopsSec:  40,
						ReadBytesSec:  1000,
						WriteBytesSec: 400,
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <blkiotune>`,
			`    <weight>900</weight>`,
			`    <device>`,
			`      <path>/dev/sda</path>`,
			`      <weight>500</weight>`,
			`      <read_iops_sec>300</read_iops_sec>`,
			`      <write_iops_sec>200</write_iops_sec>`,
			`      <read_bytes_sec>3000</read_bytes_sec>`,
			`      <write_bytes_sec>2000</write_bytes_sec>`,
			`    </device>`,
			`    <device>`,
			`      <path>/dev/sdb</path>`,
			`      <weight>600</weight>`,
			`      <read_iops_sec>100</read_iops_sec>`,
			`      <write_iops_sec>40</write_iops_sec>`,
			`      <read_bytes_sec>1000</read_bytes_sec>`,
			`      <write_bytes_sec>400</write_bytes_sec>`,
			`    </device>`,
			`  </blkiotune>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			MemoryTune: &DomainMemoryTune{
				HardLimit: &DomainMemoryTuneLimit{
					Value: 1024,
					Unit:  "MiB",
				},
				SoftLimit: &DomainMemoryTuneLimit{
					Value: 1024,
				},
				MinGuarantee: &DomainMemoryTuneLimit{
					Value: 1024,
				},
				SwapHardLimit: &DomainMemoryTuneLimit{
					Value: 1024,
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <memtune>`,
			`    <hard_limit unit="MiB">1024</hard_limit>`,
			`    <soft_limit>1024</soft_limit>`,
			`    <min_guarantee>1024</min_guarantee>`,
			`    <swap_hard_limit>1024</swap_hard_limit>`,
			`  </memtune>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			PM: &DomainPM{
				SuspendToMem: &DomainPMPolicy{
					Enabled: "no",
				},
				SuspendToDisk: &DomainPMPolicy{
					Enabled: "yes",
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <pm>`,
			`    <suspend-to-mem enabled="no"></suspend-to-mem>`,
			`    <suspend-to-disk enabled="yes"></suspend-to-disk>`,
			`  </pm>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			SecLabel: []DomainSecLabel{
				DomainSecLabel{
					Type:       "dynamic",
					Model:      "selinux",
					Relabel:    "yes",
					Label:      "system_u:system_r:svirt_t:s0:c143,c762",
					ImageLabel: "system_u:object_r:svirt_image_t:s0:c143,c762",
					BaseLabel:  "system_u:system_r:svirt_t:s0",
				},
				DomainSecLabel{
					Type:    "dynamic",
					Model:   "dac",
					Relabel: "no",
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <seclabel type="dynamic" model="selinux" relabel="yes">`,
			`    <label>system_u:system_r:svirt_t:s0:c143,c762</label>`,
			`    <imagelabel>system_u:object_r:svirt_image_t:s0:c143,c762</imagelabel>`,
			`    <baselabel>system_u:system_r:svirt_t:s0</baselabel>`,
			`  </seclabel>`,
			`  <seclabel type="dynamic" model="dac" relabel="no"></seclabel>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			OS: &DomainOS{
				Kernel:  "/vmlinuz",
				Initrd:  "/initrd",
				Cmdline: "arg",
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <os>`,
			`    <kernel>/vmlinuz</kernel>`,
			`    <initrd>/initrd</initrd>`,
			`    <cmdline>arg</cmdline>`,
			`  </os>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Resource: &DomainResource{
				Partition: "/machines/production",
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <resource>`,
			`    <partition>/machines/production</partition>`,
			`  </resource>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			VCPU: &DomainVCPU{
				Placement: "static",
				CPUSet:    "1-4,^3,6",
				Current:   1,
				Value:     2,
			},
			VCPUs: &DomainVCPUs{
				VCPU: []DomainVCPUsVCPU{
					DomainVCPUsVCPU{
						Id:           &vcpuId0,
						Enabled:      "yes",
						Hotpluggable: "no",
						Order:        &vcpuOrder0,
					},
					DomainVCPUsVCPU{
						Id:           &vcpuId1,
						Enabled:      "no",
						Hotpluggable: "yes",
						Order:        nil,
					},
				},
			},
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "00:11:22:33:44:55",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							Network: &DomainInterfaceSourceNetwork{
								Network: "default",
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <vcpu placement="static" cpuset="1-4,^3,6" current="1">2</vcpu>`,
			`  <vcpus>`,
			`    <vcpu id="0" enabled="yes" hotpluggable="no" order="1"></vcpu>`,
			`    <vcpu id="1" enabled="no" hotpluggable="yes"></vcpu>`,
			`  </vcpus>`,
			`  <devices>`,
			`    <interface type="network">`,
			`      <mac address="00:11:22:33:44:55"></mac>`,
			`      <source network="default"></source>`,
			`      <model type="virtio"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			CPU: &DomainCPU{
				Match: "exact",
				Check: "none",
				Model: &DomainCPUModel{
					Fallback: "allow",
					Value:    "core2duo",
					VendorID: "LibvirtQEMU",
				},
				Vendor: "Intel",
				Topology: &DomainCPUTopology{
					Sockets: 1,
					Cores:   2,
					Threads: 1,
				},
				Features: []DomainCPUFeature{
					DomainCPUFeature{Policy: "disable", Name: "lahf_lm"},
				},
				Cache: &DomainCPUCache{
					Level: 1,
					Mode:  "emulate",
				},
				Numa: &DomainNuma{
					[]DomainCell{
						{
							ID:        &cellID0,
							CPUs:      "0-1",
							Memory:    512000,
							Unit:      "KiB",
							MemAccess: "private",
							Distances: &DomainCellDistances{
								Siblings: []DomainCellSibling{
									DomainCellSibling{
										ID:    1,
										Value: 20,
									},
								},
							},
						},
						{
							ID:        &cellID1,
							CPUs:      "2-3",
							Memory:    512000,
							Unit:      "KiB",
							MemAccess: "private",
							Distances: &DomainCellDistances{
								Siblings: []DomainCellSibling{
									DomainCellSibling{
										ID:    0,
										Value: 20,
									},
								},
							},
						},
					},
					nil,
				},
			},
			Devices: &DomainDeviceList{
				Emulator: "/bin/qemu-kvm",
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <cpu match="exact" check="none">`,
			`    <model fallback="allow" vendor_id="LibvirtQEMU">core2duo</model>`,
			`    <vendor>Intel</vendor>`,
			`    <topology sockets="1" cores="2" threads="1"></topology>`,
			`    <cache level="1" mode="emulate"></cache>`,
			`    <feature policy="disable" name="lahf_lm"></feature>`,
			`    <numa>`,
			`      <cell id="0" cpus="0-1" memory="512000" unit="KiB" memAccess="private">`,
			`        <distances>`,
			`          <sibling id="1" value="20"></sibling>`,
			`        </distances>`,
			`      </cell>`,
			`      <cell id="1" cpus="2-3" memory="512000" unit="KiB" memAccess="private">`,
			`        <distances>`,
			`          <sibling id="0" value="20"></sibling>`,
			`        </distances>`,
			`      </cell>`,
			`    </numa>`,
			`  </cpu>`,
			`  <devices>`,
			`    <emulator>/bin/qemu-kvm</emulator>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "06:39:b4:00:00:46",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							Bridge: &DomainInterfaceSourceBridge{
								Bridge: "private",
							},
						},
						Target: &DomainInterfaceTarget{
							Dev: "vnet3",
						},
						Alias: &DomainAlias{
							Name: "net1",
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="bridge">`,
			`      <mac address="06:39:b4:00:00:46"></mac>`,
			`      <source bridge="private"></source>`,
			`      <target dev="vnet3"></target>`,
			`      <model type="virtio"></model>`,
			`      <alias name="net1"></alias>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "vmware",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "06:39:b4:00:00:46",
						},
						Model: &DomainInterfaceModel{
							Type: "e1000",
						},
						Source: &DomainInterfaceSource{
							Bridge: &DomainInterfaceSourceBridge{
								Bridge: "",
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="vmware">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="bridge">`,
			`      <mac address="06:39:b4:00:00:46"></mac>`,
			`      <source bridge=""></source>`,
			`      <model type="e1000"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "e1000",
						},
						Source: &DomainInterfaceSource{
							Network: &DomainInterfaceSourceNetwork{
								Network: "default",
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="network">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source network="default"></source>`,
			`      <model type="e1000"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							UDP: &DomainInterfaceSourceUDP{
								Address: "127.0.0.1",
								Port:    1234,
								Local: &DomainInterfaceSourceLocal{
									Address: "127.0.0.1",
									Port:    1235,
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="udp">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source address="127.0.0.1" port="1234">`,
			`        <local address="127.0.0.1" port="1235"></local>`,
			`      </source>`,
			`      <model type="virtio"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						Source: &DomainInterfaceSource{
							Direct: &DomainInterfaceSourceDirect{
								Dev:  "eth0",
								Mode: "bridge",
							},
						},
						VirtualPort: &DomainInterfaceVirtualPort{
							Params: &DomainInterfaceVirtualPortParams{
								VEPA8021QBG: &DomainInterfaceVirtualPortParamsVEPA8021QBG{
									ManagerID:     &vepaManagerID,
									TypeID:        &vepaTypeID,
									TypeIDVersion: &vepaTypeIDVersion,
									InstanceID:    vepaInstanceID,
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="direct">`,
			`      <source dev="eth0" mode="bridge"></source>`,
			`      <virtualport type="802.1Qbg">`,
			`        <parameters managerid="5" typeid="3" typeidversion="12" instanceid="c7bb5ab2-d42f-4690-89d6-f590eb199d0f"></parameters>`,
			`      </virtualport>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						Source: &DomainInterfaceSource{
							Direct: &DomainInterfaceSourceDirect{
								Dev:  "eth0",
								Mode: "bridge",
							},
						},
						VirtualPort: &DomainInterfaceVirtualPort{
							Params: &DomainInterfaceVirtualPortParams{
								VNTag8011QBH: &DomainInterfaceVirtualPortParamsVNTag8021QBH{
									ProfileID: vntagProfileID,
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="direct">`,
			`      <source dev="eth0" mode="bridge"></source>`,
			`      <virtualport type="802.1Qbh">`,
			`        <parameters profileid="c7bb5ab2-d42f-4690-89d6-f590eb199d0f"></parameters>`,
			`      </virtualport>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						Source: &DomainInterfaceSource{
							Direct: &DomainInterfaceSourceDirect{
								Dev:  "eth0",
								Mode: "bridge",
							},
						},
						VirtualPort: &DomainInterfaceVirtualPort{
							Params: &DomainInterfaceVirtualPortParams{
								OpenVSwitch: &DomainInterfaceVirtualPortParamsOpenVSwitch{
									ProfileID:   ovsProfileID,
									InterfaceID: ovsInterfaceID,
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="direct">`,
			`      <source dev="eth0" mode="bridge"></source>`,
			`      <virtualport type="openvswitch">`,
			`        <parameters interfaceid="73728ac4-53d9-44de-8438-8d8f90beca00" profileid="c7bb5ab2-d42f-4690-89d6-f590eb199d0f"></parameters>`,
			`      </virtualport>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						Source: &DomainInterfaceSource{
							Direct: &DomainInterfaceSourceDirect{
								Dev:  "eth0",
								Mode: "bridge",
							},
						},
						VirtualPort: &DomainInterfaceVirtualPort{
							Params: &DomainInterfaceVirtualPortParams{
								MidoNet: &DomainInterfaceVirtualPortParamsMidoNet{
									InterfaceID: midoInterfaceID,
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="direct">`,
			`      <source dev="eth0" mode="bridge"></source>`,
			`      <virtualport type="midonet">`,
			`        <parameters interfaceid="73728ac4-53d9-44de-8438-8d8f90beca00"></parameters>`,
			`      </virtualport>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							User: &DomainInterfaceSourceUser{},
						},
						Link: &DomainInterfaceLink{
							State: "up",
						},
						Boot: &DomainDeviceBoot{
							Order: 1,
						},
						Driver: &DomainInterfaceDriver{
							Name:   "vhost",
							Queues: 5,
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="user">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <boot order="1"></boot>`,
			`      <model type="virtio"></model>`,
			`      <driver name="vhost" queues="5"></driver>`,
			`      <link state="up"></link>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							Server: &DomainInterfaceSourceServer{
								Address: "127.0.0.1",
								Port:    1234,
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="server">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source address="127.0.0.1" port="1234"></source>`,
			`      <model type="virtio"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							Ethernet: &DomainInterfaceSourceEthernet{},
						},
						Script: &DomainInterfaceScript{
							Path: "/etc/qemu-ifup",
						},
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &ifaceAddr.Domain,
								Bus:      &ifaceAddr.Bus,
								Slot:     &ifaceAddr.Slot,
								Function: &ifaceAddr.Function,
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="ethernet">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <script path="/etc/qemu-ifup"></script>`,
			`      <model type="virtio"></model>`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x04" function="0x0"></address>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							VHostUser: &DomainChardevSource{
								UNIX: &DomainChardevSourceUNIX{
									Path: "/tmp/vhost0.sock",
									Mode: "server",
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="vhostuser">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source type="unix" mode="server" path="/tmp/vhost0.sock"></source>`,
			`      <model type="virtio"></model>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Model: &DomainInterfaceModel{
							Type: "virtio",
						},
						Source: &DomainInterfaceSource{
							VHostUser: &DomainChardevSource{
								UNIX: &DomainChardevSourceUNIX{
									Path: "/tmp/vhost0.sock",
									Mode: "server",
								},
							},
						},
						Bandwidth: &DomainInterfaceBandwidth{
							Inbound: &DomainInterfaceBandwidthParams{
								Average: &nicAverage,
								Burst:   &nicBurst,
							},
							Outbound: &DomainInterfaceBandwidthParams{
								Average: new(int),
								Burst:   new(int),
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="vhostuser">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source type="unix" mode="server" path="/tmp/vhost0.sock"></source>`,
			`      <model type="virtio"></model>`,
			`      <bandwidth>`,
			`        <inbound average="1000" burst="10000"></inbound>`,
			`        <outbound average="0" burst="0"></outbound>`,
			`      </bandwidth>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Interfaces: []DomainInterface{
					DomainInterface{
						MAC: &DomainInterfaceMAC{
							Address: "52:54:00:39:97:ac",
						},
						Source: &DomainInterfaceSource{
							Hostdev: &DomainInterfaceSourceHostdev{
								PCI: &DomainHostdevSubsysPCISource{
									Address: &DomainAddressPCI{
										Domain:   &pciHostDomain,
										Bus:      &pciHostBus,
										Slot:     &pciHostSlot,
										Function: &pciHostFunction,
									},
								},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <interface type="hostdev">`,
			`      <mac address="52:54:00:39:97:ac"></mac>`,
			`      <source>`,
			`        <address type="pci" domain="0x0000" bus="0x03" slot="0x0e" function="0x5"></address>`,
			`      </source>`,
			`    </interface>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Filesystems: []DomainFilesystem{
					DomainFilesystem{
						AccessMode: "mapped",
						Driver: &DomainFilesystemDriver{
							Type:     "path",
							WRPolicy: "immediate",
						},
						Source: &DomainFilesystemSource{
							Mount: &DomainFilesystemSourceMount{
								Dir: "/home/user/test",
							},
						},
						Target: &DomainFilesystemTarget{
							Dir: "user-test-mount",
						},
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &fsAddr.Domain,
								Bus:      &fsAddr.Bus,
								Slot:     &fsAddr.Slot,
								Function: &fsAddr.Function,
							},
						},
					},
					DomainFilesystem{
						AccessMode: "passthrough",
						Driver: &DomainFilesystemDriver{
							Name: "loop",
							Type: "raw",
						},
						Source: &DomainFilesystemSource{
							File: &DomainFilesystemSourceFile{
								File: "/home/user/test.img",
							},
						},
						Target: &DomainFilesystemTarget{
							Dir: "user-file-test-mount",
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <filesystem type="mount" accessmode="mapped">`,
			`      <driver type="path" wrpolicy="immediate"></driver>`,
			`      <source dir="/home/user/test"></source>`,
			`      <target dir="user-test-mount"></target>`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x06" function="0x0"></address>`,
			`    </filesystem>`,
			`    <filesystem type="file" accessmode="passthrough">`,
			`      <driver type="raw" name="loop"></driver>`,
			`      <source file="/home/user/test.img"></source>`,
			`      <target dir="user-file-test-mount"></target>`,
			`    </filesystem>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Features: &DomainFeatureList{
				PAE:     &DomainFeature{},
				ACPI:    &DomainFeature{},
				APIC:    &DomainFeatureAPIC{},
				HAP:     &DomainFeatureState{},
				PrivNet: &DomainFeature{},
				HyperV: &DomainFeatureHyperV{
					Relaxed: &DomainFeatureState{State: "on"},
					VAPIC:   &DomainFeatureState{State: "on"},
					Spinlocks: &DomainFeatureHyperVSpinlocks{
						DomainFeatureState{State: "on"}, 4096,
					},
					VPIndex: &DomainFeatureState{State: "on"},
					Runtime: &DomainFeatureState{State: "on"},
					Synic:   &DomainFeatureState{State: "on"},
					Reset:   &DomainFeatureState{State: "on"},
					VendorId: &DomainFeatureHyperVVendorId{
						DomainFeatureState{State: "on"}, "KVM Hv",
					},
				},
				KVM: &DomainFeatureKVM{
					Hidden: &DomainFeatureState{State: "on"},
				},
				PVSpinlock: &DomainFeatureState{State: "on"},
				GIC:        &DomainFeatureGIC{Version: "2"},
				Capabilities: &DomainFeatureCapabilities{
					Policy: "default",
					MkNod: &DomainFeatureCapability{
						State: "on",
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <features>`,
			`    <pae></pae>`,
			`    <acpi></acpi>`,
			`    <apic></apic>`,
			`    <hap></hap>`,
			`    <privnet></privnet>`,
			`    <hyperv>`,
			`      <relaxed state="on"></relaxed>`,
			`      <vapic state="on"></vapic>`,
			`      <spinlocks state="on" retries="4096"></spinlocks>`,
			`      <vpindex state="on"></vpindex>`,
			`      <runtime state="on"></runtime>`,
			`      <synic state="on"></synic>`,
			`      <reset state="on"></reset>`,
			`      <vendor_id state="on" value="KVM Hv"></vendor_id>`,
			`    </hyperv>`,
			`    <kvm>`,
			`      <hidden state="on"></hidden>`,
			`    </kvm>`,
			`    <pvspinlock state="on"></pvspinlock>`,
			`    <gic version="2"></gic>`,
			`    <capabilities policy="default">`,
			`      <mknod state="on"></mknod>`,
			`    </capabilities>`,
			`  </features>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Controllers: []DomainController{
					DomainController{
						Type:  "usb",
						Index: &uhciIndex,
						Model: "piix3-uhci",
						Address: &DomainAddress{
							PCI: &DomainAddressPCI{
								Domain:   &uhciAddr.Domain,
								Bus:      &uhciAddr.Bus,
								Slot:     &uhciAddr.Slot,
								Function: &uhciAddr.Function,
							},
						},
					},
					DomainController{
						Type:  "usb",
						Index: nil,
						Model: "ehci",
						USB: &DomainControllerUSB{
							Master: &DomainControllerUSBMaster{
								StartPort: 0,
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <controller type="usb" index="0" model="piix3-uhci">`,
			`      <address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x2"></address>`,
			`    </controller>`,
			`    <controller type="usb" model="ehci">`,
			`      <master startport="0"></master>`,
			`    </controller>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Controllers: []DomainController{
					DomainController{
						Type:  "pci",
						Index: &pciIndex,
						Model: "pci-expander-bus",
						PCI: &DomainControllerPCI{
							Model: &DomainControllerPCIModel{
								Name: "pxb",
							},
							Target: &DomainControllerPCITarget{
								ChassisNr: &pciTargetChassisNr,
								Chassis:   &pciTargetChassis,
								Port:      &pciTargetPort,
								BusNr:     &pciTargetBusNr,
								Index:     &pciTargetIndex,
								NUMANode:  &pciTargetNUMANode,
							},
							Hole64: &DomainControllerPCIHole64{
								Size: 1024,
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <controller type="pci" index="0" model="pci-expander-bus">`,
			`      <model name="pxb"></model>`,
			`      <target chassisNr="7" chassis="23" port="78" busNr="2" index="3">`,
			`        <node>2</node>`,
			`      </target>`,
			`      <pcihole64>1024</pcihole64>`,
			`    </controller>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Controllers: []DomainController{
					DomainController{
						Type:  "scsi",
						Index: &scsiIndex,
						Driver: &DomainControllerDriver{
							Queues:     &scsiQueues,
							CmdPerLUN:  &scsiCmdPerLUN,
							MaxSectors: &scsiMaxSectors,
							IOEventFD:  "yes",
							IOThread:   3,
							IOMMU:      "yes",
							ATS:        "no",
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <controller type="scsi" index="0">`,
			`      <driver queues="3" cmd_per_lun="8" max_sectors="512" ioeventfd="yes" iothread="3" iommu="yes" ats="no"></driver>`,
			`    </controller>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Hubs: []DomainHub{
					DomainHub{
						Type: "usb",
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <hub type="usb"></hub>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				IOMMU: &DomainIOMMU{
					Model: "intel",
					Driver: &DomainIOMMUDriver{
						EIM:         "on",
						IntRemap:    "on",
						CachingMode: "on",
						AWBits:      48,
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <iommu model="intel">`,
			`      <driver intremap="on" caching_mode="on" eim="on" aw_bits="48"></driver>`,
			`    </iommu>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Perf: &DomainPerf{
				Events: []DomainPerfEvent{
					DomainPerfEvent{
						Name:    "cmt",
						Enabled: "yes",
					},
					DomainPerfEvent{
						Name:    "mbmt",
						Enabled: "no",
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <perf>`,
			`    <event name="cmt" enabled="yes"></event>`,
			`    <event name="mbmt" enabled="no"></event>`,
			`  </perf>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				Leases: []DomainLease{
					DomainLease{
						Lockspace: "foo",
						Key:       "bar",
						Target: &DomainLeaseTarget{
							Path:   "/some/file",
							Offset: 1024,
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <lease>`,
			`      <lockspace>foo</lockspace>`,
			`      <key>bar</key>`,
			`      <target path="/some/file" offset="1024"></target>`,
			`    </lease>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "kvm",
			Name: "test",
			Devices: &DomainDeviceList{
				NVRAM: &DomainNVRAM{
					Address: &DomainAddress{
						SpaprVIO: &DomainAddressSpaprVIO{
							Reg: &nvramReg,
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain type="kvm">`,
			`  <name>test</name>`,
			`  <devices>`,
			`    <nvram>`,
			`      <address type="spapr-vio" reg="0x4000"></address>`,
			`    </nvram>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "qemu",
			Name: "test",
			QEMUCommandline: &DomainQEMUCommandline{
				Args: []DomainQEMUCommandlineArg{
					DomainQEMUCommandlineArg{Value: "-newarg"},
					DomainQEMUCommandlineArg{Value: "-oldarg"},
				},
				Envs: []DomainQEMUCommandlineEnv{
					DomainQEMUCommandlineEnv{Name: "QEMU_ENV", Value: "VAL"},
					DomainQEMUCommandlineEnv{Name: "QEMU_VAR", Value: "VAR"},
				},
			},
		},
		Expected: []string{
			`<domain type="qemu">`,
			`  <name>test</name>`,
			`  <commandline xmlns="http://libvirt.org/schemas/domain/qemu/1.0">`,
			`    <arg value="-newarg"></arg>`,
			`    <arg value="-oldarg"></arg>`,
			`    <env name="QEMU_ENV" value="VAL"></env>`,
			`    <env name="QEMU_VAR" value="VAR"></env>`,
			`  </commandline>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "lxc",
			Name: "test",
			LXCNamespace: &DomainLXCNamespace{
				ShareNet: &DomainLXCNamespaceMap{
					Type:  "netns",
					Value: "red",
				},
				ShareIPC: &DomainLXCNamespaceMap{
					Type:  "pid",
					Value: "12345",
				},
				ShareUTS: &DomainLXCNamespaceMap{
					Type:  "name",
					Value: "container1",
				},
			},
		},
		Expected: []string{
			`<domain type="lxc">`,
			`  <name>test</name>`,
			`  <namespace xmlns="http://libvirt.org/schemas/domain/lxc/1.0">`,
			`    <sharenet type="netns" value="red"></sharenet>`,
			`    <shareipc type="pid" value="12345"></shareipc>`,
			`    <shareuts type="name" value="container1"></shareuts>`,
			`  </namespace>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Type: "vmware",
			Name: "test",
			VMWareDataCenterPath: &DomainVMWareDataCenterPath{
				Value: "folder1/folder2/datacenter1",
			},
		},
		Expected: []string{
			`<domain type="vmware">`,
			`  <name>test</name>`,
			`  <datacenterpath xmlns="http://libvirt.org/schemas/domain/vmware/1.0">folder1/folder2/datacenter1</datacenterpath>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name:      "test",
			IOThreads: 4,
			IOThreadIDs: &DomainIOThreadIDs{
				IOThreads: []DomainIOThread{
					DomainIOThread{
						ID: 0,
					},
					DomainIOThread{
						ID: 1,
					},
					DomainIOThread{
						ID: 2,
					},
					DomainIOThread{
						ID: 3,
					},
				},
			},
			CPUTune: &DomainCPUTune{
				Shares:         &DomainCPUTuneShares{Value: 1024},
				Period:         &DomainCPUTunePeriod{Value: 500000},
				Quota:          &DomainCPUTuneQuota{Value: -1},
				GlobalPeriod:   &DomainCPUTunePeriod{Value: 500000},
				GlobalQuota:    &DomainCPUTuneQuota{Value: 500},
				EmulatorPeriod: &DomainCPUTunePeriod{Value: 900000},
				EmulatorQuota:  &DomainCPUTuneQuota{Value: 100},
				IOThreadPeriod: &DomainCPUTunePeriod{Value: 100000},
				IOThreadQuota:  &DomainCPUTuneQuota{Value: 2000},
				VCPUPin: []DomainCPUTuneVCPUPin{
					DomainCPUTuneVCPUPin{
						VCPU:   0,
						CPUSet: "0-1",
					},
					DomainCPUTuneVCPUPin{
						VCPU:   1,
						CPUSet: "2-3",
					},
				},
				EmulatorPin: &DomainCPUTuneEmulatorPin{
					CPUSet: "0-3",
				},
				IOThreadPin: []DomainCPUTuneIOThreadPin{
					DomainCPUTuneIOThreadPin{
						IOThread: 0,
						CPUSet:   "0-1",
					},
					DomainCPUTuneIOThreadPin{
						IOThread: 1,
						CPUSet:   "2-3",
					},
				},
				VCPUSched: []DomainCPUTuneVCPUSched{
					DomainCPUTuneVCPUSched{
						VCPUs:     "0-1",
						Scheduler: "fifo",
						Priority:  &vcpuPriority,
					},
				},
				IOThreadSched: []DomainCPUTuneIOThreadSched{
					DomainCPUTuneIOThreadSched{
						IOThreads: "0-1",
						Scheduler: "fifo",
						Priority:  &iothreadPriority,
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>test</name>`,
			`  <iothreads>4</iothreads>`,
			`  <iothreadids>`,
			`    <iothread id="0"></iothread>`,
			`    <iothread id="1"></iothread>`,
			`    <iothread id="2"></iothread>`,
			`    <iothread id="3"></iothread>`,
			`  </iothreadids>`,
			`  <cputune>`,
			`    <shares>1024</shares>`,
			`    <period>500000</period>`,
			`    <quota>-1</quota>`,
			`    <global_period>500000</global_period>`,
			`    <global_quota>500</global_quota>`,
			`    <emulator_period>900000</emulator_period>`,
			`    <emulator_quota>100</emulator_quota>`,
			`    <iothread_period>100000</iothread_period>`,
			`    <iothread_quota>2000</iothread_quota>`,
			`    <vcpupin vcpu="0" cpuset="0-1"></vcpupin>`,
			`    <vcpupin vcpu="1" cpuset="2-3"></vcpupin>`,
			`    <emulatorpin cpuset="0-3"></emulatorpin>`,
			`    <iothreadpin iothread="0" cpuset="0-1"></iothreadpin>`,
			`    <iothreadpin iothread="1" cpuset="2-3"></iothreadpin>`,
			`    <vcpusched vcpus="0-1" scheduler="fifo" priority="-5"></vcpusched>`,
			`    <iothreadsched iothreads="0-1" scheduler="fifo" priority="-3"></iothreadsched>`,
			`  </cputune>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name: "test",
			KeyWrap: &DomainKeyWrap{
				Ciphers: []DomainKeyWrapCipher{
					DomainKeyWrapCipher{
						Name:  "aes",
						State: "on",
					},
					DomainKeyWrapCipher{
						Name:  "dea",
						State: "off",
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>test</name>`,
			`  <keywrap>`,
			`    <cipher name="aes" state="on"></cipher>`,
			`    <cipher name="dea" state="off"></cipher>`,
			`  </keywrap>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name: "test",
			IDMap: &DomainIDMap{
				UIDs: []DomainIDMapRange{
					DomainIDMapRange{
						Start:  0,
						Target: 1000,
						Count:  50,
					},
					DomainIDMapRange{
						Start:  1000,
						Target: 5000,
						Count:  5000,
					},
				},
				GIDs: []DomainIDMapRange{
					DomainIDMapRange{
						Start:  0,
						Target: 1000,
						Count:  50,
					},
					DomainIDMapRange{
						Start:  1000,
						Target: 5000,
						Count:  5000,
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>test</name>`,
			`  <idmap>`,
			`    <uid start="0" target="1000" count="50"></uid>`,
			`    <uid start="1000" target="5000" count="5000"></uid>`,
			`    <gid start="0" target="1000" count="50"></gid>`,
			`    <gid start="1000" target="5000" count="5000"></gid>`,
			`  </idmap>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name: "test",
			NUMATune: &DomainNUMATune{
				Memory: &DomainNUMATuneMemory{
					Mode:      "strict",
					Nodeset:   "2-3",
					Placement: "static",
				},
				MemNodes: []DomainNUMATuneMemNode{
					DomainNUMATuneMemNode{
						CellID:  0,
						Mode:    "strict",
						Nodeset: "2",
					},
					DomainNUMATuneMemNode{
						CellID:  1,
						Mode:    "strict",
						Nodeset: "3",
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>test</name>`,
			`  <numatune>`,
			`    <memory mode="strict" nodeset="2-3" placement="static"></memory>`,
			`    <memnode cellid="0" mode="strict" nodeset="2"></memnode>`,
			`    <memnode cellid="1" mode="strict" nodeset="3"></memnode>`,

			`  </numatune>`,
			`</domain>`,
		},
	},

	/* Tests for sub-documents that can be hotplugged */
	{
		Object: &DomainController{
			Type:  "usb",
			Index: &uhciIndex,
			Model: "piix3-uhci",
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &uhciAddr.Domain,
					Bus:      &uhciAddr.Bus,
					Slot:     &uhciAddr.Slot,
					Function: &uhciAddr.Function,
				},
			},
		},
		Expected: []string{
			`<controller type="usb" index="0" model="piix3-uhci">`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x2"></address>`,
			`</controller>`,
		},
	},
	{
		Object: &DomainDisk{
			Device: "cdrom",
			Driver: &DomainDiskDriver{
				Name: "qemu",
				Type: "qcow2",
			},
			Source: &DomainDiskSource{
				File: &DomainDiskSourceFile{
					File: "/var/lib/libvirt/images/demo.qcow2",
				},
			},
			BackingStore: &DomainDiskBackingStore{
				Index: 1,
				Format: &DomainDiskFormat{
					Type: "qcow2",
				},
				Source: &DomainDiskSource{
					Block: &DomainDiskSourceBlock{
						Dev: "/dev/HostVG/QEMUGuest",
					},
				},
				BackingStore: &DomainDiskBackingStore{
					Index: 2,
					Format: &DomainDiskFormat{
						Type: "qcow2",
					},
					Source: &DomainDiskSource{
						File: &DomainDiskSourceFile{
							File: "/tmp/image2.qcow2",
						},
					},
					BackingStore: &DomainDiskBackingStore{
						Index: 3,
						Format: &DomainDiskFormat{
							Type: "raw",
						},
						Source: &DomainDiskSource{
							File: &DomainDiskSourceFile{
								File: "/tmp/image3.iso",
							},
						},
						BackingStore: &DomainDiskBackingStore{},
					},
				},
			},
			Target: &DomainDiskTarget{
				Dev: "vda",
				Bus: "virtio",
			},
			Serial: "fishfood",
			WWN:    "0123456789abcdef",
		},
		Expected: []string{
			`<disk type="file" device="cdrom">`,
			`  <driver name="qemu" type="qcow2"></driver>`,
			`  <source file="/var/lib/libvirt/images/demo.qcow2"></source>`,
			`  <backingStore type="block" index="1">`,
			`    <format type="qcow2"></format>`,
			`    <source dev="/dev/HostVG/QEMUGuest"></source>`,
			`    <backingStore type="file" index="2">`,
			`      <format type="qcow2"></format>`,
			`      <source file="/tmp/image2.qcow2"></source>`,
			`      <backingStore type="file" index="3">`,
			`        <format type="raw"></format>`,
			`        <source file="/tmp/image3.iso"></source>`,
			`        <backingStore></backingStore>`,
			`      </backingStore>`,
			`    </backingStore>`,
			`  </backingStore>`,
			`  <target dev="vda" bus="virtio"></target>`,
			`  <serial>fishfood</serial>`,
			`  <wwn>0123456789abcdef</wwn>`,
			`</disk>`,
		},
	},
	{
		Object: &DomainDisk{
			Device: "cdrom",
			Driver: &DomainDiskDriver{
				Name: "qemu",
				Type: "qcow2",
			},
			Source: &DomainDiskSource{
				Block: &DomainDiskSourceBlock{
					Dev: "/dev/HostVG/QEMUGuest1",
				},
			},
			Mirror: &DomainDiskMirror{
				Job:   "copy",
				Ready: "yes",
				Source: &DomainDiskSource{
					Block: &DomainDiskSourceBlock{
						Dev: "/dev/HostVG/QEMUGuest1Copy",
					},
				},
			},
			Target: &DomainDiskTarget{
				Dev: "vda",
				Bus: "virtio",
			},
		},
		Expected: []string{
			`<disk type="block" device="cdrom">`,
			`  <driver name="qemu" type="qcow2"></driver>`,
			`  <source dev="/dev/HostVG/QEMUGuest1"></source>`,
			`  <mirror type="block" job="copy" ready="yes">`,
			`    <source dev="/dev/HostVG/QEMUGuest1Copy"></source>`,
			`  </mirror>`,
			`  <target dev="vda" bus="virtio"></target>`,
			`</disk>`,
		},
	},
	{
		Object: &DomainDisk{
			Device: "cdrom",
			Driver: &DomainDiskDriver{
				Name: "qemu",
				Type: "qcow2",
			},
			Source: &DomainDiskSource{
				NVME: &DomainDiskSourceNVME{
					PCI: &DomainDiskSourceNVMEPCI{
						Managed:   "yes",
						Namespace: 15,
						Address: &DomainAddressPCI{
							Domain:   &nvmeAddr.Domain,
							Bus:      &nvmeAddr.Bus,
							Slot:     &nvmeAddr.Slot,
							Function: &nvmeAddr.Function,
						},
					},
				},
			},
			Target: &DomainDiskTarget{
				Dev: "vda",
				Bus: "virtio",
			},
		},
		Expected: []string{
			`<disk type="nvme" device="cdrom">`,
			`  <driver name="qemu" type="qcow2"></driver>`,
			`  <source type="pci" managed="yes" namespace="15">`,
			`    <address domain="0x0000" bus="0x01" slot="0x03" function="0x0"></address>`,
			`  </source>`,
			`  <target dev="vda" bus="virtio"></target>`,
			`</disk>`,
		},
	},
	{
		Object: &DomainDisk{
			Device: "cdrom",
			Driver: &DomainDiskDriver{
				Name: "qemu",
				Type: "qcow2",
			},
			Source: &DomainDiskSource{
				File: &DomainDiskSourceFile{
					File: "/var/lib/libvirt/images/demo.qcow2",
				},
			},
			Mirror: &DomainDiskMirror{
				Job: "copy",
				Format: &DomainDiskFormat{
					Type: "qcow2",
				},
				Source: &DomainDiskSource{
					File: &DomainDiskSourceFile{
						File: "/var/lib/libvirt/images/demo-copy.qcow2",
					},
				},
			},
			Target: &DomainDiskTarget{
				Dev: "vda",
				Bus: "virtio",
			},
		},
		Expected: []string{
			`<disk type="file" device="cdrom">`,
			`  <driver name="qemu" type="qcow2"></driver>`,
			`  <source file="/var/lib/libvirt/images/demo.qcow2"></source>`,
			`  <mirror type="file" file="/var/lib/libvirt/images/demo-copy.qcow2" format="qcow2" job="copy">`,
			`    <format type="qcow2"></format>`,
			`    <source file="/var/lib/libvirt/images/demo-copy.qcow2"></source>`,
			`  </mirror>`,
			`  <target dev="vda" bus="virtio"></target>`,
			`</disk>`,
		},
	},
	{
		Object: &DomainFilesystem{
			AccessMode: "mapped",
			Driver: &DomainFilesystemDriver{
				Type:     "path",
				WRPolicy: "immediate",
			},
			Source: &DomainFilesystemSource{
				Mount: &DomainFilesystemSourceMount{
					Dir: "/home/user/test",
				},
			},
			Target: &DomainFilesystemTarget{
				Dir: "user-test-mount",
			},
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &fsAddr.Domain,
					Bus:      &fsAddr.Bus,
					Slot:     &fsAddr.Slot,
					Function: &fsAddr.Function,
				},
			},
		},

		Expected: []string{
			`<filesystem type="mount" accessmode="mapped">`,
			`  <driver type="path" wrpolicy="immediate"></driver>`,
			`  <source dir="/home/user/test"></source>`,
			`  <target dir="user-test-mount"></target>`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x06" function="0x0"></address>`,
			`</filesystem>`,
		},
	},
	{
		Object: &DomainInterface{
			MAC: &DomainInterfaceMAC{
				Address: "00:11:22:33:44:55",
			},
			Model: &DomainInterfaceModel{
				Type: "virtio",
			},
			Source: &DomainInterfaceSource{
				Network: &DomainInterfaceSourceNetwork{
					Network: "default",
				},
			},
		},
		Expected: []string{
			`<interface type="network">`,
			`  <mac address="00:11:22:33:44:55"></mac>`,
			`  <source network="default"></source>`,
			`  <model type="virtio"></model>`,
			`</interface>`,
		},
	},
	{
		Object: &DomainSerial{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainSerialTarget{
				Type: "isa",
				Port: &serialPort,
				Model: &DomainSerialTargetModel{
					Name: "isa-serial",
				},
			},
			Log: &DomainChardevLog{
				File:   "/some/path",
				Append: "on",
			},
		},

		Expected: []string{
			`<serial type="pty">`,
			`  <target type="isa" port="0">`,
			`    <model name="isa-serial"></model>`,
			`  </target>`,
			`  <log file="/some/path" append="on"></log>`,
			`</serial>`,
		},
	},
	{
		Object: &DomainParallel{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainParallelTarget{
				Type: "isa",
				Port: &parallelPort,
			},
			Log: &DomainChardevLog{
				File:   "/some/path",
				Append: "on",
			},
		},

		Expected: []string{
			`<parallel type="pty">`,
			`  <target type="isa" port="0"></target>`,
			`  <log file="/some/path" append="on"></log>`,
			`</parallel>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainConsoleTarget{
				Type: "virtio",
				Port: &serialPort,
			},
		},

		Expected: []string{
			`<console type="pty">`,
			`  <target type="virtio" port="0"></target>`,
			`</console>`,
		},
	},
	{
		Object: &DomainSmartcard{
			Host: &DomainSmartcardHost{},
			Address: &DomainAddress{
				CCID: &DomainAddressCCID{
					Controller: &smartcardController,
					Slot:       &smartcardSlot,
				},
			},
		},

		Expected: []string{
			`<smartcard mode="host">`,
			`  <address type="ccid" controller="0" slot="7"></address>`,
			`</smartcard>`,
		},
	},
	{
		Object: &DomainSmartcard{
			Passthrough: &DomainChardevSource{
				TCP: &DomainChardevSourceTCP{
					Mode:    "connect",
					Host:    "localhost",
					Service: "12345",
				},
			},
			Protocol: &DomainChardevProtocol{
				Type: "raw",
			},
			Address: &DomainAddress{
				CCID: &DomainAddressCCID{
					Controller: &smartcardController,
					Slot:       &smartcardSlot,
				},
			},
		},

		Expected: []string{
			`<smartcard mode="passthrough" type="tcp">`,
			`  <source mode="connect" host="localhost" service="12345"></source>`,
			`  <protocol type="raw"></protocol>`,
			`  <address type="ccid" controller="0" slot="7"></address>`,
			`</smartcard>`,
		},
	},
	{
		Object: &DomainSmartcard{
			HostCerts: []DomainSmartcardHostCert{
				DomainSmartcardHostCert{
					File: "/some/cert1",
				},
				DomainSmartcardHostCert{
					File: "/some/cert2",
				},
				DomainSmartcardHostCert{
					File: "/some/cert3",
				},
			},
			Address: &DomainAddress{
				CCID: &DomainAddressCCID{
					Controller: &smartcardController,
					Slot:       &smartcardSlot,
				},
			},
		},

		Expected: []string{
			`<smartcard mode="host-certificates">`,
			`  <certificate>/some/cert1</certificate>`,
			`  <certificate>/some/cert2</certificate>`,
			`  <certificate>/some/cert3</certificate>`,
			`  <address type="ccid" controller="0" slot="7"></address>`,
			`</smartcard>`,
		},
	},
	{
		Object: &DomainTPM{
			Model: "tpm-tis",
			Backend: &DomainTPMBackend{
				Passthrough: &DomainTPMBackendPassthrough{
					Device: &DomainTPMBackendDevice{
						Path: "/dev/tpm0",
					},
				},
			},
		},

		Expected: []string{
			`<tpm model="tpm-tis">`,
			`  <backend type="passthrough">`,
			`    <device path="/dev/tpm0"></device>`,
			`  </backend>`,
			`</tpm>`,
		},
	},
	{
		Object: &DomainShmem{
			Name: "demo",
			Size: &DomainShmemSize{
				Value: 1,
				Unit:  "GiB",
			},
			Model: &DomainShmemModel{
				Type: "ivshmem-doorbell",
			},
			Server: &DomainShmemServer{
				Path: "/some/server",
			},
			MSI: &DomainShmemMSI{
				Enabled:   "yes",
				Vectors:   5,
				IOEventFD: "yes",
			},
		},

		Expected: []string{
			`<shmem name="demo">`,
			`  <size unit="GiB">1</size>`,
			`  <model type="ivshmem-doorbell"></model>`,
			`  <server path="/some/server"></server>`,
			`  <msi enabled="yes" vectors="5" ioeventfd="yes"></msi>`,
			`</shmem>`,
		},
	},
	{
		Object: &DomainInput{
			Type: "tablet",
			Bus:  "usb",
			Address: &DomainAddress{
				USB: &DomainAddressUSB{
					Bus:  &tabletBus,
					Port: tabletPort,
				},
			},
		},

		Expected: []string{
			`<input type="tablet" bus="usb">`,
			`  <address type="usb" bus="0" port="1.1"></address>`,
			`</input>`,
		},
	},
	{
		Object: &DomainVideo{
			Driver: &DomainVideoDriver{
				VGAConf: "io",
			},
			Model: DomainVideoModel{
				Type:    "cirrus",
				Heads:   1,
				Ram:     4096,
				VRam:    8192,
				VRam64:  8192,
				VGAMem:  256,
				Primary: "yes",
				Accel: &DomainVideoAccel{
					Accel3D: "yes",
					Accel2D: "no",
				},
			},
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:        &videoAddr.Domain,
					Bus:           &videoAddr.Bus,
					Slot:          &videoAddr.Slot,
					Function:      &videoAddr.Function,
					MultiFunction: "on",
				},
			},
		},

		Expected: []string{
			`<video>`,
			`  <model type="cirrus" heads="1" ram="4096" vram="8192" vram64="8192" vgamem="256" primary="yes">`,
			`    <acceleration accel3d="yes" accel2d="no"></acceleration>`,
			`  </model>`,
			`  <driver vgaconf="io"></driver>`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x05" function="0x0" multifunction="on"></address>`,
			`</video>`,
		},
	},
	{
		Object: &DomainChannel{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainChannelTarget{
				VirtIO: &DomainChannelTargetVirtIO{
					Name:  "org.redhat.spice",
					State: "connected",
				},
			},
		},

		Expected: []string{
			`<channel type="pty">`,
			`  <target type="virtio" name="org.redhat.spice" state="connected"></target>`,
			`</channel>`,
		},
	},
	{
		Object: &DomainChannel{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainChannelTarget{
				Xen: &DomainChannelTargetXen{
					Name:  "org.redhat.spice",
					State: "connected",
				},
			},
		},

		Expected: []string{
			`<channel type="pty">`,
			`  <target type="xen" name="org.redhat.spice" state="connected"></target>`,
			`</channel>`,
		},
	},
	{
		Object: &DomainRedirDev{
			Bus: "usb",
			Source: &DomainChardevSource{
				SpiceVMC: &DomainChardevSourceSpiceVMC{},
			},
			Address: &DomainAddress{
				USB: &DomainAddressUSB{
					Bus:  &redirBus,
					Port: redirPort,
				},
			},
		},

		Expected: []string{
			`<redirdev type="spicevmc" bus="usb">`,
			`  <address type="usb" bus="0" port="3"></address>`,
			`</redirdev>`,
		},
	},
	{
		Object: &DomainRedirDev{
			Bus: "usb",
			Source: &DomainChardevSource{
				TCP: &DomainChardevSourceTCP{
					Mode:    "connect",
					Host:    "localhost",
					Service: "1234",
				},
			},
			Protocol: &DomainChardevProtocol{
				Type: "raw",
			},
			Boot: &DomainDeviceBoot{
				Order: 1,
			},
			Address: &DomainAddress{
				USB: &DomainAddressUSB{
					Bus:  &redirBus,
					Port: redirPort,
				},
			},
		},

		Expected: []string{
			`<redirdev type="tcp" bus="usb">`,
			`  <source mode="connect" host="localhost" service="1234"></source>`,
			`  <protocol type="raw"></protocol>`,
			`  <boot order="1"></boot>`,
			`  <address type="usb" bus="0" port="3"></address>`,
			`</redirdev>`,
		},
	},
	{
		Object: &DomainChannel{
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{},
			},
			Target: &DomainChannelTarget{
				GuestFWD: &DomainChannelTargetGuestFWD{
					Address: "192.168.1.1",
					Port:    "123",
				},
			},
		},

		Expected: []string{
			`<channel type="pty">`,
			`  <target type="guestfwd" address="192.168.1.1" port="123"></target>`,
			`</channel>`,
		},
	},
	{
		Object: &Domain{
			Name: "demo",
			Devices: &DomainDeviceList{
				Graphics: []DomainGraphic{
					DomainGraphic{
						Spice: &DomainGraphicSpice{
							Port:        5903,
							TLSPort:     5904,
							AutoPort:    "no",
							Listen:      "127.0.0.1",
							DefaultMode: "secure",
							Listeners: []DomainGraphicListener{
								DomainGraphicListener{
									Address: &DomainGraphicListenerAddress{
										Address: "127.0.0.1",
									},
								},
							},
							Channel: []DomainGraphicSpiceChannel{
								DomainGraphicSpiceChannel{
									Name: "main",
									Mode: "secure",
								},
								DomainGraphicSpiceChannel{
									Name: "inputs",
									Mode: "insecure",
								},
							},
							Image: &DomainGraphicSpiceImage{
								Compression: "auto_glz",
							},
							JPEG: &DomainGraphicSpiceJPEG{
								Compression: "auto",
							},
							ZLib: &DomainGraphicSpiceZLib{
								Compression: "auto",
							},
							Playback: &DomainGraphicSpicePlayback{
								Compression: "on",
							},
							Streaming: &DomainGraphicSpiceStreaming{
								Mode: "filter",
							},
							ClipBoard: &DomainGraphicSpiceClipBoard{
								CopyPaste: "no",
							},
							FileTransfer: &DomainGraphicSpiceFileTransfer{
								Enable: "no",
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>demo</name>`,
			`  <devices>`,
			`    <graphics type="spice" port="5903" tlsPort="5904" autoport="no" listen="127.0.0.1" defaultMode="secure">`,
			`      <listen type="address" address="127.0.0.1"></listen>`,
			`      <channel name="main" mode="secure"></channel>`,
			`      <channel name="inputs" mode="insecure"></channel>`,
			`      <image compression="auto_glz"></image>`,
			`      <jpeg compression="auto"></jpeg>`,
			`      <zlib compression="auto"></zlib>`,
			`      <playback compression="on"></playback>`,
			`      <streaming mode="filter"></streaming>`,
			`      <clipboard copypaste="no"></clipboard>`,
			`      <filetransfer enable="no"></filetransfer>`,
			`    </graphics>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name: "demo",
			Devices: &DomainDeviceList{
				Graphics: []DomainGraphic{
					DomainGraphic{
						VNC: &DomainGraphicVNC{
							Port:     5903,
							AutoPort: "no",
							Listeners: []DomainGraphicListener{
								DomainGraphicListener{},
							},
						},
					},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>demo</name>`,
			`  <devices>`,
			`    <graphics type="vnc" port="5903" autoport="no">`,
			`      <listen type="none"></listen>`,
			`    </graphics>`,
			`  </devices>`,
			`</domain>`,
		},
	},
	{
		Object: &DomainMemBalloon{
			Model:       "virtio",
			AutoDeflate: "on",
			Stats: &DomainMemBalloonStats{
				Period: 10,
			},
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &balloonAddr.Domain,
					Bus:      &balloonAddr.Bus,
					Slot:     &balloonAddr.Slot,
					Function: &balloonAddr.Function,
				},
			},
		},

		Expected: []string{
			`<memballoon model="virtio" autodeflate="on">`,
			`  <stats period="10"></stats>`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x07" function="0x0"></address>`,
			`</memballoon>`,
		},
	},
	{
		Object: &DomainWatchdog{
			Model:  "ib700",
			Action: "inject-nmi",
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &watchdogAddr.Domain,
					Bus:      &watchdogAddr.Bus,
					Slot:     &watchdogAddr.Slot,
					Function: &watchdogAddr.Function,
				},
			},
		},

		Expected: []string{
			`<watchdog model="ib700" action="inject-nmi">`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x08" function="0x0"></address>`,
			`</watchdog>`,
		},
	},
	{
		Object: &DomainSound{
			Model: "ich6",
			Codec: []DomainSoundCodec{
				DomainSoundCodec{
					Type: "duplex",
				},
				DomainSoundCodec{
					Type: "micro",
				},
			},
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &duplexAddr.Domain,
					Bus:      &duplexAddr.Bus,
					Slot:     &duplexAddr.Slot,
					Function: &duplexAddr.Function,
				},
			},
		},

		Expected: []string{
			`<sound model="ich6">`,
			`  <codec type="duplex"></codec>`,
			`  <codec type="micro"></codec>`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x08" function="0x0"></address>`,
			`</sound>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				Null: &DomainChardevSourceNull{},
			},
		},

		Expected: []string{
			`<console type="null"></console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				VC: &DomainChardevSourceVC{},
			},
		},

		Expected: []string{
			`<console type="vc"></console>`,
		},
	},
	{
		Object: &DomainConsole{
			TTY: "/dev/pts/3",
			Source: &DomainChardevSource{
				Pty: &DomainChardevSourcePty{
					Path: "/dev/pts/3",
				},
			},
		},

		Expected: []string{
			`<console type="pty" tty="/dev/pts/3">`,
			`  <source path="/dev/pts/3"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				Dev: &DomainChardevSourceDev{
					Path: "/dev/ttyS0",
				},
			},
		},

		Expected: []string{
			`<console type="dev">`,
			`  <source path="/dev/ttyS0"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				File: &DomainChardevSourceFile{
					Path: "/tmp/file.log",
				},
			},
		},

		Expected: []string{
			`<console type="file">`,
			`  <source path="/tmp/file.log"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				Pipe: &DomainChardevSourcePipe{
					Path: "/tmp/file.fifo",
				},
			},
		},

		Expected: []string{
			`<console type="pipe">`,
			`  <source path="/tmp/file.fifo"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				StdIO: &DomainChardevSourceStdIO{},
			},
		},

		Expected: []string{
			`<console type="stdio"></console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				UDP: &DomainChardevSourceUDP{
					ConnectHost:    "some.server",
					ConnectService: "4999",
					BindHost:       "my.server",
					BindService:    "5921",
				},
			},
		},

		Expected: []string{
			`<console type="udp">`,
			`  <source mode="bind" host="my.server" service="5921"></source>`,
			`  <source mode="connect" host="some.server" service="4999"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				TCP: &DomainChardevSourceTCP{
					Mode:    "connect",
					Host:    "localhost",
					Service: "25",
				},
			},
		},

		Expected: []string{
			`<console type="tcp">`,
			`  <source mode="connect" host="localhost" service="25"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				UNIX: &DomainChardevSourceUNIX{
					Mode: "connect",
					Path: "/tmp/myvm.sock",
				},
			},
		},

		Expected: []string{
			`<console type="unix">`,
			`  <source mode="connect" path="/tmp/myvm.sock"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				SpiceVMC: &DomainChardevSourceSpiceVMC{},
			},
		},

		Expected: []string{
			`<console type="spicevmc"></console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				SpicePort: &DomainChardevSourceSpicePort{
					Channel: "org.qemu.console.serial.0",
				},
			},
		},

		Expected: []string{
			`<console type="spiceport">`,
			`  <source channel="org.qemu.console.serial.0"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainConsole{
			Source: &DomainChardevSource{
				NMDM: &DomainChardevSourceNMDM{
					Master: "/dev/nmdm0A",
					Slave:  "/dev/nmdm0B",
				},
			},
		},

		Expected: []string{
			`<console type="nmdm">`,
			`  <source master="/dev/nmdm0A" slave="/dev/nmdm0B"></source>`,
			`</console>`,
		},
	},
	{
		Object: &DomainRNG{
			Model: "virtio",
			Rate: &DomainRNGRate{
				Period: 2000,
				Bytes:  1234,
			},
			Backend: &DomainRNGBackend{
				Random: &DomainRNGBackendRandom{
					Device: "/dev/random",
				},
			},
			Address: &DomainAddress{
				PCI: &DomainAddressPCI{
					Domain:   &rngAddr.Domain,
					Bus:      &rngAddr.Bus,
					Slot:     &rngAddr.Slot,
					Function: &rngAddr.Function,
				},
			},
		},

		Expected: []string{
			`<rng model="virtio">`,
			`  <rate bytes="1234" period="2000"></rate>`,
			`  <backend model="random">/dev/random</backend>`,
			`  <address type="pci" domain="0x0000" bus="0x00" slot="0x09" function="0x0"></address>`,
			`</rng>`,
		},
	},
	{
		Object: &DomainRNG{
			Model: "virtio",
			Rate: &DomainRNGRate{
				Period: 2000,
				Bytes:  1234,
			},
			Backend: &DomainRNGBackend{
				EGD: &DomainRNGBackendEGD{
					Source: &DomainChardevSource{
						UDP: &DomainChardevSourceUDP{
							BindService:    "1234",
							ConnectHost:    "1.2.3.4",
							ConnectService: "1234",
						},
					},
				},
			},
		},

		Expected: []string{
			`<rng model="virtio">`,
			`  <rate bytes="1234" period="2000"></rate>`,
			`  <backend model="egd" type="udp">`,
			`    <source mode="bind" service="1234"></source>`,
			`    <source mode="connect" host="1.2.3.4" service="1234"></source>`,
			`  </backend>`,
			`</rng>`,
		},
	},
	{
		Object: &DomainHostdev{
			SubsysSCSI: &DomainHostdevSubsysSCSI{
				SGIO:  "unfiltered",
				RawIO: "yes",
				Source: &DomainHostdevSubsysSCSISource{
					Host: &DomainHostdevSubsysSCSISourceHost{
						Adapter: &DomainHostdevSubsysSCSIAdapter{
							Name: "scsi_host0",
						},
						Address: &DomainAddressDrive{
							Bus:    &hostdevSCSI.Bus,
							Target: &hostdevSCSI.Target,
							Unit:   &hostdevSCSI.Unit,
						},
					},
				},
			},
			Address: &DomainAddress{
				Drive: &DomainAddressDrive{
					Controller: &hostdevSCSI.Controller,
					Bus:        &hostdevSCSI.Bus,
					Target:     &hostdevSCSI.Target,
					Unit:       &hostdevSCSI.Unit,
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="scsi" sgio="unfiltered" rawio="yes">`,
			`  <source>`,
			`    <adapter name="scsi_host0"></adapter>`,
			`    <address bus="0" target="3" unit="0"></address>`,
			`  </source>`,
			`  <address type="drive" controller="0" bus="0" target="3" unit="0"></address>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			SubsysSCSI: &DomainHostdevSubsysSCSI{
				SGIO:  "unfiltered",
				RawIO: "yes",
				Source: &DomainHostdevSubsysSCSISource{
					ISCSI: &DomainHostdevSubsysSCSISourceISCSI{
						Name: "iqn.1992-01.com.example:storage/1",
						Host: []DomainDiskSourceHost{
							DomainDiskSourceHost{
								Name: "example.org",
								Port: "3260",
							},
						},
						Auth: &DomainDiskAuth{
							Username: "myname",
							Secret: &DomainDiskSecret{
								Type:  "iscsi",
								Usage: "mycluster_myname",
							},
						},
					},
				},
			},
			Address: &DomainAddress{
				Drive: &DomainAddressDrive{
					Controller: &hostdevSCSI.Controller,
					Bus:        &hostdevSCSI.Bus,
					Target:     &hostdevSCSI.Target,
					Unit:       &hostdevSCSI.Unit,
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="scsi" sgio="unfiltered" rawio="yes">`,
			`  <source protocol="iscsi" name="iqn.1992-01.com.example:storage/1">`,
			`    <host name="example.org" port="3260"></host>`,
			`    <auth username="myname">`,
			`      <secret type="iscsi" usage="mycluster_myname"></secret>`,
			`    </auth>`,
			`  </source>`,
			`  <address type="drive" controller="0" bus="0" target="3" unit="0"></address>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			SubsysSCSIHost: &DomainHostdevSubsysSCSIHost{
				Source: &DomainHostdevSubsysSCSIHostSource{
					Protocol: "vhost",
					WWPN:     "naa.5123456789abcde0",
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="scsi_host">`,
			`  <source protocol="vhost" wwpn="naa.5123456789abcde0"></source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			SubsysUSB: &DomainHostdevSubsysUSB{
				Source: &DomainHostdevSubsysUSBSource{
					Address: &DomainAddressUSB{
						Bus:    &usbHostBus,
						Device: &usbHostDevice,
					},
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="usb">`,
			`  <source>`,
			`    <address bus="14" device="6"></address>`,
			`  </source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			Managed: "yes",
			SubsysPCI: &DomainHostdevSubsysPCI{
				Source: &DomainHostdevSubsysPCISource{
					Address: &DomainAddressPCI{
						Domain:   &pciHostDomain,
						Bus:      &pciHostBus,
						Slot:     &pciHostSlot,
						Function: &pciHostFunction,
					},
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="pci" managed="yes">`,
			`  <source>`,
			`    <address domain="0x0000" bus="0x03" slot="0x0e" function="0x5"></address>`,
			`  </source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			SubsysMDev: &DomainHostdevSubsysMDev{
				Model: "vfio-pci",
				Source: &DomainHostdevSubsysMDevSource{
					Address: &DomainAddressMDev{
						UUID: "53764d0e-85a0-42b4-af5c-2046b460b1dc",
					},
				},
			},
		},

		Expected: []string{
			`<hostdev mode="subsystem" type="mdev" model="vfio-pci">`,
			`  <source>`,
			`    <address uuid="53764d0e-85a0-42b4-af5c-2046b460b1dc"></address>`,
			`  </source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			CapsStorage: &DomainHostdevCapsStorage{
				Source: &DomainHostdevCapsStorageSource{
					Block: "/dev/sda",
				},
			},
		},

		Expected: []string{
			`<hostdev mode="capabilities" type="storage">`,
			`  <source>`,
			`    <block>/dev/sda</block>`,
			`  </source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			CapsMisc: &DomainHostdevCapsMisc{
				Source: &DomainHostdevCapsMiscSource{
					Char: "/dev/kvm",
				},
			},
		},

		Expected: []string{
			`<hostdev mode="capabilities" type="misc">`,
			`  <source>`,
			`    <char>/dev/kvm</char>`,
			`  </source>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainHostdev{
			CapsNet: &DomainHostdevCapsNet{
				Source: &DomainHostdevCapsNetSource{
					Interface: "eth0",
				},
				IP: []DomainIP{
					DomainIP{
						Address: "192.168.122.2",
						Family:  "ipv4",
					},
					DomainIP{
						Address: "2003:db8:1:0:214:1234:fe0b:3596",
						Family:  "ipv6",
						Prefix:  &ipv6Prefix,
					},
				},
				Route: []DomainRoute{
					DomainRoute{
						Family:  "ipv4",
						Address: "0.0.0.0",
						Gateway: "192.168.122.1",
					},
					DomainRoute{
						Family:  "ipv6",
						Address: "::",
						Gateway: "2003:db8:1:0:214:1234:fe0b:3595",
					},
				},
			},
		},

		Expected: []string{
			`<hostdev mode="capabilities" type="net">`,
			`  <source>`,
			`    <interface>eth0</interface>`,
			`  </source>`,
			`  <ip address="192.168.122.2" family="ipv4"></ip>`,
			`  <ip address="2003:db8:1:0:214:1234:fe0b:3596" family="ipv6" prefix="24"></ip>`,
			`  <route family="ipv4" address="0.0.0.0" gateway="192.168.122.1"></route>`,
			`  <route family="ipv6" address="::" gateway="2003:db8:1:0:214:1234:fe0b:3595"></route>`,
			`</hostdev>`,
		},
	},
	{
		Object: &DomainMemorydev{
			Model:  "dimm",
			Access: "private",
			Source: &DomainMemorydevSource{
				PageSize: &DomainMemorydevSourcePagesize{
					Value: 2048,
					Unit:  "KiB",
				},
				Path:     "/tmp/nvdimm",
				NodeMask: "0-1",
			},
			Target: &DomainMemorydevTarget{
				Size: &DomainMemorydevTargetSize{
					Value: 1,
					Unit:  "GiB",
				},
				Node: &DomainMemorydevTargetNode{
					Value: 0,
				},
				Label: &DomainMemorydevTargetLabel{
					Size: &DomainMemorydevTargetSize{
						Value: 200,
						Unit:  "KiB",
					},
				},
			},
		},

		Expected: []string{
			`<memory model="dimm" access="private">`,
			`  <source>`,
			`    <nodemask>0-1</nodemask>`,
			`    <pagesize unit="KiB">2048</pagesize>`,
			`    <path>/tmp/nvdimm</path>`,
			`  </source>`,
			`  <target>`,
			`    <size unit="GiB">1</size>`,
			`    <node>0</node>`,
			`    <label>`,
			`      <size unit="KiB">200</size>`,
			`    </label>`,
			`  </target>`,
			`</memory>`,
		},
	},
	/* Host Bootloader -- bhyve, Xen */
	{
		Object: &Domain{
			Type:           "bhyve",
			Name:           "test",
			Bootloader:     "/usr/local/sbin/grub-bhyve",
			BootloaderArgs: "-r cd0 -m /tmp/test-device.map -M 1024M linuxguest",
		},
		Expected: []string{
			`<domain type="bhyve">`,
			`  <name>test</name>`,
			`  <bootloader>/usr/local/sbin/grub-bhyve</bootloader>`,
			`  <bootloader_args>-r cd0 -m /tmp/test-device.map -M 1024M linuxguest</bootloader_args>`,
			`</domain>`,
		},
	},
	{
		Object: &Domain{
			Name: "demo",
			Devices: &DomainDeviceList{
				Graphics: []DomainGraphic{
					DomainGraphic{SDL: &DomainGraphicSDL{}},
					DomainGraphic{VNC: &DomainGraphicVNC{}},
					DomainGraphic{RDP: &DomainGraphicRDP{}},
					DomainGraphic{Desktop: &DomainGraphicDesktop{}},
					DomainGraphic{Spice: &DomainGraphicSpice{}},
				},
			},
		},
		Expected: []string{
			`<domain>`,
			`  <name>demo</name>`,
			`  <devices>`,
			`    <graphics type="sdl"></graphics>`,
			`    <graphics type="vnc"></graphics>`,
			`    <graphics type="rdp"></graphics>`,
			`    <graphics type="desktop"></graphics>`,
			`    <graphics type="spice"></graphics>`,
			`  </devices>`,
			`</domain>`,
		},
	},
}

func TestDomain(t *testing.T) {
	for _, test := range domainTestData {
		doc, err := test.Object.Marshal()
		if err != nil {
			t.Fatal(err)
		}

		expect := strings.Join(test.Expected, "\n")

		if doc != expect {
			t.Fatal("Bad initial xml:\n", string(doc), "\n does not match\n", expect, "\n")
		}

		typ := reflect.ValueOf(test.Object).Elem().Type()

		newobj := reflect.New(typ)

		newdocobj, ok := newobj.Interface().(Document)
		if !ok {
			t.Fatalf("Could not clone %s", newobj.Interface())
		}

		err = newdocobj.Unmarshal(expect)
		if err != nil {
			t.Fatal(err)
		}

		doc, err = newdocobj.Marshal()
		if err != nil {
			t.Fatal(err)
		}

		if doc != expect {
			t.Fatal("Bad roundtrip xml:\n", string(doc), "\n does not match\n", expect, "\n")
		}
	}
}
