# Re: [libvirt] [PATCH 0/3] libxl: Add a test suite for libxl_domain_config generator

• From: Jim Fehlig <jfehlig suse com>
• To: Marek Marczykowski-Górecki <marmarek invisiblethingslab com>
• Cc: libvir-list redhat com
• Subject: Re: [libvirt] [PATCH 0/3] libxl: Add a test suite for libxl_domain_config generator
• Date: Fri, 14 Jul 2017 17:59:57 -0600

```On 07/01/2017 08:16 PM, Marek Marczykowski-Górecki wrote:
```
```On Sun, Feb 26, 2017 at 07:02:24PM -0700, Jim Fehlig wrote:
```
```Long ago danpb posted some patches to test libvirt domXML to
libxl_domain_config conversion

https://www.redhat.com/archives/libvir-list/2014-May/msg01102.html

Some of the prerequisite patches were pushed, but we've never managed
to push patches actually providing the conversion tests. I sent several
follow-ups to Dan's work but never converged on a satisfactory solution
for all the Xen versions supported by libvirt. The last attempt was in
Sept 2014

https://www.redhat.com/archives/libvir-list/2014-September/msg00698.html

I tried to revive the work in Jan 2015, but that also stalled

https://www.redhat.com/archives/libvir-list/2015-January/msg00924.html

Fast-forward over 2.5 years from the first attempt and libvirt no longer
supports older Xen versions 4.2 and 4.3 that were proving to be problematic.
Starting with Xen 4.5 libxl added support for libxl_domain_config_from_json,
which provides a way to implement the conversion tests that work with all
Xen versions >= 4.5 (including latest xen.git master).
```
```
Few more months have passed...
```
```
```
And a few more weeks :-). Sorry for the delay. Slowly catching up on libvirt mail after some time away...
```
```
```
FWIW, I've tested it with Xen 4.6. The patch needs very minor update:
- add xencaps argument to libxlBuildDomainConfig cal >

After that, it works! When I made some test to fail, reported error is
not so helpful ("libvirt: Xen Light Driver error : internal error:
Expected and actual libxl_domain_config objects do not compare"), but it
do catch failures.
Then, if I change strcmp to virTestCompareToString, the output is much
```
```
```
Thanks for the improvements. I noticed you included them in your V2 of patch 3/3. I assume you needed patches 1 and 2 as well?
```
```
```I'd really love to have it merged, mostly because I want to add more tests
using this framework (see "Add setting CPU features (CPUID) with
```
```
```
I really dislike patches 1 and 2. They remove very useful checks IMO. Shortly after posting the series in Feb, I tried mocking the emulator checks. I failed quite a bit before coming up with something that worked, yet not so satisfying :-). I'll attach the (now rather old) patches for reference.
```
> Is there anything I can do to make it happen?

```
Do you have time to update these old patches, test, and repost to the list? Or perhaps have better ideas on mocking, or approaches that avoid the need for 1/3 and 2/3.
```
Regards,
Jim

```
```>From 1c57fc09689148e3f51718900d9c270062120fb8 Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig suse com>
Date: Mon, 20 Mar 2017 16:18:31 -0600
Subject: [PATCH 1/2] libxl: make emulator checks mockable

Experimenting with the idea of making emulator checks macros that can be
redefined in test code.

Signed-off-by: Jim Fehlig <jfehlig suse com>
---
src/libxl/libxl_capabilities.c | 68 +++++++++++++++++++++++++++++-------------
src/libxl/libxl_capabilities.h |  5 +++-
src/libxl/libxl_conf.c         | 17 ++---------
src/libxl/libxl_domain.c       |  2 +-
4 files changed, 56 insertions(+), 36 deletions(-)

diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c
index 839a2ee81..938e4a78f 100644
--- a/src/libxl/libxl_capabilities.c
+++ b/src/libxl/libxl_capabilities.c
@@ -727,33 +727,61 @@ libxlMakeDomainCapabilities(virDomainCapsPtr domCaps,

#define LIBXL_QEMU_DM_STR  "Options specific to the Xen version:"

+#define LIBXL_EMULATOR_TYPE()                                                  \
+{                                                                              \
+    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {                               \
+        if (def->emulator) {                                                   \
+            if (virFileExists(def->emulator)) {                                \
+                virCommandPtr cmd = NULL;                                      \
+                char *output = NULL;                                           \
+                                                                               \
+                cmd = virCommandNew(def->emulator);                            \
+                                                                               \
+                virCommandSetOutputBuffer(cmd, &output);                       \
+                                                                               \
+                if (virCommandRun(cmd, NULL) == 0) {                           \
+                    if (strstr(output, LIBXL_QEMU_DM_STR))                     \
+                }                                                              \
+                VIR_FREE(output);                                              \
+                virCommandFree(cmd);                                           \
+            }                                                                  \
+        }                                                                      \
+    }                                                                          \
+}
+
int
-libxlDomainGetEmulatorType(const virDomainDef *def)
+libxlGetEmulatorType(const virDomainDef *def)
{
int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
-    virCommandPtr cmd = NULL;
-    char *output = NULL;

-    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
-        if (def->emulator) {
-            if (!virFileExists(def->emulator))
-                goto cleanup;
-
-            cmd = virCommandNew(def->emulator);
+    LIBXL_EMULATOR_TYPE();
+    return ret;
+}

-            virCommandSetOutputBuffer(cmd, &output);
+#define LIBXL_CHECK_EMULATOR()                               \
+{                                                            \
+    if (!virFileExists(def->emulator)) {                     \
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,           \
+                       def->emulator);                       \
+    }                                                        \
+                                                             \
+    if (!virFileIsExecutable(def->emulator)) {               \
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,           \
+                       _("emulator '%s' is not executable"), \
+                       def->emulator);                       \
+    }                                                        \
+    ret = 0;                                                 \
+}

-            if (virCommandRun(cmd, NULL) < 0)
-                goto cleanup;
+int
+libxlCheckEmulator(const virDomainDef *def)
+{
+    int ret = -1;

-            if (strstr(output, LIBXL_QEMU_DM_STR))
-        }
-    }
+    LIBXL_CHECK_EMULATOR();

- cleanup:
-    VIR_FREE(output);
-    virCommandFree(cmd);
return ret;
}
diff --git a/src/libxl/libxl_capabilities.h b/src/libxl/libxl_capabilities.h
index 992b78077..4a7994f33 100644
--- a/src/libxl/libxl_capabilities.h
+++ b/src/libxl/libxl_capabilities.h
@@ -52,6 +52,9 @@ libxlMakeDomainCapabilities(virDomainCapsPtr domCaps,
size_t nfirmwares);

int
-libxlDomainGetEmulatorType(const virDomainDef *def);
+libxlGetEmulatorType(const virDomainDef *def);
+
+int
+libxlCheckEmulator(const virDomainDef *def);

#endif /* LIBXL_CAPABILITIES_H */
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index 4bab651b3..11b7066e1 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -435,25 +435,14 @@ libxlMakeDomBuildInfo(virDomainDefPtr def,
b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF;

if (def->emulator) {
-            if (!virFileExists(def->emulator)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               def->emulator);
+            if (libxlCheckEmulator(def) < 0)
return -1;
-            }
-
-            if (!virFileIsExecutable(def->emulator)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               _("emulator '%s' is not executable"),
-                               def->emulator);
-                return -1;
-            }

VIR_FREE(b_info->device_model);
if (VIR_STRDUP(b_info->device_model, def->emulator) < 0)
return -1;

-            b_info->device_model_version = libxlDomainGetEmulatorType(def);
+            b_info->device_model_version = libxlGetEmulatorType(def);
}

if (def->nserials) {
@@ -1974,7 +1963,7 @@ libxlMakeVideo(virDomainDefPtr def, libxl_domain_config *d_config)

{
libxl_domain_build_info *b_info = &d_config->b_info;
-    int dm_type = libxlDomainGetEmulatorType(def);
+    int dm_type = libxlGetEmulatorType(def);

if (d_config->c_info.type != LIBXL_DOMAIN_TYPE_HVM)
return 0;
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index ea28c9334..7b79004f0 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -335,7 +335,7 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
}

if (dev->type == VIR_DOMAIN_DEVICE_VIDEO && def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
-        int dm_type = libxlDomainGetEmulatorType(def);
+        int dm_type = libxlGetEmulatorType(def);

switch (dev->data.video->type) {
case VIR_DOMAIN_VIDEO_TYPE_VGA:
--
2.13.1

```
```>From da0a52c14cbca5f81c349d030b4d19c59233de82 Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig suse com>
Date: Wed, 22 Feb 2017 16:20:29 -0700
Subject: [PATCH 2/2] libxl: Add a test suite for libxl_domain_config generator

The libxl library allows a libxl_domain_config object to be serialized
from/to a JSON string. Use this to allow testing of the XML to
libxl_domain_config conversion process. Test XML is converted to
libxl_domain_config, which is then serialized to json. A json template
corresponding to the test XML is converted to a libxl_domain_config
object using libxl_domain_config_from_json(), and then serialized
back to json using libxl_domain_config_to_json(). The two json
docs are then compared.

Using libxl to convert the json template to a libxl_domain_config
object and then back to json provides a simple way to account for
any changes or additions to the json representation across Xen
releases.

Signed-off-by: Jim Fehlig <jfehlig suse com>
---
m4/virt-driver-libxl.m4                        |   6 +-
tests/Makefile.am                              |  18 +-
tests/libxlxml2domconfigdata/basic-hvm.json    |  89 ++++++++++
tests/libxlxml2domconfigdata/basic-hvm.xml     |  36 ++++
tests/libxlxml2domconfigdata/basic-pv.json     |  65 ++++++++
tests/libxlxml2domconfigdata/basic-pv.xml      |  28 ++++
tests/libxlxml2domconfigdata/moredevs-hvm.json | 111 +++++++++++++
tests/libxlxml2domconfigdata/moredevs-hvm.xml  |  63 +++++++
tests/libxlxml2domconfigtest.c                 | 222 +++++++++++++++++++++++++
tests/virmocklibxl.c                           |  87 ++++++++++
10 files changed, 722 insertions(+), 3 deletions(-)
create mode 100644 tests/libxlxml2domconfigdata/basic-hvm.json
create mode 100644 tests/libxlxml2domconfigdata/basic-hvm.xml
create mode 100644 tests/libxlxml2domconfigdata/basic-pv.json
create mode 100644 tests/libxlxml2domconfigdata/basic-pv.xml
create mode 100644 tests/libxlxml2domconfigdata/moredevs-hvm.json
create mode 100644 tests/libxlxml2domconfigdata/moredevs-hvm.xml
create mode 100644 tests/libxlxml2domconfigtest.c
create mode 100644 tests/virmocklibxl.c

diff --git a/m4/virt-driver-libxl.m4 b/m4/virt-driver-libxl.m4
index 96a9d4736..3d635f0a6 100644
--- a/m4/virt-driver-libxl.m4
+++ b/m4/virt-driver-libxl.m4
@@ -35,7 +35,7 @@ AC_DEFUN([LIBVIRT_DRIVER_CHECK_LIBXL], [
if test "x\$with_libxl" = "xyes" ; then
LIBXL_FIRMWARE_DIR=\$(\$PKG_CONFIG --variable xenfirmwaredir xenlight)
LIBXL_EXECBIN_DIR=\$(\$PKG_CONFIG --variable libexec_bin xenlight)
-  fi
+ fi

if test "x\$with_libxl" = "xno" ; then
@@ -80,6 +80,10 @@ AC_DEFUN([LIBVIRT_DRIVER_CHECK_LIBXL], [
LIBXL_LIBS="\$LIBXL_LIBS -lxenctrl"
])

+    dnl Check if libxl_domain_config_from_json is available for domXML to
+    dnl libxl_domain_config tests
+    LIBS="\$LIBS -lxenlight -lxenctrl"
+    AC_CHECK_FUNCS([libxl_domain_config_from_json])
CFLAGS="\$old_CFLAGS"
LIBS="\$old_LIBS"
fi
diff --git a/tests/Makefile.am b/tests/Makefile.am
index af69a3a84..34a17dbaa 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -100,6 +100,7 @@ EXTRA_DIST =		\
genericxml2xmlindata \
genericxml2xmloutdata \
+	libxlxml2domconfigdata \
lxcconf2xmldata \
lxcxml2xmldata \
lxcxml2xmloutdata \
@@ -268,7 +269,8 @@ test_programs += xml2sexprtest sexpr2xmltest \
endif WITH_XEN

if WITH_LIBXL
-test_programs += xlconfigtest
+test_programs += xlconfigtest libxlxml2domconfigtest
+test_libraries += virmocklibxl.la
endif WITH_LIBXL

if WITH_QEMU
@@ -522,8 +524,20 @@ xlconfigtest_SOURCES = \
xlconfigtest.c testutilsxen.c testutilsxen.h \
testutils.c testutils.h
+
+libxlxml2domconfigtest_SOURCES = \
+	libxlxml2domconfigtest.c testutilsxen.c testutilsxen.h \
+	testutils.c testutils.h
+
+virmocklibxl_la_SOURCES = \
+	virmocklibxl.c
+virmocklibxl_la_CFLAGS = \$(AM_CFLAGS)
+virmocklibxl_la_LDFLAGS = -module -avoid-version \
+        -rpath /evil/libtool/hack/to/force/shared/lib/creation
+
else ! WITH_LIBXL
-EXTRA_DIST += xlconfigtest.c
+EXTRA_DIST += xlconfigtest.c libxlxml2domconfigtest.c
endif ! WITH_LIBXL

QEMUMONITORTESTUTILS_SOURCES = \
diff --git a/tests/libxlxml2domconfigdata/basic-hvm.json b/tests/libxlxml2domconfigdata/basic-hvm.json
new file mode 100644
index 000000000..e4771920e
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/basic-hvm.json
@@ -0,0 +1,89 @@
+{
+    "c_info": {
+        "type": "hvm",
+        "name": "test-hvm",
+        "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+    },
+    "b_info": {
+        "max_vcpus": 4,
+        "avail_vcpus": [
+            0,
+            1,
+            2,
+            3
+        ],
+        "max_memkb": 1048576,
+        "target_memkb": 1048576,
+        "video_memkb": 8192,
+        "device_model_version": "qemu_xen",
+        "device_model": "/usr/lib/xen/bin/qemu-system-i386",
+        "sched_params": {
+            "weight": 1000
+        },
+        "type.hvm": {
+            "pae": "True",
+            "apic": "True",
+            "acpi": "True",
+            "vga": {
+                "kind": "cirrus"
+            },
+            "vnc": {
+                "enable": "True",
+                "listen": "0.0.0.0",
+                "findunused": "False"
+            },
+            "sdl": {
+                "enable": "False"
+            },
+            "spice": {
+
+            },
+            "boot": "c",
+            "rdm": {
+
+            }
+        },
+        "arch_arm": {
+
+        }
+    },
+    "disks": [
+        {
+            "pdev_path": "/var/lib/xen/images/test-hvm.img",
+            "vdev": "hda",
+            "backend": "qdisk",
+            "format": "raw",
+            "removable": 1,
+        }
+    ],
+    "nics": [
+        {
+            "devid": 0,
+            "mac": "00:16:3e:66:12:b4",
+            "bridge": "br0",
+            "script": "/etc/xen/scripts/vif-bridge",
+            "nictype": "vif_ioemu"
+        }
+    ],
+    "vfbs": [
+        {
+	    "devid": -1,
+            "vnc": {
+                "enable": "True",
+                "listen": "0.0.0.0",
+                "findunused": "False"
+            },
+            "sdl": {
+                "enable": "False"
+            }
+        }
+    ],
+    "vkbs": [
+        {
+            "devid": -1
+        }
+    ],
+    "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/basic-hvm.xml b/tests/libxlxml2domconfigdata/basic-hvm.xml
new file mode 100644
index 000000000..9dedf1729
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/basic-hvm.xml
@@ -0,0 +1,36 @@
+<domain type='xen'>
+  <name>test-hvm</name>
+  <description>None</description>
+  <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+  <memory>1048576</memory>
+  <currentMemory>1048576</currentMemory>
+  <vcpu>4</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <clock sync='utc'/>
+  <os>
+    <type>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <apic/>
+    <acpi/>
+    <pae/>
+  </features>
+  <devices>
+    <emulator>/usr/lib/xen/bin/qemu-system-i386</emulator>
+    <disk type='file' device='disk'>
+      <driver name='qemu'/>
+      <source file='/var/lib/xen/images/test-hvm.img'/>
+      <target dev='hda'/>
+    </disk>
+    <interface type='bridge'>
+      <source bridge='br0'/>
+      <script path='/etc/xen/scripts/vif-bridge'/>
+    </interface>
+    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+  </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigdata/basic-pv.json b/tests/libxlxml2domconfigdata/basic-pv.json
new file mode 100644
index 000000000..7e1abd3d6
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/basic-pv.json
@@ -0,0 +1,65 @@
+{
+    "c_info": {
+        "type": "pv",
+        "name": "test-pv",
+        "uuid": "039e9ee6-4a84-3055-4c81-8ba426ae2656"
+    },
+    "b_info": {
+        "max_vcpus": 4,
+        "avail_vcpus": [
+            0,
+            1,
+            2,
+            3
+        ],
+        "max_memkb": 524288,
+        "target_memkb": 524288,
+        "sched_params": {
+            "weight": 1000
+        },
+        "type.pv": {
+        },
+        "arch_arm": {
+
+        }
+    },
+    "disks": [
+        {
+            "pdev_path": "/var/lib/xen/images/test-pv.img",
+            "vdev": "xvda",
+            "backend": "qdisk",
+            "format": "raw",
+            "removable": 1,
+        }
+    ],
+    "nics": [
+        {
+            "devid": 0,
+            "mac": "00:16:3e:3e:86:60",
+            "bridge": "br0",
+            "script": "/etc/xen/scripts/vif-bridge",
+            "nictype": "vif"
+        }
+    ],
+    "vfbs": [
+        {
+	    "devid": -1,
+            "vnc": {
+                "enable": "True",
+                "listen": "0.0.0.0",
+                "findunused": "False"
+            },
+            "sdl": {
+                "enable": "False"
+            }
+        }
+    ],
+    "vkbs": [
+        {
+	    "devid": -1
+        }
+    ],
+    "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/basic-pv.xml b/tests/libxlxml2domconfigdata/basic-pv.xml
new file mode 100644
index 000000000..b3bc6012d
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/basic-pv.xml
@@ -0,0 +1,28 @@
+<domain type='xen'>
+  <name>test-pv</name>
+  <uuid>039e9ee6-4a84-3055-4c81-8ba426ae2656</uuid>
+  <memory>524288</memory>
+  <currentMemory>524288</currentMemory>
+  <vcpu>4</vcpu>
+  <os>
+    <type arch='i686' machine='xenpv'>linux</type>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu'/>
+      <source file='/var/lib/xen/images/test-pv.img'/>
+      <target dev='xvda'/>
+    </disk>
+    <interface type='bridge'>
+      <source bridge='br0'/>
+      <script path='/etc/xen/scripts/vif-bridge'/>
+    </interface>
+    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+  </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigdata/moredevs-hvm.json b/tests/libxlxml2domconfigdata/moredevs-hvm.json
new file mode 100644
index 000000000..70840d2b3
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/moredevs-hvm.json
@@ -0,0 +1,111 @@
+{
+    "c_info": {
+        "type": "hvm",
+        "hap": "True",
+        "name": "test-hvm",
+        "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+    },
+    "b_info": {
+        "max_vcpus": 4,
+        "avail_vcpus": [
+            0,
+            1,
+            2,
+            3
+        ],
+        "tsc_mode": "native",
+        "max_memkb": 1048576,
+        "target_memkb": 1048576,
+        "video_memkb": 8192,
+        "device_model_version": "qemu_xen",
+        "device_model": "/usr/lib/xen/bin/qemu-system-i386",
+        "sched_params": {
+            "weight": 1000
+        },
+        "type.hvm": {
+            "pae": "True",
+            "apic": "True",
+            "acpi": "True",
+            "hpet": "True",
+            "vga": {
+                "kind": "cirrus"
+            },
+            "vnc": {
+                "enable": "True",
+                "findunused": "False"
+            },
+            "sdl": {
+                "enable": "False"
+            },
+            "spice": {
+
+            },
+            "serial": "pty",
+            "boot": "c",
+            "usbdevice_list": [
+                "mouse",
+                "tablet"
+            ],
+            "rdm": {
+
+            }
+        },
+        "arch_arm": {
+
+        }
+    },
+    "disks": [
+        {
+            "pdev_path": "/var/lib/xen/images/test-hvm.img",
+            "vdev": "hda",
+            "backend": "qdisk",
+            "format": "raw",
+            "removable": 1,
+        },
+        {
+            "pdev_path": "/root/boot.iso",
+            "vdev": "hdb",
+            "backend": "qdisk",
+            "format": "raw",
+            "removable": 1,
+            "is_cdrom": 1
+        }
+    ],
+    "nics": [
+        {
+            "devid": 0,
+            "model": "netfront",
+            "mac": "00:16:3e:7a:35:ce",
+            "bridge": "br0",
+            "script": "/etc/xen/scripts/vif-bridge",
+            "nictype": "vif"
+        }
+    ],
+    "pcidevs": [
+        {
+            "dev": 16,
+            "bus": 10,
+	    "rdm_policy": "invalid"
+        }
+    ],
+    "vfbs": [
+        {
+	    "devid": -1,
+            "vnc": {
+                "enable": "True",
+                "findunused": "False"
+            },
+            "sdl": {
+                "enable": "False"
+            }
+        }
+    ],
+    "vkbs": [
+        {
+	    "devid": -1
+        }
+    ],
+    "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/moredevs-hvm.xml b/tests/libxlxml2domconfigdata/moredevs-hvm.xml
new file mode 100644
index 000000000..e93e153c5
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/moredevs-hvm.xml
@@ -0,0 +1,63 @@
+<domain type='xen'>
+  <name>test-hvm</name>
+  <description>None</description>
+  <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+  <memory>1048576</memory>
+  <currentMemory>1048576</currentMemory>
+  <vcpu>4</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+    <timer name='tsc' present='yes' mode='native'/>
+    <timer name='hpet' present='yes'/>
+  </clock>
+  <os>
+    <type>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <apic/>
+    <acpi/>
+    <pae/>
+    <hap/>
+  </features>
+  <devices>
+    <emulator>/usr/lib/xen/bin/qemu-system-i386</emulator>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='raw' cache='default'/>
+      <source file='/var/lib/xen/images/test-hvm.img'/>
+      <target dev='hda'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw' cache='default'/>
+      <source file='/root/boot.iso'/>
+      <target dev='hdb'/>
+    </disk>
+    <interface type='bridge'>
+      <source bridge='br0'/>
+      <script path='/etc/xen/scripts/vif-bridge'/>
+      <model type='netfront'/>
+    </interface>
+    <interface type='hostdev' managed='yes'>
+      <driver name='xen'/>
+      <source>
+        <address type='pci' domain='0x0000' bus='0x0a' slot='0x10' function='0x0'/>
+      </source>
+    </interface>
+    <graphics type='vnc'/>
+    <video>
+      <model type='cirrus' vram='8192' heads='1' primary='yes'/>
+    </video>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+    <input type='mouse' bus='usb'/>
+    <input type='tablet' bus='usb'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+  </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigtest.c b/tests/libxlxml2domconfigtest.c
new file mode 100644
index 000000000..2782eaf4a
--- /dev/null
+++ b/tests/libxlxml2domconfigtest.c
@@ -0,0 +1,222 @@
+/*
+ * libxlxml2domconfigtest.c: test conversion of domXML to
+ * libxl_domain_config structure.
+ *
+ * Copyright (C) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ *
+ * Author: Jim Fehlig <jfehlig suse com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "testutils.h"
+
+#if defined(WITH_LIBXL) && defined(WITH_YAJL) && defined(HAVE_LIBXL_DOMAIN_CONFIG_FROM_JSON)
+
+# include "internal.h"
+# include "viralloc.h"
+# include "libxl/libxl_conf.h"
+# include "datatypes.h"
+# include "virstring.h"
+# include "virmock.h"
+# include "virjson.h"
+# include "testutilsxen.h"
+
+# define VIR_FROM_THIS VIR_FROM_LIBXL
+
+static const char *abs_top_srcdir;
+static virCapsPtr xencaps;
+
+# ifdef LIBXL_EMULATOR_TYPE
+#  undef LIBXL_EMULATOR_TYPE
+#  define LIBXL_EMULATOR_TYPE
+# endif
+
+# ifdef LIBXL_CHECK_EMULATOR
+#  undef LIBXL_CHECK_EMULATOR
+#  undef LIBXL_CHECK_EMULATOR              \
+{                                         \
+    *ret = 0;                             \
+}
+# endif
+
+static int testCompareXMLToDomConfig(const char *xmlfile,
+                                     const char *jsonfile)
+{
+    int ret = -1;
+    libxl_domain_config actualconfig;
+    libxl_domain_config expectconfig;
+    xentoollog_logger *log = NULL;
+    libxl_ctx *ctx = NULL;
+    virPortAllocatorPtr gports = NULL;
+    virDomainXMLOptionPtr xmlopt = NULL;
+    virDomainDefPtr vmdef = NULL;
+    char *actualjson = NULL;
+    char *tempjson = NULL;
+    char *expectjson = NULL;
+
+    libxl_domain_config_init(&actualconfig);
+    libxl_domain_config_init(&expectconfig);
+
+    if (!(log = (xentoollog_logger *)xtl_createlogger_stdiostream(stderr, XTL_DEBUG, 0)))
+        goto cleanup;
+
+    if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, log) < 0)
+        goto cleanup;
+
+    if (!(gports = virPortAllocatorNew("vnc", 5900, 6000,
+                                       VIR_PORT_ALLOCATOR_SKIP_BIND_CHECK)))
+        goto cleanup;
+
+    if (!(xmlopt = libxlCreateXMLConf()))
+        goto cleanup;
+
+    if (!(vmdef = virDomainDefParseFile(xmlfile, xencaps, xmlopt,
+                                        NULL, VIR_DOMAIN_XML_INACTIVE)))
+        goto cleanup;
+
+    if (libxlBuildDomainConfig(gports, vmdef, NULL, ctx, &actualconfig) < 0)
+        goto cleanup;
+
+    if (!(actualjson = libxl_domain_config_to_json(ctx, &actualconfig))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "Failed to retrieve JSON doc for libxl_domain_config");
+        goto cleanup;
+    }
+    printf("\nlibvirt converted json:\n%s\n", actualjson);
+
+    if (libxl_domain_config_from_json(ctx, &expectconfig, tempjson) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "Failed to create libxl_domain_config from JSON doc");
+        goto cleanup;
+    }
+    if (!(expectjson = libxl_domain_config_to_json(ctx, &expectconfig))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "Failed to retrieve JSON doc for libxl_domain_config");
+        goto cleanup;
+    }
+    printf("\nlibxl converted json:\n%s\n", expectjson);
+
+    if (strcmp(expectjson, actualjson)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "Expected and actual libxl_domain_config objects do not compare");
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(expectjson);
+    VIR_FREE(actualjson);
+    VIR_FREE(tempjson);
+    virDomainDefFree(vmdef);
+    virObjectUnref(gports);
+    virObjectUnref(xmlopt);
+    libxl_ctx_free(ctx);
+    libxl_domain_config_dispose(&actualconfig);
+    libxl_domain_config_dispose(&expectconfig);
+    xtl_logger_destroy(log);
+    return ret;
+}
+
+
+struct testInfo {
+    const char *name;
+};
+
+
+static int
+testCompareXMLToDomConfigHelper(const void *data)
+{
+    int ret = -1;
+    const struct testInfo *info = data;
+    char *xmlfile = NULL;
+    char *jsonfile = NULL;
+
+    if (virAsprintf(&xmlfile, "%s/libxlxml2domconfigdata/%s.xml",
+                    abs_srcdir, info->name) < 0 ||
+        virAsprintf(&jsonfile, "%s/libxlxml2domconfigdata/%s.json",
+                    abs_srcdir, info->name) < 0)
+        goto cleanup;
+
+    ret = testCompareXMLToDomConfig(xmlfile, jsonfile);
+
+ cleanup:
+    VIR_FREE(xmlfile);
+    VIR_FREE(jsonfile);
+    return ret;
+}
+
+
+static int
+mymain(void)
+{
+    int ret = 0;
+
+    abs_top_srcdir = getenv("abs_top_srcdir");
+    if (!abs_top_srcdir)
+        abs_top_srcdir = abs_srcdir "/..";
+
+    /* Set the timezone because we are mocking the time() function.
+     * If we don't do that, then localtime() may return unpredictable
+     * results. In order to detect things that just work by a blind
+     * chance, we need to set an virtual timezone that no libvirt
+     * developer resides in. */
+    if (setenv("TZ", "VIR00:30", 1) < 0) {
+        perror("setenv");
+        return EXIT_FAILURE;
+    }
+
+    if ((xencaps = testXenCapsInit()) == NULL)
+        return EXIT_FAILURE;
+
+# define DO_TEST(name)                                                  \
+    do {                                                                \
+        static struct testInfo info = {                                 \
+            name,                                                       \
+        };                                                              \
+        if (virTestRun("LibXL XML-2-JSON " name,                        \
+                        testCompareXMLToDomConfigHelper, &info) < 0)    \
+            ret = -1;                                                   \
+    } while (0)
+
+    DO_TEST("basic-pv");
+    DO_TEST("basic-hvm");
+    DO_TEST("moredevs-hvm");
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+
+#else
+
+int main(void)
+{
+    return EXIT_AM_SKIP;
+}
+
+#endif /* WITH_LIBXL && WITH_YAJL && HAVE_LIBXL_DOMAIN_CONFIG_FROM_JSON */
diff --git a/tests/virmocklibxl.c b/tests/virmocklibxl.c
new file mode 100644
index 000000000..bc4b53d68
--- /dev/null
+++ b/tests/virmocklibxl.c
@@ -0,0 +1,87 @@
+/*
+ * virmocklibxl.c: mocking of xenstore/libxs for libxl
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ *
+ * Author: Daniel P. Berrange <berrange redhat com>
+ */
+
+#include <config.h>
+
+#if defined(WITH_LIBXL) && defined(WITH_YAJL)
+# include "virmock.h"
+# include <sys/stat.h>
+# include <unistd.h>
+# include <libxl.h>
+# include <xenstore.h>
+# include <xenctrl.h>
+
+VIR_MOCK_IMPL_RET_VOID(xs_daemon_open,
+                       struct xs_handle *)
+{
+    VIR_MOCK_REAL_INIT(xs_daemon_open);
+    return (void*)0x1;
+}
+
+VIR_MOCK_IMPL_RET_ARGS(xc_interface_open,
+                       xc_interface *,
+                       xentoollog_logger *, logger,
+                       xentoollog_logger *, dombuild_logger,
+                       unsigned, open_flags)
+{
+    VIR_MOCK_REAL_INIT(xc_interface_open);
+    return (void*)0x1;
+}
+
+
+VIR_MOCK_STUB_RET_ARGS(xc_interface_close,
+                       int, 0,
+                       xc_interface *, handle)
+
+VIR_MOCK_STUB_VOID_ARGS(xs_daemon_close,
+                        struct xs_handle *, handle)
+
+VIR_MOCK_IMPL_RET_ARGS(__xstat, int,
+                       int, ver,
+                       const char *, path,
+                       struct stat *, sb)
+{
+    VIR_MOCK_REAL_INIT(__xstat);
+
+    if (strstr(path, "xenstored.pid")) {
+        memset(sb, 0, sizeof(*sb));
+        return 0;
+    }
+
+    return real___xstat(ver, path, sb);
+}
+
+VIR_MOCK_IMPL_RET_ARGS(stat, int,
+                       const char *, path,
+                       struct stat *, sb)
+{
+    VIR_MOCK_REAL_INIT(stat);
+
+    if (strstr(path, "xenstored.pid")) {
+        memset(sb, 0, sizeof(*sb));
+        return 0;
+    }
+
+    return real_stat(path, sb);
+}
+
+#endif /* WITH_LIBXL && WITH_YAJL */
--
2.13.1

```