[PATCH] test driver: File test_driver.c was splitted into smaller files.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Because the file had over 7000 lines. Now its splitted into 5
smaller files. It looks clearer and it's better for reading the code.

Signed-off-by: Tomáš Ryšavý <tom.rysavy.0@xxxxxxxxx>
---
 po/POTFILES.in                    |    6 +-
 src/Makefile.am                   |    8 +-
 src/test/test_device_driver.c     |  462 +++
 src/test/test_device_driver.h     |    1 +
 src/test/test_driver.c            | 6924 +------------------------------------
 src/test/test_hypervisor_driver.c | 4152 ++++++++++++++++++++++
 src/test/test_hypervisor_driver.h |    1 +
 src/test/test_interface_driver.c  |  487 +++
 src/test/test_interface_driver.h  |    1 +
 src/test/test_network_driver.c    |  540 +++
 src/test/test_network_driver.h    |    1 +
 src/test/test_private_driver.h    |   70 +
 src/test/test_storage_driver.c    | 1517 ++++++++
 src/test/test_storage_driver.h    |    1 +
 14 files changed, 7259 insertions(+), 6912 deletions(-)
 create mode 100644 src/test/test_device_driver.c
 create mode 100644 src/test/test_device_driver.h
 create mode 100644 src/test/test_hypervisor_driver.c
 create mode 100644 src/test/test_hypervisor_driver.h
 create mode 100644 src/test/test_interface_driver.c
 create mode 100644 src/test/test_interface_driver.h
 create mode 100644 src/test/test_network_driver.c
 create mode 100644 src/test/test_network_driver.h
 create mode 100644 src/test/test_private_driver.h
 create mode 100644 src/test/test_storage_driver.c
 create mode 100644 src/test/test_storage_driver.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 25dbc84..5738c4e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -173,7 +173,11 @@ src/storage/storage_backend_scsi.c
 src/storage/storage_backend_sheepdog.c
 src/storage/storage_backend_zfs.c
 src/storage/storage_driver.c
-src/test/test_driver.c
+src/test/test_device_driver.c
+src/test/test_hypervisor_driver.c
+src/test/test_interface_driver.c
+src/test/test_network_driver.c
+src/test/test_storage_driver.c
 src/uml/uml_conf.c
 src/uml/uml_driver.c
 src/util/iohelper.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8ee5567..4cf01fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -689,7 +689,13 @@ check-local: check-protocol check-symfile check-symsorting \
 
 # Mock driver, covering domains, storage, networks, etc
 TEST_DRIVER_SOURCES =						\
-		test/test_driver.c test/test_driver.h
+		test/test_driver.c test/test_driver.h \
+		test/test_device_driver.c test/test_device_driver.h \
+		test/test_hypervisor_driver.c test/test_hypervisor_driver.h \
+		test/test_interface_driver.c test/test_interface_driver.h \
+		test/test_network_driver.c test/test_network_driver.h \
+		test/test_storage_driver.c test/test_storage_driver.h
+
 
 # Now the Hypervisor specific drivers
 XEN_DRIVER_SOURCES =						\
diff --git a/src/test/test_device_driver.c b/src/test/test_device_driver.c
new file mode 100644
index 0000000..1172bc5
--- /dev/null
+++ b/src/test/test_device_driver.c
@@ -0,0 +1,462 @@
+/*
+ * test_device_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_device_driver.h"
+
+#include "test_private_driver.h"
+
+/* Node device implementations */
+
+static int
+testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
+                                      virNodeDevicePtr dev,
+                                      int eventID,
+                                      virConnectNodeDeviceEventGenericCallback callback,
+                                      void *opaque,
+                                      virFreeCallback freecb)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret;
+
+    if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
+                                          dev, eventID, callback,
+                                          opaque, freecb, &ret) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int
+testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
+                                        int callbackID)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virObjectEventStateDeregisterID(conn, driver->eventState,
+                                        callbackID) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int
+testNodeNumOfDevices(virConnectPtr conn,
+                     const char *cap,
+                     unsigned int flags)
+{
+    testDriverPtr driver = conn->privateData;
+    int ndevs = 0;
+    size_t i;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(driver);
+    for (i = 0; i < driver->devs.count; i++)
+        if ((cap == NULL) ||
+            virNodeDeviceHasCap(driver->devs.objs[i], cap))
+            ++ndevs;
+    testDriverUnlock(driver);
+
+    return ndevs;
+}
+
+static int
+testNodeListDevices(virConnectPtr conn,
+                    const char *cap,
+                    char **const names,
+                    int maxnames,
+                    unsigned int flags)
+{
+    testDriverPtr driver = conn->privateData;
+    int ndevs = 0;
+    size_t i;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(driver);
+    for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
+        virNodeDeviceObjLock(driver->devs.objs[i]);
+        if (cap == NULL ||
+            virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
+            if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
+                virNodeDeviceObjUnlock(driver->devs.objs[i]);
+                goto failure;
+            }
+        }
+        virNodeDeviceObjUnlock(driver->devs.objs[i]);
+    }
+    testDriverUnlock(driver);
+
+    return ndevs;
+
+ failure:
+    testDriverUnlock(driver);
+    --ndevs;
+    while (--ndevs >= 0)
+        VIR_FREE(names[ndevs]);
+    return -1;
+}
+
+static virNodeDevicePtr
+testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
+{
+    testDriverPtr driver = conn->privateData;
+    virNodeDeviceObjPtr obj;
+    virNodeDevicePtr ret = NULL;
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       name);
+        goto cleanup;
+    }
+
+    ret = virGetNodeDevice(conn, name);
+
+ cleanup:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    return ret;
+}
+
+static char *
+testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
+                         unsigned int flags)
+{
+    testDriverPtr driver = dev->conn->privateData;
+    virNodeDeviceObjPtr obj;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       dev->name);
+        goto cleanup;
+    }
+
+    ret = virNodeDeviceDefFormat(obj->def);
+
+ cleanup:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    return ret;
+}
+
+static char *
+testNodeDeviceGetParent(virNodeDevicePtr dev)
+{
+    testDriverPtr driver = dev->conn->privateData;
+    virNodeDeviceObjPtr obj;
+    char *ret = NULL;
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       dev->name);
+        goto cleanup;
+    }
+
+    if (obj->def->parent) {
+        ignore_value(VIR_STRDUP(ret, obj->def->parent));
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("no parent for this device"));
+    }
+
+ cleanup:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    return ret;
+}
+
+
+static int
+testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
+{
+    testDriverPtr driver = dev->conn->privateData;
+    virNodeDeviceObjPtr obj;
+    virNodeDevCapsDefPtr caps;
+    int ncaps = 0;
+    int ret = -1;
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       dev->name);
+        goto cleanup;
+    }
+
+    for (caps = obj->def->caps; caps; caps = caps->next)
+        ++ncaps;
+    ret = ncaps;
+
+ cleanup:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    return ret;
+}
+
+
+static int
+testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
+{
+    testDriverPtr driver = dev->conn->privateData;
+    virNodeDeviceObjPtr obj;
+    virNodeDevCapsDefPtr caps;
+    int ncaps = 0;
+    int ret = -1;
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       dev->name);
+        goto cleanup;
+    }
+
+    for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
+        if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
+            goto cleanup;
+    }
+    ret = ncaps;
+
+ cleanup:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    if (ret == -1) {
+        --ncaps;
+        while (--ncaps >= 0)
+            VIR_FREE(names[ncaps]);
+    }
+    return ret;
+}
+
+static virNodeDevicePtr
+testNodeDeviceCreateXML(virConnectPtr conn,
+                        const char *xmlDesc,
+                        unsigned int flags)
+{
+    testDriverPtr driver = conn->privateData;
+    virNodeDeviceDefPtr def = NULL;
+    virNodeDeviceObjPtr obj = NULL;
+    char *wwnn = NULL, *wwpn = NULL;
+    int parent_host = -1;
+    virNodeDevicePtr dev = NULL;
+    virNodeDevCapsDefPtr caps;
+    virObjectEventPtr event = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(driver);
+
+    def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
+    if (def == NULL)
+        goto cleanup;
+
+    /* We run these next two simply for validation */
+    if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
+        goto cleanup;
+
+    if (virNodeDeviceGetParentHost(&driver->devs,
+                                   def->name,
+                                   def->parent,
+                                   &parent_host) == -1) {
+        goto cleanup;
+    }
+
+    /* 'name' is supposed to be filled in by the node device backend, which
+     * we don't have. Use WWPN instead. */
+    VIR_FREE(def->name);
+    if (VIR_STRDUP(def->name, wwpn) < 0)
+        goto cleanup;
+
+    /* Fill in a random 'host' and 'unique_id' value,
+     * since this would also come from the backend */
+    caps = def->caps;
+    while (caps) {
+        if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
+            continue;
+
+        caps->data.scsi_host.host = virRandomBits(10);
+        caps->data.scsi_host.unique_id = 2;
+        caps = caps->next;
+    }
+
+
+    if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
+        goto cleanup;
+    virNodeDeviceObjUnlock(obj);
+
+    event = virNodeDeviceEventLifecycleNew(def->name,
+                                           VIR_NODE_DEVICE_EVENT_CREATED,
+                                           0);
+
+    dev = virGetNodeDevice(conn, def->name);
+    def = NULL;
+ cleanup:
+    testDriverUnlock(driver);
+    virNodeDeviceDefFree(def);
+    testObjectEventQueue(driver, event);
+    VIR_FREE(wwnn);
+    VIR_FREE(wwpn);
+    return dev;
+}
+
+static int
+testNodeDeviceDestroy(virNodeDevicePtr dev)
+{
+    int ret = 0;
+    testDriverPtr driver = dev->conn->privateData;
+    virNodeDeviceObjPtr obj = NULL;
+    char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
+    int parent_host = -1;
+    virObjectEventPtr event = NULL;
+
+    testDriverLock(driver);
+    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+    testDriverUnlock(driver);
+
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NODE_DEVICE,
+                       _("no node device with matching name '%s'"),
+                       dev->name);
+        goto out;
+    }
+
+    if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
+        goto out;
+
+    if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
+        goto out;
+
+    /* virNodeDeviceGetParentHost will cause the device object's lock to be
+     * taken, so we have to dup the parent's name and drop the lock
+     * before calling it.  We don't need the reference to the object
+     * any more once we have the parent's name.  */
+    virNodeDeviceObjUnlock(obj);
+
+    /* We do this just for basic validation */
+    if (virNodeDeviceGetParentHost(&driver->devs,
+                                   dev->name,
+                                   parent_name,
+                                   &parent_host) == -1) {
+        obj = NULL;
+        goto out;
+    }
+
+    event = virNodeDeviceEventLifecycleNew(dev->name,
+                                           VIR_NODE_DEVICE_EVENT_DELETED,
+                                           0);
+
+    virNodeDeviceObjLock(obj);
+    virNodeDeviceObjRemove(&driver->devs, &obj);
+
+ out:
+    if (obj)
+        virNodeDeviceObjUnlock(obj);
+    testObjectEventQueue(driver, event);
+    VIR_FREE(parent_name);
+    VIR_FREE(wwnn);
+    VIR_FREE(wwpn);
+    return ret;
+}
+
+virNodeDeviceDriver testNodeDeviceDriver = {
+    .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
+    .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
+    .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
+    .nodeListDevices = testNodeListDevices, /* 0.7.2 */
+    .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
+    .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
+    .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
+    .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
+    .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
+    .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
+    .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
+};
diff --git a/src/test/test_device_driver.h b/src/test/test_device_driver.h
new file mode 100644
index 0000000..b5bd2bd
--- /dev/null
+++ b/src/test/test_device_driver.h
@@ -0,0 +1 @@
+extern virNodeDeviceDriver testNodeDeviceDriver;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 87799e1..c30ae29 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -65,113 +65,28 @@
 #include "virdomainobjlist.h"
 #include "virhostcpu.h"
 
-#define VIR_FROM_THIS VIR_FROM_TEST
+#include "test_hypervisor_driver.h"
+#include "test_storage_driver.h"
+#include "test_network_driver.h"
+#include "test_interface_driver.h"
+#include "test_device_driver.h"
 
-VIR_LOG_INIT("test.test_driver");
-
-
-#define MAX_CPUS 128
-
-struct _testCell {
-    unsigned long mem;
-    unsigned long freeMem;
-    int numCpus;
-    virCapsHostNUMACellCPU cpus[MAX_CPUS];
-};
-typedef struct _testCell testCell;
-typedef struct _testCell *testCellPtr;
-
-#define MAX_CELLS 128
-
-struct _testAuth {
-    char *username;
-    char *password;
-};
-typedef struct _testAuth testAuth;
-typedef struct _testAuth *testAuthPtr;
-
-struct _testDriver {
-    virMutex lock;
-
-    virNodeInfo nodeInfo;
-    virInterfaceObjList ifaces;
-    bool transaction_running;
-    virInterfaceObjList backupIfaces;
-    virStoragePoolObjList pools;
-    virNodeDeviceObjList devs;
-    int numCells;
-    testCell cells[MAX_CELLS];
-    size_t numAuths;
-    testAuthPtr auths;
-
-    /* virAtomic access only */
-    volatile int nextDomID;
-
-    /* immutable pointer, immutable object after being initialized with
-     * testBuildCapabilities */
-    virCapsPtr caps;
-
-    /* immutable pointer, immutable object */
-    virDomainXMLOptionPtr xmlopt;
-
-    /* immutable pointer, self-locking APIs */
-    virDomainObjListPtr domains;
-    virNetworkObjListPtr networks;
-    virObjectEventStatePtr eventState;
-};
-typedef struct _testDriver testDriver;
-typedef testDriver *testDriverPtr;
-
-static testDriverPtr defaultConn;
-static int defaultConnections;
-static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+#include "test_private_driver.h"
 
-#define TEST_MODEL "i686"
-#define TEST_EMULATOR "/usr/bin/test-hv"
-
-static const virNodeInfo defaultNodeInfo = {
-    TEST_MODEL,
-    1024*1024*3, /* 3 GB */
-    16,
-    1400,
-    2,
-    2,
-    2,
-    2,
-};
-
-static void
-testDriverFree(testDriverPtr driver)
-{
-    if (!driver)
-        return;
-
-    virObjectUnref(driver->caps);
-    virObjectUnref(driver->xmlopt);
-    virObjectUnref(driver->domains);
-    virNodeDeviceObjListFree(&driver->devs);
-    virObjectUnref(driver->networks);
-    virInterfaceObjListFree(&driver->ifaces);
-    virStoragePoolObjListFree(&driver->pools);
-    virObjectEventStateFree(driver->eventState);
-    virMutexUnlock(&driver->lock);
-    virMutexDestroy(&driver->lock);
-
-    VIR_FREE(driver);
-}
+VIR_LOG_INIT("test.test_driver");
 
 
-static void testDriverLock(testDriverPtr driver)
+void testDriverLock(testDriverPtr driver)
 {
     virMutexLock(&driver->lock);
 }
 
-static void testDriverUnlock(testDriverPtr driver)
+void testDriverUnlock(testDriverPtr driver)
 {
     virMutexUnlock(&driver->lock);
 }
 
-static void testObjectEventQueue(testDriverPtr driver,
+void testObjectEventQueue(testDriverPtr driver,
                                  virObjectEventPtr event)
 {
     if (!event)
@@ -180,6825 +95,14 @@ static void testObjectEventQueue(testDriverPtr driver,
     virObjectEventStateQueue(driver->eventState, event);
 }
 
-#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0";
-
-typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
-typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
-struct _testDomainNamespaceDef {
-    int runstate;
-    bool transient;
-    bool hasManagedSave;
-
-    unsigned int num_snap_nodes;
-    xmlNodePtr *snap_nodes;
-};
-
-static void
-testDomainDefNamespaceFree(void *data)
-{
-    testDomainNamespaceDefPtr nsdata = data;
-    size_t i;
-
-    if (!nsdata)
-        return;
-
-    for (i = 0; i < nsdata->num_snap_nodes; i++)
-        xmlFreeNode(nsdata->snap_nodes[i]);
-
-    VIR_FREE(nsdata->snap_nodes);
-    VIR_FREE(nsdata);
-}
-
-static int
-testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
-                            xmlNodePtr root ATTRIBUTE_UNUSED,
-                            xmlXPathContextPtr ctxt,
-                            void **data)
-{
-    testDomainNamespaceDefPtr nsdata = NULL;
-    xmlNodePtr *nodes = NULL;
-    int tmp, n;
-    size_t i;
-    unsigned int tmpuint;
-
-    if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
-                           BAD_CAST TEST_NAMESPACE_HREF) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to register xml namespace '%s'"),
-                       TEST_NAMESPACE_HREF);
-        return -1;
-    }
-
-    if (VIR_ALLOC(nsdata) < 0)
-        return -1;
-
-    n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
-    if (n < 0)
-        goto error;
-
-    if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
-        goto error;
-
-    for (i = 0; i < n; i++) {
-        xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
-        if (!newnode) {
-            virReportOOMError();
-            goto error;
-        }
-
-        nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
-        nsdata->num_snap_nodes++;
-    }
-    VIR_FREE(nodes);
-
-    tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
-    if (tmp == -1) {
-        virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
-        goto error;
-    }
-    nsdata->transient = tmp;
-
-    tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
-    if (tmp == -1) {
-        virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
-        goto error;
-    }
-    nsdata->hasManagedSave = tmp;
-
-    tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
-    if (tmp == 0) {
-        if (tmpuint >= VIR_DOMAIN_LAST) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("runstate '%d' out of range'"), tmpuint);
-            goto error;
-        }
-        nsdata->runstate = tmpuint;
-    } else if (tmp == -1) {
-        nsdata->runstate = VIR_DOMAIN_RUNNING;
-    } else if (tmp == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid runstate"));
-        goto error;
-    }
-
-    if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-            _("transient domain cannot have runstate 'shutoff'"));
-        goto error;
-    }
-    if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-            _("domain with managedsave data can only have runstate 'shutoff'"));
-        goto error;
-    }
-
-    *data = nsdata;
-    return 0;
-
- error:
-    VIR_FREE(nodes);
-    testDomainDefNamespaceFree(nsdata);
-    return -1;
-}
-
-static virCapsPtr
-testBuildCapabilities(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    virCapsPtr caps;
-    virCapsGuestPtr guest;
-    int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
-                          VIR_DOMAIN_OSTYPE_XEN };
-    size_t i, j;
-
-    if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
-        goto error;
-
-    if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
-        goto error;
-    if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
-        goto error;
-
-    if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
-        goto error;
-
-    caps->host.pagesSize[caps->host.nPagesSize++] = 4;
-    caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
-
-    for (i = 0; i < privconn->numCells; i++) {
-        virCapsHostNUMACellCPUPtr cpu_cells;
-        virCapsHostNUMACellPageInfoPtr pages;
-        size_t nPages;
-
-        if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
-            VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
-                VIR_FREE(cpu_cells);
-                goto error;
-            }
-
-        nPages = caps->host.nPagesSize;
-
-        memcpy(cpu_cells, privconn->cells[i].cpus,
-               sizeof(*cpu_cells) * privconn->cells[i].numCpus);
-
-        for (j = 0; j < nPages; j++)
-            pages[j].size = caps->host.pagesSize[j];
-
-        pages[0].avail = privconn->cells[i].mem / pages[0].size;
-
-        if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
-                                           privconn->cells[i].numCpus,
-                                           cpu_cells, 0, NULL, nPages, pages) < 0)
-            goto error;
-    }
-
-    for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
-        if ((guest = virCapabilitiesAddGuest(caps,
-                                             guest_types[i],
-                                             VIR_ARCH_I686,
-                                             TEST_EMULATOR,
-                                             NULL,
-                                             0,
-                                             NULL)) == NULL)
-            goto error;
-
-        if (virCapabilitiesAddGuestDomain(guest,
-                                          VIR_DOMAIN_VIRT_TEST,
-                                          NULL,
-                                          NULL,
-                                          0,
-                                          NULL) == NULL)
-            goto error;
-
-        if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
-            goto error;
-        if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
-            goto error;
-    }
-
-    caps->host.nsecModels = 1;
-    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
-        goto error;
-    if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
-        goto error;
-
-    if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
-        goto error;
-
-    return caps;
-
- error:
-    virObjectUnref(caps);
-    return NULL;
-}
-
-
-static testDriverPtr
-testDriverNew(void)
-{
-    virDomainXMLNamespace ns = {
-        .parse = testDomainDefNamespaceParse,
-        .free = testDomainDefNamespaceFree,
-    };
-    testDriverPtr ret;
-
-    if (VIR_ALLOC(ret) < 0)
-        return NULL;
-
-    if (virMutexInit(&ret->lock) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("cannot initialize mutex"));
-        goto error;
-    }
-
-    if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
-        !(ret->eventState = virObjectEventStateNew()) ||
-        !(ret->domains = virDomainObjListNew()) ||
-        !(ret->networks = virNetworkObjListNew()))
-        goto error;
-
-    virAtomicIntSet(&ret->nextDomID, 1);
-
-    return ret;
-
- error:
-    testDriverFree(ret);
-    return NULL;
-}
-
-
-static const char *defaultConnXML =
-"<node>"
-"<domain type='test'>"
-"  <name>test</name>"
-"  <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
-"  <memory>8388608</memory>"
-"  <currentMemory>2097152</currentMemory>"
-"  <vcpu>2</vcpu>"
-"  <os>"
-"    <type>hvm</type>"
-"  </os>"
-"</domain>"
-""
-"<network>"
-"  <name>default</name>"
-"  <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
-"  <bridge name='virbr0'/>"
-"  <forward/>"
-"  <ip address='192.168.122.1' netmask='255.255.255.0'>"
-"    <dhcp>"
-"      <range start='192.168.122.2' end='192.168.122.254'/>"
-"    </dhcp>"
-"  </ip>"
-"</network>"
-""
-"<interface type=\"ethernet\" name=\"eth1\">"
-"  <start mode=\"onboot\"/>"
-"  <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
-"  <mtu size=\"1492\"/>"
-"  <protocol family=\"ipv4\">"
-"    <ip address=\"192.168.0.5\" prefix=\"24\"/>"
-"    <route gateway=\"192.168.0.1\"/>"
-"  </protocol>"
-"</interface>"
-""
-"<pool type='dir'>"
-"  <name>default-pool</name>"
-"  <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
-"  <target>"
-"    <path>/default-pool</path>"
-"  </target>"
-"</pool>"
-""
-"<device>"
-"  <name>computer</name>"
-"  <capability type='system'>"
-"    <hardware>"
-"      <vendor>Libvirt</vendor>"
-"      <version>Test driver</version>"
-"      <serial>123456</serial>"
-"      <uuid>11111111-2222-3333-4444-555555555555</uuid>"
-"    </hardware>"
-"    <firmware>"
-"      <vendor>Libvirt</vendor>"
-"      <version>Test Driver</version>"
-"      <release_date>01/22/2007</release_date>"
-"    </firmware>"
-"  </capability>"
-"</device>"
-"<device>"
-"  <name>test-scsi-host-vport</name>"
-"  <parent>computer</parent>"
-"  <capability type='scsi_host'>"
-"    <host>1</host>"
-"    <capability type='fc_host'>"
-"      <wwnn>2000000012341234</wwnn>"
-"      <wwpn>1000000012341234</wwpn>"
-"    </capability>"
-"    <capability type='vport_ops'/>"
-"  </capability>"
-"</device>"
-"</node>";
-
-
-static const char *defaultPoolSourcesLogicalXML =
-"<sources>\n"
-"  <source>\n"
-"    <device path='/dev/sda20'/>\n"
-"    <name>testvg1</name>\n"
-"    <format type='lvm2'/>\n"
-"  </source>\n"
-"  <source>\n"
-"    <device path='/dev/sda21'/>\n"
-"    <name>testvg2</name>\n"
-"    <format type='lvm2'/>\n"
-"  </source>\n"
-"</sources>\n";
-
-static const char *defaultPoolSourcesNetFSXML =
-"<sources>\n"
-"  <source>\n"
-"    <host name='%s'/>\n"
-"    <dir path='/testshare'/>\n"
-"    <format type='nfs'/>\n"
-"  </source>\n"
-"</sources>\n";
-
-static const unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
-static const unsigned long long defaultPoolAlloc;
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
-static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
-
-static virDomainObjPtr
-testDomObjFromDomain(virDomainPtr domain)
-{
-    virDomainObjPtr vm;
-    testDriverPtr driver = domain->conn->privateData;
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-
-    vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
-    if (!vm) {
-        virUUIDFormat(domain->uuid, uuidstr);
-        virReportError(VIR_ERR_NO_DOMAIN,
-                       _("no domain with matching uuid '%s' (%s)"),
-                       uuidstr, domain->name);
-    }
-
-    return vm;
-}
-
-static char *
-testDomainGenerateIfname(virDomainDefPtr domdef)
-{
-    int maxif = 1024;
-    int ifctr;
-    size_t i;
-
-    for (ifctr = 0; ifctr < maxif; ++ifctr) {
-        char *ifname;
-        int found = 0;
-
-        if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
-            return NULL;
-
-        /* Generate network interface names */
-        for (i = 0; i < domdef->nnets; i++) {
-            if (domdef->nets[i]->ifname &&
-                STREQ(domdef->nets[i]->ifname, ifname)) {
-                found = 1;
-                break;
-            }
-        }
-
-        if (!found)
-            return ifname;
-        VIR_FREE(ifname);
-    }
-
-    virReportError(VIR_ERR_INTERNAL_ERROR,
-                   _("Exceeded max iface limit %d"), maxif);
-    return NULL;
-}
-
-static int
-testDomainGenerateIfnames(virDomainDefPtr domdef)
-{
-    size_t i = 0;
-
-    for (i = 0; i < domdef->nnets; i++) {
-        char *ifname;
-        if (domdef->nets[i]->ifname)
-            continue;
-
-        ifname = testDomainGenerateIfname(domdef);
-        if (!ifname)
-            return -1;
-
-        domdef->nets[i]->ifname = ifname;
-    }
-
-    return 0;
-}
-
-
-static void
-testDomainShutdownState(virDomainPtr domain,
-                        virDomainObjPtr privdom,
-                        virDomainShutoffReason reason)
-{
-    virDomainObjRemoveTransientDef(privdom);
-    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
-
-    if (domain)
-        domain->id = -1;
-}
-
-/* Set up domain runtime state */
-static int
-testDomainStartState(testDriverPtr privconn,
-                     virDomainObjPtr dom,
-                     virDomainRunningReason reason)
-{
-    int ret = -1;
-
-    virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
-    dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
-
-    if (virDomainObjSetDefTransient(privconn->caps,
-                                    privconn->xmlopt,
-                                    dom) < 0) {
-        goto cleanup;
-    }
-
-    dom->hasManagedSave = false;
-    ret = 0;
- cleanup:
-    if (ret < 0)
-        testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
-    return ret;
-}
-
-
-static char *testBuildFilename(const char *relativeTo,
-                               const char *filename)
-{
-    char *offset;
-    int baseLen;
-    char *ret;
-
-    if (!filename || filename[0] == '\0')
-        return NULL;
-    if (filename[0] == '/') {
-        ignore_value(VIR_STRDUP(ret, filename));
-        return ret;
-    }
-
-    offset = strrchr(relativeTo, '/');
-    if ((baseLen = (offset-relativeTo+1))) {
-        char *absFile;
-        int totalLen = baseLen + strlen(filename) + 1;
-        if (VIR_ALLOC_N(absFile, totalLen) < 0)
-            return NULL;
-        if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
-            VIR_FREE(absFile);
-            return NULL;
-        }
-        strcat(absFile, filename);
-        return absFile;
-    } else {
-        ignore_value(VIR_STRDUP(ret, filename));
-        return ret;
-    }
-}
-
-static xmlNodePtr
-testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
-{
-    xmlNodePtr ret = NULL;
-    xmlDocPtr doc = NULL;
-    char *absFile = NULL;
-    char *relFile = virXMLPropString(node, "file");
-
-    if (relFile != NULL) {
-        absFile = testBuildFilename(file, relFile);
-        VIR_FREE(relFile);
-        if (!absFile) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("resolving %s filename"), type);
-            return NULL;
-        }
-
-        if (!(doc = virXMLParse(absFile, NULL, type)))
-            goto error;
-
-        ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
-        if (!ret) {
-            virReportOOMError();
-            goto error;
-        }
-        xmlReplaceNode(node, ret);
-        xmlFreeNode(node);
-    } else {
-        ret = node;
-    }
-
- error:
-    xmlFreeDoc(doc);
-    VIR_FREE(absFile);
-    return ret;
-}
-
-static int
-testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
-{
-    char *str;
-    long l;
-    int ret;
-
-    ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->nodes = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu nodes value"));
-        goto error;
-    }
-
-    ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->sockets = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu sockets value"));
-        goto error;
-    }
-
-    ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->cores = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu cores value"));
-        goto error;
-    }
-
-    ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->threads = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu threads value"));
-        goto error;
-    }
-
-    nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
-                      nodeInfo->sockets * nodeInfo->nodes);
-    ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
-    if (ret == 0) {
-        if (l < nodeInfo->cpus)
-            nodeInfo->cpus = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu active value"));
-        goto error;
-    }
-    ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->mhz = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node cpu mhz value"));
-        goto error;
-    }
-
-    str = virXPathString("string(/node/cpu/model[1])", ctxt);
-    if (str != NULL) {
-        if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Model %s too big for destination"), str);
-            VIR_FREE(str);
-            goto error;
-        }
-        VIR_FREE(str);
-    }
-
-    ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
-    if (ret == 0) {
-        nodeInfo->memory = l;
-    } else if (ret == -2) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("invalid node memory value"));
-        goto error;
-    }
-
-    return 0;
- error:
-    return -1;
-}
-
-static int
-testParseDomainSnapshots(testDriverPtr privconn,
-                         virDomainObjPtr domobj,
-                         const char *file,
-                         xmlXPathContextPtr ctxt)
-{
-    size_t i;
-    int ret = -1;
-    testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
-    xmlNodePtr *nodes = nsdata->snap_nodes;
-
-    for (i = 0; i < nsdata->num_snap_nodes; i++) {
-        virDomainSnapshotObjPtr snap;
-        virDomainSnapshotDefPtr def;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
-                                                  "domainsnapshot");
-        if (!node)
-            goto error;
-
-        def = virDomainSnapshotDefParseNode(ctxt->doc, node,
-                                            privconn->caps,
-                                            privconn->xmlopt,
-                                            VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
-                                            VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
-                                            VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
-        if (!def)
-            goto error;
-
-        if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
-            virDomainSnapshotDefFree(def);
-            goto error;
-        }
-
-        if (def->current) {
-            if (domobj->current_snapshot) {
-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("more than one snapshot claims to be active"));
-                goto error;
-            }
-
-            domobj->current_snapshot = snap;
-        }
-    }
-
-    if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Snapshots have inconsistent relations for "
-                         "domain %s"), domobj->def->name);
-        goto error;
-    }
-
-    ret = 0;
- error:
-    return ret;
-}
-
-static int
-testParseDomains(testDriverPtr privconn,
-                 const char *file,
-                 xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-    virDomainObjPtr obj;
-
-    num = virXPathNodeSet("/node/domain", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        virDomainDefPtr def;
-        testDomainNamespaceDefPtr nsdata;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
-        if (!node)
-            goto error;
-
-        def = virDomainDefParseNode(ctxt->doc, node,
-                                    privconn->caps, privconn->xmlopt,
-                                    VIR_DOMAIN_DEF_PARSE_INACTIVE);
-        if (!def)
-            goto error;
-
-        if (testDomainGenerateIfnames(def) < 0 ||
-            !(obj = virDomainObjListAdd(privconn->domains,
-                                        def,
-                                        privconn->xmlopt,
-                                        0, NULL))) {
-            virDomainDefFree(def);
-            goto error;
-        }
-
-        if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
-            virObjectUnlock(obj);
-            goto error;
-        }
-
-        nsdata = def->namespaceData;
-        obj->persistent = !nsdata->transient;
-        obj->hasManagedSave = nsdata->hasManagedSave;
-
-        if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
-            if (testDomainStartState(privconn, obj,
-                                     VIR_DOMAIN_RUNNING_BOOTED) < 0) {
-                virObjectUnlock(obj);
-                goto error;
-            }
-        } else {
-            testDomainShutdownState(NULL, obj, 0);
-        }
-        virDomainObjSetState(obj, nsdata->runstate, 0);
-
-        virObjectUnlock(obj);
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testParseNetworks(testDriverPtr privconn,
-                  const char *file,
-                  xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-    virNetworkObjPtr obj;
-
-    num = virXPathNodeSet("/node/network", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        virNetworkDefPtr def;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
-        if (!node)
-            goto error;
-
-        def = virNetworkDefParseNode(ctxt->doc, node);
-        if (!def)
-            goto error;
-
-        if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
-            virNetworkDefFree(def);
-            goto error;
-        }
-
-        obj->active = 1;
-        virNetworkObjEndAPI(&obj);
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testParseInterfaces(testDriverPtr privconn,
-                    const char *file,
-                    xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-    virInterfaceObjPtr obj;
-
-    num = virXPathNodeSet("/node/interface", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        virInterfaceDefPtr def;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
-                                                   "interface");
-        if (!node)
-            goto error;
-
-        def = virInterfaceDefParseNode(ctxt->doc, node);
-        if (!def)
-            goto error;
-
-        if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
-            virInterfaceDefFree(def);
-            goto error;
-        }
-
-        obj->active = 1;
-        virInterfaceObjUnlock(obj);
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testOpenVolumesForPool(const char *file,
-                       xmlXPathContextPtr ctxt,
-                       virStoragePoolObjPtr pool,
-                       int poolidx)
-{
-    char *vol_xpath;
-    size_t i;
-    int num, ret = -1;
-    xmlNodePtr *nodes = NULL;
-    virStorageVolDefPtr def = NULL;
-
-    /* Find storage volumes */
-    if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
-        goto error;
-
-    num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
-    VIR_FREE(vol_xpath);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
-                                                   "volume");
-        if (!node)
-            goto error;
-
-        def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
-        if (!def)
-            goto error;
-
-        if (def->target.path == NULL) {
-            if (virAsprintf(&def->target.path, "%s/%s",
-                            pool->def->target.path,
-                            def->name) == -1)
-                goto error;
-        }
-
-        if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
-            goto error;
-        if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
-            goto error;
-
-        pool->def->allocation += def->target.allocation;
-        pool->def->available = (pool->def->capacity -
-                                pool->def->allocation);
-        def = NULL;
-    }
-
-    ret = 0;
- error:
-    virStorageVolDefFree(def);
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testParseStorage(testDriverPtr privconn,
-                 const char *file,
-                 xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-    virStoragePoolObjPtr obj;
-
-    num = virXPathNodeSet("/node/pool", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        virStoragePoolDefPtr def;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
-                                                   "pool");
-        if (!node)
-            goto error;
-
-        def = virStoragePoolDefParseNode(ctxt->doc, node);
-        if (!def)
-            goto error;
-
-        if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
-                                                def))) {
-            virStoragePoolDefFree(def);
-            goto error;
-        }
-
-        if (testStoragePoolObjSetDefaults(obj) == -1) {
-            virStoragePoolObjUnlock(obj);
-            goto error;
-        }
-        obj->active = 1;
-
-        /* Find storage volumes */
-        if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
-            virStoragePoolObjUnlock(obj);
-            goto error;
-        }
-
-        virStoragePoolObjUnlock(obj);
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testParseNodedevs(testDriverPtr privconn,
-                  const char *file,
-                  xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-    virNodeDeviceObjPtr obj;
-
-    num = virXPathNodeSet("/node/device", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        virNodeDeviceDefPtr def;
-        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
-                                                  "nodedev");
-        if (!node)
-            goto error;
-
-        def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
-        if (!def)
-            goto error;
-
-        if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
-            virNodeDeviceDefFree(def);
-            goto error;
-        }
-
-        virNodeDeviceObjUnlock(obj);
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testParseAuthUsers(testDriverPtr privconn,
-                   xmlXPathContextPtr ctxt)
-{
-    int num, ret = -1;
-    size_t i;
-    xmlNodePtr *nodes = NULL;
-
-    num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
-    if (num < 0)
-        goto error;
-
-    privconn->numAuths = num;
-    if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
-        goto error;
-
-    for (i = 0; i < num; i++) {
-        char *username, *password;
-
-        ctxt->node = nodes[i];
-        username = virXPathString("string(.)", ctxt);
-        if (!username || STREQ(username, "")) {
-            virReportError(VIR_ERR_XML_ERROR, "%s",
-                           _("missing username in /node/auth/user field"));
-            VIR_FREE(username);
-            goto error;
-        }
-        /* This field is optional. */
-        password = virXMLPropString(nodes[i], "password");
-
-        privconn->auths[i].username = username;
-        privconn->auths[i].password = password;
-    }
-
-    ret = 0;
- error:
-    VIR_FREE(nodes);
-    return ret;
-}
-
-static int
-testOpenParse(testDriverPtr privconn,
-              const char *file,
-              xmlXPathContextPtr ctxt)
-{
-    if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("Root element is not 'node'"));
-        goto error;
-    }
-
-    if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
-        goto error;
-    if (testParseDomains(privconn, file, ctxt) < 0)
-        goto error;
-    if (testParseNetworks(privconn, file, ctxt) < 0)
-        goto error;
-    if (testParseInterfaces(privconn, file, ctxt) < 0)
-        goto error;
-    if (testParseStorage(privconn, file, ctxt) < 0)
-        goto error;
-    if (testParseNodedevs(privconn, file, ctxt) < 0)
-        goto error;
-    if (testParseAuthUsers(privconn, ctxt) < 0)
-        goto error;
+unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
+unsigned long long defaultPoolAlloc;
 
-    return 0;
- error:
-    return -1;
-}
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
 
 /* No shared state between simultaneous test connections initialized
  * from a file.  */
-static int
-testOpenFromFile(virConnectPtr conn, const char *file)
-{
-    xmlDocPtr doc = NULL;
-    xmlXPathContextPtr ctxt = NULL;
-    testDriverPtr privconn;
-
-    if (!(privconn = testDriverNew()))
-        return VIR_DRV_OPEN_ERROR;
-
-    testDriverLock(privconn);
-    conn->privateData = privconn;
-
-    if (!(privconn->caps = testBuildCapabilities(conn)))
-        goto error;
-
-    if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
-        goto error;
-
-    privconn->numCells = 0;
-    memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
-    if (testOpenParse(privconn, file, ctxt) < 0)
-        goto error;
-
-    xmlXPathFreeContext(ctxt);
-    xmlFreeDoc(doc);
-    testDriverUnlock(privconn);
-
-    return 0;
-
- error:
-    xmlXPathFreeContext(ctxt);
-    xmlFreeDoc(doc);
-    testDriverFree(privconn);
-    conn->privateData = NULL;
-    return VIR_DRV_OPEN_ERROR;
-}
-
-/* Simultaneous test:///default connections should share the same
- * common state (among other things, this allows testing event
- * detection in one connection for an action caused in another).  */
-static int
-testOpenDefault(virConnectPtr conn)
-{
-    int u;
-    testDriverPtr privconn = NULL;
-    xmlDocPtr doc = NULL;
-    xmlXPathContextPtr ctxt = NULL;
-
-    virMutexLock(&defaultLock);
-    if (defaultConnections++) {
-        conn->privateData = defaultConn;
-        virMutexUnlock(&defaultLock);
-        return VIR_DRV_OPEN_SUCCESS;
-    }
-
-    if (!(privconn = testDriverNew()))
-        goto error;
-
-    conn->privateData = privconn;
-
-    memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
-    /* Numa setup */
-    privconn->numCells = 2;
-    for (u = 0; u < privconn->numCells; ++u) {
-        privconn->cells[u].numCpus = 8;
-        privconn->cells[u].mem = (u + 1) * 2048 * 1024;
-        privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
-    }
-    for (u = 0; u < 16; u++) {
-        virBitmapPtr siblings = virBitmapNew(16);
-        if (!siblings)
-            goto error;
-        ignore_value(virBitmapSetBit(siblings, u));
-        privconn->cells[u / 8].cpus[(u % 8)].id = u;
-        privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
-        privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
-        privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
-    }
-
-    if (!(privconn->caps = testBuildCapabilities(conn)))
-        goto error;
-
-    if (!(doc = virXMLParseStringCtxt(defaultConnXML,
-                                      _("(test driver)"), &ctxt)))
-        goto error;
-
-    if (testOpenParse(privconn, NULL, ctxt) < 0)
-        goto error;
-
-    defaultConn = privconn;
-
-    xmlXPathFreeContext(ctxt);
-    xmlFreeDoc(doc);
-    virMutexUnlock(&defaultLock);
-
-    return VIR_DRV_OPEN_SUCCESS;
-
- error:
-    testDriverFree(privconn);
-    xmlXPathFreeContext(ctxt);
-    xmlFreeDoc(doc);
-    conn->privateData = NULL;
-    defaultConnections--;
-    virMutexUnlock(&defaultLock);
-    return VIR_DRV_OPEN_ERROR;
-}
-
-static int
-testConnectAuthenticate(virConnectPtr conn,
-                        virConnectAuthPtr auth)
-{
-    testDriverPtr privconn = conn->privateData;
-    int ret = -1;
-    ssize_t i;
-    char *username = NULL, *password = NULL;
-
-    if (privconn->numAuths == 0)
-        return 0;
-
-    /* Authentication is required because the test XML contains a
-     * non-empty <auth/> section.  First we must ask for a username.
-     */
-    username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
-    if (!username) {
-        virReportError(VIR_ERR_AUTH_FAILED, "%s",
-                       _("authentication failed when asking for username"));
-        goto cleanup;
-    }
-
-    /* Does the username exist? */
-    for (i = 0; i < privconn->numAuths; ++i) {
-        if (STREQ(privconn->auths[i].username, username))
-            goto found_user;
-    }
-    i = -1;
-
- found_user:
-    /* Even if we didn't find the user, we still ask for a password. */
-    if (i == -1 || privconn->auths[i].password != NULL) {
-        password = virAuthGetPassword(conn, auth, "test",
-                                      username, "localhost");
-        if (password == NULL) {
-            virReportError(VIR_ERR_AUTH_FAILED, "%s",
-                           _("authentication failed when asking for password"));
-            goto cleanup;
-        }
-    }
-
-    if (i == -1 ||
-        (password && STRNEQ(privconn->auths[i].password, password))) {
-        virReportError(VIR_ERR_AUTH_FAILED, "%s",
-                       _("authentication failed, see test XML for the correct username/password"));
-        goto cleanup;
-    }
-
-    ret = 0;
- cleanup:
-    VIR_FREE(username);
-    VIR_FREE(password);
-    return ret;
-}
-
-static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
-                                        virConnectAuthPtr auth,
-                                        virConfPtr conf ATTRIBUTE_UNUSED,
-                                        unsigned int flags)
-{
-    int ret;
-
-    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
-
-    if (!conn->uri)
-        return VIR_DRV_OPEN_DECLINED;
-
-    if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
-        return VIR_DRV_OPEN_DECLINED;
-
-    /* Remote driver should handle these. */
-    if (conn->uri->server)
-        return VIR_DRV_OPEN_DECLINED;
-
-    /* From this point on, the connection is for us. */
-    if (!conn->uri->path
-        || conn->uri->path[0] == '\0'
-        || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       "%s", _("testOpen: supply a path or use test:///default"));
-        return VIR_DRV_OPEN_ERROR;
-    }
-
-    if (STREQ(conn->uri->path, "/default"))
-        ret = testOpenDefault(conn);
-    else
-        ret = testOpenFromFile(conn,
-                               conn->uri->path);
-
-    if (ret != VIR_DRV_OPEN_SUCCESS)
-        return ret;
-
-    /* Fake authentication. */
-    if (testConnectAuthenticate(conn, auth) < 0)
-        return VIR_DRV_OPEN_ERROR;
-
-    return VIR_DRV_OPEN_SUCCESS;
-}
-
-static int testConnectClose(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    bool dflt = false;
-
-    if (privconn == defaultConn) {
-        dflt = true;
-        virMutexLock(&defaultLock);
-        if (--defaultConnections) {
-            virMutexUnlock(&defaultLock);
-            return 0;
-        }
-    }
-
-    testDriverLock(privconn);
-    testDriverFree(privconn);
-
-    if (dflt) {
-        defaultConn = NULL;
-        virMutexUnlock(&defaultLock);
-    }
-
-    conn->privateData = NULL;
-    return 0;
-}
-
-static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                 unsigned long *hvVer)
-{
-    *hvVer = 2;
-    return 0;
-}
-
-static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
-    return virGetHostname();
-}
-
-
-static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
-    return 1;
-}
-
-static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
-    return 0;
-}
-
-static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
-    return 1;
-}
-
-static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                  const char *type ATTRIBUTE_UNUSED)
-{
-    return 32;
-}
-
-static char *
-testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
-                       const char **xmlCPUs,
-                       unsigned int ncpus,
-                       unsigned int flags)
-{
-    char *cpu;
-
-    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
-
-    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
-
-    return cpu;
-}
-
-static int testNodeGetInfo(virConnectPtr conn,
-                           virNodeInfoPtr info)
-{
-    testDriverPtr privconn = conn->privateData;
-    testDriverLock(privconn);
-    memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
-    testDriverUnlock(privconn);
-    return 0;
-}
-
-static char *testConnectGetCapabilities(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    char *xml;
-    testDriverLock(privconn);
-    xml = virCapabilitiesFormatXML(privconn->caps);
-    testDriverUnlock(privconn);
-    return xml;
-}
-
-static char *
-testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
-                      unsigned int flags)
-{
-    char *ret;
-    const char *sysinfo = "<sysinfo type='smbios'>\n"
-           "  <bios>\n"
-           "    <entry name='vendor'>LENOVO</entry>\n"
-           "    <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
-           "    <entry name='date'>05/07/2014</entry>\n"
-           "    <entry name='release'>2.61</entry>\n"
-           "  </bios>\n"
-           "</sysinfo>\n";
-
-    virCheckFlags(0, NULL);
-
-    ignore_value(VIR_STRDUP(ret, sysinfo));
-    return ret;
-}
-
-static const char *
-testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
-    return "TEST";
-}
-
-static int testConnectNumOfDomains(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    int count;
-
-    testDriverLock(privconn);
-    count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
-    testDriverUnlock(privconn);
-
-    return count;
-}
-
-static int testDomainIsActive(virDomainPtr dom)
-{
-    virDomainObjPtr obj;
-    int ret;
-
-    if (!(obj = testDomObjFromDomain(dom)))
-        return -1;
-
-    ret = virDomainObjIsActive(obj);
-    virDomainObjEndAPI(&obj);
-    return ret;
-}
-
-static int testDomainIsPersistent(virDomainPtr dom)
-{
-    virDomainObjPtr obj;
-    int ret;
-
-    if (!(obj = testDomObjFromDomain(dom)))
-        return -1;
-
-    ret = obj->persistent;
-
-    virDomainObjEndAPI(&obj);
-    return ret;
-}
-
-static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
-    return 0;
-}
-
-static virDomainPtr
-testDomainCreateXML(virConnectPtr conn, const char *xml,
-                      unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    virDomainPtr ret = NULL;
-    virDomainDefPtr def;
-    virDomainObjPtr dom = NULL;
-    virObjectEventPtr event = NULL;
-    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
-    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
-
-    if (flags & VIR_DOMAIN_START_VALIDATE)
-        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
-    testDriverLock(privconn);
-    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
-                                       parse_flags)) == NULL)
-        goto cleanup;
-
-    if (testDomainGenerateIfnames(def) < 0)
-        goto cleanup;
-    if (!(dom = virDomainObjListAdd(privconn->domains,
-                                    def,
-                                    privconn->xmlopt,
-                                    VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
-                                    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
-                                    NULL)))
-        goto cleanup;
-    def = NULL;
-
-    if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
-        if (!dom->persistent) {
-            virDomainObjListRemove(privconn->domains, dom);
-            dom = NULL;
-        }
-        goto cleanup;
-    }
-
-    event = virDomainEventLifecycleNewFromObj(dom,
-                                     VIR_DOMAIN_EVENT_STARTED,
-                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
-    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
-    if (ret)
-        ret->id = dom->def->id;
-
- cleanup:
-    if (dom)
-        virObjectUnlock(dom);
-    testObjectEventQueue(privconn, event);
-    virDomainDefFree(def);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-
-static virDomainPtr testDomainLookupByID(virConnectPtr conn,
-                                         int id)
-{
-    testDriverPtr privconn = conn->privateData;
-    virDomainPtr ret = NULL;
-    virDomainObjPtr dom;
-
-    if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
-        virReportError(VIR_ERR_NO_DOMAIN, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
-    if (ret)
-        ret->id = dom->def->id;
-
- cleanup:
-    if (dom)
-        virObjectUnlock(dom);
-    return ret;
-}
-
-static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
-                                           const unsigned char *uuid)
-{
-    testDriverPtr privconn = conn->privateData;
-    virDomainPtr ret = NULL;
-    virDomainObjPtr dom;
-
-    if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
-        virReportError(VIR_ERR_NO_DOMAIN, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
-    if (ret)
-        ret->id = dom->def->id;
-
- cleanup:
-    if (dom)
-        virObjectUnlock(dom);
-    return ret;
-}
-
-static virDomainPtr testDomainLookupByName(virConnectPtr conn,
-                                           const char *name)
-{
-    testDriverPtr privconn = conn->privateData;
-    virDomainPtr ret = NULL;
-    virDomainObjPtr dom;
-
-    if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
-        virReportError(VIR_ERR_NO_DOMAIN, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
-    if (ret)
-        ret->id = dom->def->id;
-
- cleanup:
-    virDomainObjEndAPI(&dom);
-    return ret;
-}
-
-static int testConnectListDomains(virConnectPtr conn,
-                                  int *ids,
-                                  int maxids)
-{
-    testDriverPtr privconn = conn->privateData;
-
-    return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
-                                        NULL, NULL);
-}
-
-static int testDomainDestroy(virDomainPtr domain)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_STOPPED,
-                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
-
-    if (!privdom->persistent)
-        virDomainObjListRemove(privconn->domains, privdom);
-
-    ret = 0;
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainResume(virDomainPtr domain)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
-                       domain->name);
-        goto cleanup;
-    }
-
-    virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
-                         VIR_DOMAIN_RUNNING_UNPAUSED);
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_RESUMED,
-                                     VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainSuspend(virDomainPtr domain)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-    int state;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    state = virDomainObjGetState(privdom, NULL);
-    if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
-                       domain->name);
-        goto cleanup;
-    }
-
-    virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_SUSPENDED,
-                                     VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainShutdownFlags(virDomainPtr domain,
-                                   unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("domain '%s' not running"), domain->name);
-        goto cleanup;
-    }
-
-    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_STOPPED,
-                                     VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
-    if (!privdom->persistent)
-        virDomainObjListRemove(privconn->domains, privdom);
-
-    ret = 0;
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainShutdown(virDomainPtr domain)
-{
-    return testDomainShutdownFlags(domain, 0);
-}
-
-/* Similar behaviour as shutdown */
-static int testDomainReboot(virDomainPtr domain,
-                            unsigned int action ATTRIBUTE_UNUSED)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
-                         VIR_DOMAIN_SHUTDOWN_USER);
-
-    switch (privdom->def->onReboot) {
-    case VIR_DOMAIN_LIFECYCLE_DESTROY:
-        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
-                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
-        break;
-
-    case VIR_DOMAIN_LIFECYCLE_RESTART:
-        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
-                             VIR_DOMAIN_RUNNING_BOOTED);
-        break;
-
-    case VIR_DOMAIN_LIFECYCLE_PRESERVE:
-        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
-                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
-        break;
-
-    case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
-        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
-                             VIR_DOMAIN_RUNNING_BOOTED);
-        break;
-
-    default:
-        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
-                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
-        break;
-    }
-
-    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
-        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
-        event = virDomainEventLifecycleNewFromObj(privdom,
-                                         VIR_DOMAIN_EVENT_STOPPED,
-                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
-        if (!privdom->persistent)
-            virDomainObjListRemove(privconn->domains, privdom);
-    }
-
-    ret = 0;
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainGetInfo(virDomainPtr domain,
-                             virDomainInfoPtr info)
-{
-    struct timeval tv;
-    virDomainObjPtr privdom;
-    int ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (gettimeofday(&tv, NULL) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("getting time of day"));
-        goto cleanup;
-    }
-
-    info->state = virDomainObjGetState(privdom, NULL);
-    info->memory = privdom->def->mem.cur_balloon;
-    info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
-    info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
-    info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainGetState(virDomainPtr domain,
-                   int *state,
-                   int *reason,
-                   unsigned int flags)
-{
-    virDomainObjPtr privdom;
-
-    virCheckFlags(0, -1);
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    *state = virDomainObjGetState(privdom, reason);
-
-    virDomainObjEndAPI(&privdom);
-
-    return 0;
-}
-
-#define TEST_SAVE_MAGIC "TestGuestMagic"
-
-static int
-testDomainSaveFlags(virDomainPtr domain, const char *path,
-                    const char *dxml, unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    char *xml = NULL;
-    int fd = -1;
-    int len;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-    if (dxml) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("xml modification unsupported"));
-        return -1;
-    }
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    xml = virDomainDefFormat(privdom->def, privconn->caps,
-                             VIR_DOMAIN_DEF_FORMAT_SECURE);
-
-    if (xml == NULL) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' failed to allocate space for metadata"),
-                             domain->name);
-        goto cleanup;
-    }
-
-    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' to '%s': open failed"),
-                             domain->name, path);
-        goto cleanup;
-    }
-    len = strlen(xml);
-    if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
-        goto cleanup;
-    }
-    if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
-        goto cleanup;
-    }
-    if (safewrite(fd, xml, len) < 0) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
-        goto cleanup;
-    }
-
-    if (VIR_CLOSE(fd) < 0) {
-        virReportSystemError(errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
-        goto cleanup;
-    }
-    fd = -1;
-
-    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_STOPPED,
-                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
-
-    if (!privdom->persistent)
-        virDomainObjListRemove(privconn->domains, privdom);
-
-    ret = 0;
- cleanup:
-    VIR_FREE(xml);
-
-    /* Don't report failure in close or unlink, because
-     * in either case we're already in a failure scenario
-     * and have reported a earlier error */
-    if (ret != 0) {
-        VIR_FORCE_CLOSE(fd);
-        unlink(path);
-    }
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int
-testDomainSave(virDomainPtr domain,
-               const char *path)
-{
-    return testDomainSaveFlags(domain, path, NULL, 0);
-}
-
-static int
-testDomainRestoreFlags(virConnectPtr conn,
-                       const char *path,
-                       const char *dxml,
-                       unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    char *xml = NULL;
-    char magic[15];
-    int fd = -1;
-    int len;
-    virDomainDefPtr def = NULL;
-    virDomainObjPtr dom = NULL;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-    if (dxml) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("xml modification unsupported"));
-        return -1;
-    }
-
-    if ((fd = open(path, O_RDONLY)) < 0) {
-        virReportSystemError(errno,
-                             _("cannot read domain image '%s'"),
-                             path);
-        goto cleanup;
-    }
-    if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
-        virReportSystemError(errno,
-                             _("incomplete save header in '%s'"),
-                             path);
-        goto cleanup;
-    }
-    if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("mismatched header magic"));
-        goto cleanup;
-    }
-    if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
-        virReportSystemError(errno,
-                             _("failed to read metadata length in '%s'"),
-                             path);
-        goto cleanup;
-    }
-    if (len < 1 || len > 8192) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("length of metadata out of range"));
-        goto cleanup;
-    }
-    if (VIR_ALLOC_N(xml, len+1) < 0)
-        goto cleanup;
-    if (saferead(fd, xml, len) != len) {
-        virReportSystemError(errno,
-                             _("incomplete metadata in '%s'"), path);
-        goto cleanup;
-    }
-    xml[len] = '\0';
-
-    def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
-                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
-    if (!def)
-        goto cleanup;
-
-    if (testDomainGenerateIfnames(def) < 0)
-        goto cleanup;
-    if (!(dom = virDomainObjListAdd(privconn->domains,
-                                    def,
-                                    privconn->xmlopt,
-                                    VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
-                                    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
-                                    NULL)))
-        goto cleanup;
-    def = NULL;
-
-    if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
-        if (!dom->persistent) {
-            virDomainObjListRemove(privconn->domains, dom);
-            dom = NULL;
-        }
-        goto cleanup;
-    }
-
-    event = virDomainEventLifecycleNewFromObj(dom,
-                                     VIR_DOMAIN_EVENT_STARTED,
-                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
-    ret = 0;
-
- cleanup:
-    virDomainDefFree(def);
-    VIR_FREE(xml);
-    VIR_FORCE_CLOSE(fd);
-    if (dom)
-        virObjectUnlock(dom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int
-testDomainRestore(virConnectPtr conn,
-                  const char *path)
-{
-    return testDomainRestoreFlags(conn, path, NULL, 0);
-}
-
-static int testDomainCoreDumpWithFormat(virDomainPtr domain,
-                                        const char *to,
-                                        unsigned int dumpformat,
-                                        unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    int fd = -1;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(VIR_DUMP_CRASH, -1);
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
-        virReportSystemError(errno,
-                             _("domain '%s' coredump: failed to open %s"),
-                             domain->name, to);
-        goto cleanup;
-    }
-    if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
-        virReportSystemError(errno,
-                             _("domain '%s' coredump: failed to write header to %s"),
-                             domain->name, to);
-        goto cleanup;
-    }
-    if (VIR_CLOSE(fd) < 0) {
-        virReportSystemError(errno,
-                             _("domain '%s' coredump: write failed: %s"),
-                             domain->name, to);
-        goto cleanup;
-    }
-
-    /* we don't support non-raw formats in test driver */
-    if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
-        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                       _("kdump-compressed format is not supported here"));
-        goto cleanup;
-    }
-
-    if (flags & VIR_DUMP_CRASH) {
-        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
-        event = virDomainEventLifecycleNewFromObj(privdom,
-                                         VIR_DOMAIN_EVENT_STOPPED,
-                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
-        if (!privdom->persistent)
-            virDomainObjListRemove(privconn->domains, privdom);
-    }
-
-    ret = 0;
- cleanup:
-    VIR_FORCE_CLOSE(fd);
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-
-static int
-testDomainCoreDump(virDomainPtr domain,
-                   const char *to,
-                   unsigned int flags)
-{
-    return testDomainCoreDumpWithFormat(domain, to,
-                                        VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
-}
-
-
-static char *
-testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
-    char *ret;
-
-    ignore_value(VIR_STRDUP(ret, "linux"));
-    return ret;
-}
-
-
-static unsigned long long
-testDomainGetMaxMemory(virDomainPtr domain)
-{
-    virDomainObjPtr privdom;
-    unsigned long long ret = 0;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return 0;
-
-    ret = virDomainDefGetMemoryTotal(privdom->def);
-
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int testDomainSetMaxMemory(virDomainPtr domain,
-                                  unsigned long memory)
-{
-    virDomainObjPtr privdom;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    /* XXX validate not over host memory wrt to other domains */
-    virDomainDefSetMemoryTotal(privdom->def, memory);
-
-    virDomainObjEndAPI(&privdom);
-    return 0;
-}
-
-static int testDomainSetMemory(virDomainPtr domain,
-                               unsigned long memory)
-{
-    virDomainObjPtr privdom;
-    int ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privdom->def->mem.cur_balloon = memory;
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
-{
-    virDomainObjPtr vm;
-    virDomainDefPtr def;
-    int ret = -1;
-
-    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG |
-                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (!(def = virDomainObjGetOneDef(vm, flags)))
-        goto cleanup;
-
-    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
-        ret = virDomainDefGetVcpusMax(def);
-    else
-        ret = virDomainDefGetVcpus(def);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-static int
-testDomainGetMaxVcpus(virDomainPtr domain)
-{
-    return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
-                                            VIR_DOMAIN_VCPU_MAXIMUM));
-}
-
-static int
-testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
-                        unsigned int flags)
-{
-    testDriverPtr driver = domain->conn->privateData;
-    virDomainObjPtr privdom = NULL;
-    virDomainDefPtr def;
-    virDomainDefPtr persistentDef;
-    int ret = -1, maxvcpus;
-
-    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG |
-                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
-    if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
-        return -1;
-
-    if (nrCpus > maxvcpus) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("requested cpu amount exceeds maximum supported amount "
-                         "(%d > %d)"), nrCpus, maxvcpus);
-        return -1;
-    }
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
-        goto cleanup;
-
-    if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("requested cpu amount exceeds maximum (%d > %d)"),
-                       nrCpus, virDomainDefGetVcpusMax(def));
-        goto cleanup;
-    }
-
-    if (persistentDef &&
-        !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
-        virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("requested cpu amount exceeds maximum (%d > %d)"),
-                       nrCpus, virDomainDefGetVcpusMax(persistentDef));
-        goto cleanup;
-    }
-
-    if (def &&
-        virDomainDefSetVcpus(def, nrCpus) < 0)
-        goto cleanup;
-
-    if (persistentDef) {
-        if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
-            if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
-                                        driver->xmlopt) < 0)
-                goto cleanup;
-        } else {
-            if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
-                goto cleanup;
-        }
-    }
-
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
-{
-    return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
-}
-
-static int testDomainGetVcpus(virDomainPtr domain,
-                              virVcpuInfoPtr info,
-                              int maxinfo,
-                              unsigned char *cpumaps,
-                              int maplen)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virDomainDefPtr def;
-    size_t i;
-    int maxcpu, hostcpus;
-    int ret = -1;
-    struct timeval tv;
-    unsigned long long statbase;
-    virBitmapPtr allcpumap = NULL;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (!virDomainObjIsActive(privdom)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       "%s", _("cannot list vcpus for an inactive domain"));
-        goto cleanup;
-    }
-
-    def = privdom->def;
-
-    if (gettimeofday(&tv, NULL) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("getting time of day"));
-        goto cleanup;
-    }
-
-    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
-
-    hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
-    maxcpu = maplen * 8;
-    if (maxcpu > hostcpus)
-        maxcpu = hostcpus;
-
-    if (!(allcpumap = virBitmapNew(hostcpus)))
-        goto cleanup;
-
-    virBitmapSetAll(allcpumap);
-
-    /* Clamp to actual number of vcpus */
-    if (maxinfo > virDomainDefGetVcpus(privdom->def))
-        maxinfo = virDomainDefGetVcpus(privdom->def);
-
-    memset(info, 0, sizeof(*info) * maxinfo);
-    memset(cpumaps, 0, maxinfo * maplen);
-
-    for (i = 0; i < maxinfo; i++) {
-        virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
-        virBitmapPtr bitmap = NULL;
-
-        if (!vcpu->online)
-            continue;
-
-        if (vcpu->cpumask)
-            bitmap = vcpu->cpumask;
-        else if (def->cpumask)
-            bitmap = def->cpumask;
-        else
-            bitmap = allcpumap;
-
-        if (cpumaps)
-            virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
-
-        info[i].number = i;
-        info[i].state = VIR_VCPU_RUNNING;
-        info[i].cpu = virBitmapLastSetBit(bitmap);
-
-        /* Fake an increasing cpu time value */
-        info[i].cpuTime = statbase / 10;
-    }
-
-    ret = maxinfo;
- cleanup:
-    virBitmapFree(allcpumap);
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int testDomainPinVcpu(virDomainPtr domain,
-                             unsigned int vcpu,
-                             unsigned char *cpumap,
-                             int maplen)
-{
-    virDomainVcpuDefPtr vcpuinfo;
-    virDomainObjPtr privdom;
-    virDomainDefPtr def;
-    int ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    def = privdom->def;
-
-    if (!virDomainObjIsActive(privdom)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       "%s", _("cannot pin vcpus on an inactive domain"));
-        goto cleanup;
-    }
-
-    if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
-        !vcpuinfo->online) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("requested vcpu '%d' is not present in the domain"),
-                       vcpu);
-        goto cleanup;
-    }
-
-    virBitmapFree(vcpuinfo->cpumask);
-
-    if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainGetVcpuPinInfo(virDomainPtr dom,
-                        int ncpumaps,
-                        unsigned char *cpumaps,
-                        int maplen,
-                        unsigned int flags)
-{
-    testDriverPtr driver = dom->conn->privateData;
-    virDomainObjPtr privdom;
-    virDomainDefPtr def;
-    int ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(dom)))
-        return -1;
-
-    if (!(def = virDomainObjGetOneDef(privdom, flags)))
-        goto cleanup;
-
-    ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
-                                           VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
-                                           NULL);
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainDefPtr def;
-    virDomainObjPtr privdom;
-    char *ret = NULL;
-
-    /* Flags checked by virDomainDefFormat */
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return NULL;
-
-    def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
-        privdom->newDef ? privdom->newDef : privdom->def;
-
-    ret = virDomainDefFormat(def, privconn->caps,
-                             virDomainDefFormatConvertXMLFlags(flags));
-
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int testConnectNumOfDefinedDomains(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-
-    return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
-}
-
-static int testConnectListDefinedDomains(virConnectPtr conn,
-                                         char **const names,
-                                         int maxnames)
-{
-
-    testDriverPtr privconn = conn->privateData;
-
-    memset(names, 0, sizeof(*names)*maxnames);
-    return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
-                                            NULL, NULL);
-}
-
-static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
-                                             const char *xml,
-                                             unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    virDomainPtr ret = NULL;
-    virDomainDefPtr def;
-    virDomainObjPtr dom = NULL;
-    virObjectEventPtr event = NULL;
-    virDomainDefPtr oldDef = NULL;
-    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
-    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
-
-    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
-        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
-    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
-                                       parse_flags)) == NULL)
-        goto cleanup;
-
-    if (testDomainGenerateIfnames(def) < 0)
-        goto cleanup;
-    if (!(dom = virDomainObjListAdd(privconn->domains,
-                                    def,
-                                    privconn->xmlopt,
-                                    0,
-                                    &oldDef)))
-        goto cleanup;
-    def = NULL;
-    dom->persistent = 1;
-
-    event = virDomainEventLifecycleNewFromObj(dom,
-                                     VIR_DOMAIN_EVENT_DEFINED,
-                                     !oldDef ?
-                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
-                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
-
-    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
-    if (ret)
-        ret->id = dom->def->id;
-
- cleanup:
-    virDomainDefFree(def);
-    virDomainDefFree(oldDef);
-    if (dom)
-        virObjectUnlock(dom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static virDomainPtr
-testDomainDefineXML(virConnectPtr conn, const char *xml)
-{
-    return testDomainDefineXMLFlags(conn, xml, 0);
-}
-
-static char *testDomainGetMetadata(virDomainPtr dom,
-                                   int type,
-                                   const char *uri,
-                                   unsigned int flags)
-{
-    virDomainObjPtr privdom;
-    char *ret;
-
-    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG, NULL);
-
-    if (!(privdom = testDomObjFromDomain(dom)))
-        return NULL;
-
-    ret = virDomainObjGetMetadata(privdom, type, uri, flags);
-
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int testDomainSetMetadata(virDomainPtr dom,
-                                 int type,
-                                 const char *metadata,
-                                 const char *key,
-                                 const char *uri,
-                                 unsigned int flags)
-{
-    testDriverPtr privconn = dom->conn->privateData;
-    virDomainObjPtr privdom;
-    int ret;
-
-    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG, -1);
-
-    if (!(privdom = testDomObjFromDomain(dom)))
-        return -1;
-
-    ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
-                                  privconn->caps, privconn->xmlopt,
-                                  NULL, NULL, flags);
-
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-
-static int testNodeGetCellsFreeMemory(virConnectPtr conn,
-                                      unsigned long long *freemems,
-                                      int startCell, int maxCells)
-{
-    testDriverPtr privconn = conn->privateData;
-    int cell;
-    size_t i;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    if (startCell > privconn->numCells) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       "%s", _("Range exceeds available cells"));
-        goto cleanup;
-    }
-
-    for (cell = startCell, i = 0;
-         (cell < privconn->numCells && i < maxCells);
-         ++cell, ++i) {
-        freemems[i] = privconn->cells[cell].mem;
-    }
-    ret = i;
-
- cleanup:
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-#define TEST_NB_CPU_STATS 4
-
-static int
-testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
-                    int cpuNum ATTRIBUTE_UNUSED,
-                    virNodeCPUStatsPtr params,
-                    int *nparams,
-                    unsigned int flags)
-{
-    size_t i = 0;
-
-    virCheckFlags(0, -1);
-
-    if (params == NULL) {
-        *nparams = TEST_NB_CPU_STATS;
-        return 0;
-    }
-
-    for (i = 0; i < *nparams && i < 4; i++) {
-        switch (i) {
-        case 0:
-            if (virHostCPUStatsAssign(&params[i],
-                                      VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
-                return -1;
-            break;
-        case 1:
-            if (virHostCPUStatsAssign(&params[i],
-                                      VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
-                return -1;
-            break;
-        case 2:
-            if (virHostCPUStatsAssign(&params[i],
-                                      VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
-                return -1;
-            break;
-        case 3:
-            if (virHostCPUStatsAssign(&params[i],
-                                      VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
-                return -1;
-            break;
-        }
-    }
-
-    *nparams = i;
-    return 0;
-}
-
-static unsigned long long
-testNodeGetFreeMemory(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    unsigned int freeMem = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-
-    for (i = 0; i < privconn->numCells; i++)
-        freeMem += privconn->cells[i].freeMem;
-
-    testDriverUnlock(privconn);
-    return freeMem;
-}
-
-static int
-testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
-                     unsigned int npages,
-                     unsigned int *pages ATTRIBUTE_UNUSED,
-                     int startCell ATTRIBUTE_UNUSED,
-                     unsigned int cellCount,
-                     unsigned long long *counts,
-                     unsigned int flags)
-{
-    size_t i = 0, j = 0;
-    int x = 6;
-
-    virCheckFlags(0, -1);
-
-    for (i = 0; i < cellCount; i++) {
-        for (j = 0; j < npages; j++) {
-            x = x * 2 + 7;
-            counts[(i * npages) +  j] = x;
-        }
-    }
-
-    return 0;
-}
-
-static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Domain '%s' is already running"), domain->name);
-        goto cleanup;
-    }
-
-    if (testDomainStartState(privconn, privdom,
-                             VIR_DOMAIN_RUNNING_BOOTED) < 0)
-        goto cleanup;
-    domain->id = privdom->def->id;
-
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_STARTED,
-                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int testDomainCreate(virDomainPtr domain)
-{
-    return testDomainCreateWithFlags(domain, 0);
-}
-
-static int testDomainUndefineFlags(virDomainPtr domain,
-                                   unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr privdom;
-    virObjectEventPtr event = NULL;
-    int nsnapshots;
-    int ret = -1;
-
-    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
-                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
-
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    if (privdom->hasManagedSave &&
-        !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("Refusing to undefine while domain managed "
-                         "save image exists"));
-        goto cleanup;
-    }
-
-    /* Requiring an inactive VM is part of the documented API for
-     * UNDEFINE_SNAPSHOTS_METADATA
-     */
-    if (!virDomainObjIsActive(privdom) &&
-        (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
-                                                  NULL, 0))) {
-        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
-            virReportError(VIR_ERR_OPERATION_INVALID,
-                           _("cannot delete inactive domain with %d "
-                             "snapshots"),
-                           nsnapshots);
-            goto cleanup;
-        }
-
-        /* There isn't actually anything to do, we are just emulating qemu
-         * behavior here. */
-    }
-
-    event = virDomainEventLifecycleNewFromObj(privdom,
-                                     VIR_DOMAIN_EVENT_UNDEFINED,
-                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
-    privdom->hasManagedSave = false;
-
-    if (virDomainObjIsActive(privdom))
-        privdom->persistent = 0;
-    else
-        virDomainObjListRemove(privconn->domains, privdom);
-
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    testObjectEventQueue(privconn, event);
-    return ret;
-}
-
-static int testDomainUndefine(virDomainPtr domain)
-{
-    return testDomainUndefineFlags(domain, 0);
-}
-
-static int testDomainGetAutostart(virDomainPtr domain,
-                                  int *autostart)
-{
-    virDomainObjPtr privdom;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    *autostart = privdom->autostart;
-
-    virDomainObjEndAPI(&privdom);
-    return 0;
-}
-
-
-static int testDomainSetAutostart(virDomainPtr domain,
-                                  int autostart)
-{
-    virDomainObjPtr privdom;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    privdom->autostart = autostart ? 1 : 0;
-
-    virDomainObjEndAPI(&privdom);
-    return 0;
-}
-
-static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
-                                        int *nparams)
-{
-    char *type = NULL;
-
-    if (nparams)
-        *nparams = 1;
-
-    ignore_value(VIR_STRDUP(type, "fair"));
-
-    return type;
-}
-
-static int
-testDomainGetSchedulerParametersFlags(virDomainPtr domain,
-                                      virTypedParameterPtr params,
-                                      int *nparams,
-                                      unsigned int flags)
-{
-    virDomainObjPtr privdom;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
-                                VIR_TYPED_PARAM_UINT, 50) < 0)
-        goto cleanup;
-    /* XXX */
-    /*params[0].value.ui = privdom->weight;*/
-
-    *nparams = 1;
-    ret = 0;
-
- cleanup:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainGetSchedulerParameters(virDomainPtr domain,
-                                 virTypedParameterPtr params,
-                                 int *nparams)
-{
-    return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int
-testDomainSetSchedulerParametersFlags(virDomainPtr domain,
-                                      virTypedParameterPtr params,
-                                      int nparams,
-                                      unsigned int flags)
-{
-    virDomainObjPtr privdom;
-    int ret = -1;
-    size_t i;
-
-    virCheckFlags(0, -1);
-    if (virTypedParamsValidate(params, nparams,
-                               VIR_DOMAIN_SCHEDULER_WEIGHT,
-                               VIR_TYPED_PARAM_UINT,
-                               NULL) < 0)
-        return -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    for (i = 0; i < nparams; i++) {
-        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
-            /* XXX */
-            /*privdom->weight = params[i].value.ui;*/
-        }
-    }
-
-    ret = 0;
-
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int
-testDomainSetSchedulerParameters(virDomainPtr domain,
-                                 virTypedParameterPtr params,
-                                 int nparams)
-{
-    return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int testDomainBlockStats(virDomainPtr domain,
-                                const char *path,
-                                virDomainBlockStatsPtr stats)
-{
-    virDomainObjPtr privdom;
-    struct timeval tv;
-    unsigned long long statbase;
-    int ret = -1;
-
-    if (!*path) {
-        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                       _("summary statistics are not supported yet"));
-        return ret;
-    }
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return ret;
-
-    if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("invalid path: %s"), path);
-        goto error;
-    }
-
-    if (gettimeofday(&tv, NULL) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("getting time of day"));
-        goto error;
-    }
-
-    /* No significance to these numbers, just enough to mix it up*/
-    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
-    stats->rd_req = statbase / 10;
-    stats->rd_bytes = statbase / 20;
-    stats->wr_req = statbase / 30;
-    stats->wr_bytes = statbase / 40;
-    stats->errs = tv.tv_sec / 2;
-
-    ret = 0;
- error:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-static int testDomainInterfaceStats(virDomainPtr domain,
-                                    const char *path,
-                                    virDomainInterfaceStatsPtr stats)
-{
-    virDomainObjPtr privdom;
-    struct timeval tv;
-    unsigned long long statbase;
-    size_t i;
-    int found = 0, ret = -1;
-
-    if (!(privdom = testDomObjFromDomain(domain)))
-        return -1;
-
-    for (i = 0; i < privdom->def->nnets; i++) {
-        if (privdom->def->nets[i]->ifname &&
-            STREQ(privdom->def->nets[i]->ifname, path)) {
-            found = 1;
-            break;
-        }
-    }
-
-    if (!found) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("invalid path, '%s' is not a known interface"), path);
-        goto error;
-    }
-
-    if (gettimeofday(&tv, NULL) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("getting time of day"));
-        goto error;
-    }
-
-    /* No significance to these numbers, just enough to mix it up*/
-    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
-    stats->rx_bytes = statbase / 10;
-    stats->rx_packets = statbase / 100;
-    stats->rx_errs = tv.tv_sec / 1;
-    stats->rx_drop = tv.tv_sec / 2;
-    stats->tx_bytes = statbase / 20;
-    stats->tx_packets = statbase / 110;
-    stats->tx_errs = tv.tv_sec / 3;
-    stats->tx_drop = tv.tv_sec / 4;
-
-    ret = 0;
- error:
-    virDomainObjEndAPI(&privdom);
-    return ret;
-}
-
-
-static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
-                                             const unsigned char *uuid)
-{
-    testDriverPtr privconn = conn->privateData;
-    virNetworkObjPtr net;
-    virNetworkPtr ret = NULL;
-
-    net = virNetworkObjFindByUUID(privconn->networks, uuid);
-    if (net == NULL) {
-        virReportError(VIR_ERR_NO_NETWORK, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
-    virNetworkObjEndAPI(&net);
-    return ret;
-}
-
-static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
-                                             const char *name)
-{
-    testDriverPtr privconn = conn->privateData;
-    virNetworkObjPtr net;
-    virNetworkPtr ret = NULL;
-
-    net = virNetworkObjFindByName(privconn->networks, name);
-    if (net == NULL) {
-        virReportError(VIR_ERR_NO_NETWORK, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
-    virNetworkObjEndAPI(&net);
-    return ret;
-}
-
-
-static int testConnectNumOfNetworks(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    int numActive;
-
-    numActive = virNetworkObjListNumOfNetworks(privconn->networks,
-                                               true, NULL, conn);
-    return numActive;
-}
-
-static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
-    testDriverPtr privconn = conn->privateData;
-    int n;
-
-    n = virNetworkObjListGetNames(privconn->networks,
-                                  true, names, nnames, NULL, conn);
-    return n;
-}
-
-static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    int numInactive;
-
-    numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
-                                                 false, NULL, conn);
-    return numInactive;
-}
-
-static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
-    testDriverPtr privconn = conn->privateData;
-    int n;
-
-    n = virNetworkObjListGetNames(privconn->networks,
-                                  false, names, nnames, NULL, conn);
-    return n;
-}
-
-static int
-testConnectListAllNetworks(virConnectPtr conn,
-                           virNetworkPtr **nets,
-                           unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-
-    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
-
-    return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
-}
-
-static int testNetworkIsActive(virNetworkPtr net)
-{
-    testDriverPtr privconn = net->conn->privateData;
-    virNetworkObjPtr obj;
-    int ret = -1;
-
-    obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NETWORK, NULL);
-        goto cleanup;
-    }
-    ret = virNetworkObjIsActive(obj);
-
- cleanup:
-    virNetworkObjEndAPI(&obj);
-    return ret;
-}
-
-static int testNetworkIsPersistent(virNetworkPtr net)
-{
-    testDriverPtr privconn = net->conn->privateData;
-    virNetworkObjPtr obj;
-    int ret = -1;
-
-    obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NETWORK, NULL);
-        goto cleanup;
-    }
-    ret = obj->persistent;
-
- cleanup:
-    virNetworkObjEndAPI(&obj);
-    return ret;
-}
-
-
-static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
-{
-    testDriverPtr privconn = conn->privateData;
-    virNetworkDefPtr def;
-    virNetworkObjPtr net = NULL;
-    virNetworkPtr ret = NULL;
-    virObjectEventPtr event = NULL;
-
-    if ((def = virNetworkDefParseString(xml)) == NULL)
-        goto cleanup;
-
-    if (!(net = virNetworkAssignDef(privconn->networks, def,
-                                    VIR_NETWORK_OBJ_LIST_ADD_LIVE |
-                                    VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
-        goto cleanup;
-    def = NULL;
-    net->active = 1;
-
-    event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
-                                        VIR_NETWORK_EVENT_STARTED,
-                                        0);
-
-    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
-    virNetworkDefFree(def);
-    testObjectEventQueue(privconn, event);
-    virNetworkObjEndAPI(&net);
-    return ret;
-}
-
-static
-virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
-{
-    testDriverPtr privconn = conn->privateData;
-    virNetworkDefPtr def;
-    virNetworkObjPtr net = NULL;
-    virNetworkPtr ret = NULL;
-    virObjectEventPtr event = NULL;
-
-    if ((def = virNetworkDefParseString(xml)) == NULL)
-        goto cleanup;
-
-    if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
-        goto cleanup;
-    def = NULL;
-
-    event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
-                                        VIR_NETWORK_EVENT_DEFINED,
-                                        0);
-
-    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
-    virNetworkDefFree(def);
-    testObjectEventQueue(privconn, event);
-    virNetworkObjEndAPI(&net);
-    return ret;
-}
-
-static int testNetworkUndefine(virNetworkPtr network)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virNetworkObjIsActive(privnet)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("Network '%s' is still running"), network->name);
-        goto cleanup;
-    }
-
-    event = virNetworkEventLifecycleNew(network->name, network->uuid,
-                                        VIR_NETWORK_EVENT_UNDEFINED,
-                                        0);
-
-    virNetworkRemoveInactive(privconn->networks, privnet);
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-static int
-testNetworkUpdate(virNetworkPtr net,
-                  unsigned int command,
-                  unsigned int section,
-                  int parentIndex,
-                  const char *xml,
-                  unsigned int flags)
-{
-    testDriverPtr privconn = net->conn->privateData;
-    virNetworkObjPtr network = NULL;
-    int isActive, ret = -1;
-
-    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
-                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
-                  -1);
-
-    network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
-    if (!network) {
-        virReportError(VIR_ERR_NO_NETWORK,
-                       "%s", _("no network with matching uuid"));
-        goto cleanup;
-    }
-
-    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
-     * is active, else change CONFIG
-    */
-    isActive = virNetworkObjIsActive(network);
-    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
-                   | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
-        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
-        if (isActive)
-            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
-        else
-            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
-    }
-
-    /* update the network config in memory/on disk */
-    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
-       goto cleanup;
-
-    ret = 0;
- cleanup:
-    virNetworkObjEndAPI(&network);
-    return ret;
-}
-
-static int testNetworkCreate(virNetworkPtr network)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virNetworkObjIsActive(privnet)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("Network '%s' is already running"), network->name);
-        goto cleanup;
-    }
-
-    privnet->active = 1;
-    event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
-                                        VIR_NETWORK_EVENT_STARTED,
-                                        0);
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-static int testNetworkDestroy(virNetworkPtr network)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privnet->active = 0;
-    event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
-                                        VIR_NETWORK_EVENT_STOPPED,
-                                        0);
-    if (!privnet->persistent)
-        virNetworkRemoveInactive(privconn->networks, privnet);
-
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-static char *testNetworkGetXMLDesc(virNetworkPtr network,
-                                   unsigned int flags)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    ret = virNetworkDefFormat(privnet->def, flags);
-
- cleanup:
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-static char *testNetworkGetBridgeName(virNetworkPtr network) {
-    testDriverPtr privconn = network->conn->privateData;
-    char *bridge = NULL;
-    virNetworkObjPtr privnet;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!(privnet->def->bridge)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("network '%s' does not have a bridge name."),
-                       privnet->def->name);
-        goto cleanup;
-    }
-
-    ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
-
- cleanup:
-    virNetworkObjEndAPI(&privnet);
-    return bridge;
-}
-
-static int testNetworkGetAutostart(virNetworkPtr network,
-                                   int *autostart)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    int ret = -1;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    *autostart = privnet->autostart;
-    ret = 0;
-
- cleanup:
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-static int testNetworkSetAutostart(virNetworkPtr network,
-                                   int autostart)
-{
-    testDriverPtr privconn = network->conn->privateData;
-    virNetworkObjPtr privnet;
-    int ret = -1;
-
-    privnet = virNetworkObjFindByName(privconn->networks, network->name);
-    if (privnet == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privnet->autostart = autostart ? 1 : 0;
-    ret = 0;
-
- cleanup:
-    virNetworkObjEndAPI(&privnet);
-    return ret;
-}
-
-
-/*
- * Physical host interface routines
- */
-
-
-static int testConnectNumOfInterfaces(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    size_t i;
-    int count = 0;
-
-    testDriverLock(privconn);
-    for (i = 0; (i < privconn->ifaces.count); i++) {
-        virInterfaceObjLock(privconn->ifaces.objs[i]);
-        if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
-            count++;
-        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-    }
-    testDriverUnlock(privconn);
-    return count;
-}
-
-static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
-    testDriverPtr privconn = conn->privateData;
-    int n = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    memset(names, 0, sizeof(*names)*nnames);
-    for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
-        virInterfaceObjLock(privconn->ifaces.objs[i]);
-        if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
-            if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
-                virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-                goto error;
-            }
-        }
-        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    return n;
-
- error:
-    for (n = 0; n < nnames; n++)
-        VIR_FREE(names[n]);
-    testDriverUnlock(privconn);
-    return -1;
-}
-
-static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    size_t i;
-    int count = 0;
-
-    testDriverLock(privconn);
-    for (i = 0; i < privconn->ifaces.count; i++) {
-        virInterfaceObjLock(privconn->ifaces.objs[i]);
-        if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
-            count++;
-        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-    }
-    testDriverUnlock(privconn);
-    return count;
-}
-
-static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
-    testDriverPtr privconn = conn->privateData;
-    int n = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    memset(names, 0, sizeof(*names)*nnames);
-    for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
-        virInterfaceObjLock(privconn->ifaces.objs[i]);
-        if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
-            if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
-                virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-                goto error;
-            }
-        }
-        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    return n;
-
- error:
-    for (n = 0; n < nnames; n++)
-        VIR_FREE(names[n]);
-    testDriverUnlock(privconn);
-    return -1;
-}
-
-static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
-                                                 const char *name)
-{
-    testDriverPtr privconn = conn->privateData;
-    virInterfaceObjPtr iface;
-    virInterfacePtr ret = NULL;
-
-    testDriverLock(privconn);
-    iface = virInterfaceFindByName(&privconn->ifaces, name);
-    testDriverUnlock(privconn);
-
-    if (iface == NULL) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
-    if (iface)
-        virInterfaceObjUnlock(iface);
-    return ret;
-}
-
-static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
-                                                      const char *mac)
-{
-    testDriverPtr privconn = conn->privateData;
-    virInterfaceObjPtr iface;
-    int ifacect;
-    virInterfacePtr ret = NULL;
-
-    testDriverLock(privconn);
-    ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
-    testDriverUnlock(privconn);
-
-    if (ifacect == 0) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-
-    if (ifacect > 1) {
-        virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
-    if (iface)
-        virInterfaceObjUnlock(iface);
-    return ret;
-}
-
-static int testInterfaceIsActive(virInterfacePtr iface)
-{
-    testDriverPtr privconn = iface->conn->privateData;
-    virInterfaceObjPtr obj;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
-    testDriverUnlock(privconn);
-    if (!obj) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-    ret = virInterfaceObjIsActive(obj);
-
- cleanup:
-    if (obj)
-        virInterfaceObjUnlock(obj);
-    return ret;
-}
-
-static int testInterfaceChangeBegin(virConnectPtr conn,
-                                    unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    if (privconn->transaction_running) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("there is another transaction running."));
-        goto cleanup;
-    }
-
-    privconn->transaction_running = true;
-
-    if (virInterfaceObjListClone(&privconn->ifaces,
-                                 &privconn->backupIfaces) < 0)
-        goto cleanup;
-
-    ret = 0;
- cleanup:
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int testInterfaceChangeCommit(virConnectPtr conn,
-                                     unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-
-    if (!privconn->transaction_running) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("no transaction running, "
-                         "nothing to be committed."));
-        goto cleanup;
-    }
-
-    virInterfaceObjListFree(&privconn->backupIfaces);
-    privconn->transaction_running = false;
-
-    ret = 0;
-
- cleanup:
-    testDriverUnlock(privconn);
-
-    return ret;
-}
-
-static int testInterfaceChangeRollback(virConnectPtr conn,
-                                       unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-
-    if (!privconn->transaction_running) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("no transaction running, "
-                         "nothing to rollback."));
-        goto cleanup;
-    }
-
-    virInterfaceObjListFree(&privconn->ifaces);
-    privconn->ifaces.count = privconn->backupIfaces.count;
-    privconn->ifaces.objs = privconn->backupIfaces.objs;
-    privconn->backupIfaces.count = 0;
-    privconn->backupIfaces.objs = NULL;
-
-    privconn->transaction_running = false;
-
-    ret = 0;
-
- cleanup:
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
-                                     unsigned int flags)
-{
-    testDriverPtr privconn = iface->conn->privateData;
-    virInterfaceObjPtr privinterface;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    privinterface = virInterfaceFindByName(&privconn->ifaces,
-                                           iface->name);
-    testDriverUnlock(privconn);
-
-    if (privinterface == NULL) {
-        virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
-        goto cleanup;
-    }
-
-    ret = virInterfaceDefFormat(privinterface->def);
-
- cleanup:
-    if (privinterface)
-        virInterfaceObjUnlock(privinterface);
-    return ret;
-}
-
-
-static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
-                                              unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    virInterfaceDefPtr def;
-    virInterfaceObjPtr iface = NULL;
-    virInterfacePtr ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
-        goto cleanup;
-
-    if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
-        goto cleanup;
-    def = NULL;
-
-    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
-    virInterfaceDefFree(def);
-    if (iface)
-        virInterfaceObjUnlock(iface);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int testInterfaceUndefine(virInterfacePtr iface)
-{
-    testDriverPtr privconn = iface->conn->privateData;
-    virInterfaceObjPtr privinterface;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privinterface = virInterfaceFindByName(&privconn->ifaces,
-                                           iface->name);
-
-    if (privinterface == NULL) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-
-    virInterfaceRemove(&privconn->ifaces,
-                       privinterface);
-    ret = 0;
-
- cleanup:
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int testInterfaceCreate(virInterfacePtr iface,
-                               unsigned int flags)
-{
-    testDriverPtr privconn = iface->conn->privateData;
-    virInterfaceObjPtr privinterface;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privinterface = virInterfaceFindByName(&privconn->ifaces,
-                                           iface->name);
-
-    if (privinterface == NULL) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-
-    if (privinterface->active != 0) {
-        virReportError(VIR_ERR_OPERATION_INVALID, NULL);
-        goto cleanup;
-    }
-
-    privinterface->active = 1;
-    ret = 0;
-
- cleanup:
-    if (privinterface)
-        virInterfaceObjUnlock(privinterface);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int testInterfaceDestroy(virInterfacePtr iface,
-                                unsigned int flags)
-{
-    testDriverPtr privconn = iface->conn->privateData;
-    virInterfaceObjPtr privinterface;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privinterface = virInterfaceFindByName(&privconn->ifaces,
-                                           iface->name);
-
-    if (privinterface == NULL) {
-        virReportError(VIR_ERR_NO_INTERFACE, NULL);
-        goto cleanup;
-    }
-
-    if (privinterface->active == 0) {
-        virReportError(VIR_ERR_OPERATION_INVALID, NULL);
-        goto cleanup;
-    }
-
-    privinterface->active = 0;
-    ret = 0;
-
- cleanup:
-    if (privinterface)
-        virInterfaceObjUnlock(privinterface);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-
-
-/*
- * Storage Driver routines
- */
-
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
-{
-
-    pool->def->capacity = defaultPoolCap;
-    pool->def->allocation = defaultPoolAlloc;
-    pool->def->available = defaultPoolCap - defaultPoolAlloc;
-
-    return VIR_STRDUP(pool->configFile, "");
-}
-
-
-static virStoragePoolPtr
-testStoragePoolLookupByUUID(virConnectPtr conn,
-                            const unsigned char *uuid)
-{
-    testDriverPtr privconn = conn->privateData;
-    virStoragePoolObjPtr pool;
-    virStoragePoolPtr ret = NULL;
-
-    testDriverLock(privconn);
-    pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
-    testDriverUnlock(privconn);
-
-    if (pool == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
-                            NULL, NULL);
-
- cleanup:
-    if (pool)
-        virStoragePoolObjUnlock(pool);
-    return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByName(virConnectPtr conn,
-                            const char *name)
-{
-    testDriverPtr privconn = conn->privateData;
-    virStoragePoolObjPtr pool;
-    virStoragePoolPtr ret = NULL;
-
-    testDriverLock(privconn);
-    pool = virStoragePoolObjFindByName(&privconn->pools, name);
-    testDriverUnlock(privconn);
-
-    if (pool == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
-        goto cleanup;
-    }
-
-    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
-                            NULL, NULL);
-
- cleanup:
-    if (pool)
-        virStoragePoolObjUnlock(pool);
-    return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByVolume(virStorageVolPtr vol)
-{
-    return testStoragePoolLookupByName(vol->conn, vol->pool);
-}
-
-static int
-testConnectNumOfStoragePools(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    int numActive = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    for (i = 0; i < privconn->pools.count; i++)
-        if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
-            numActive++;
-    testDriverUnlock(privconn);
-
-    return numActive;
-}
-
-static int
-testConnectListStoragePools(virConnectPtr conn,
-                            char **const names,
-                            int nnames)
-{
-    testDriverPtr privconn = conn->privateData;
-    int n = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    memset(names, 0, sizeof(*names)*nnames);
-    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
-        virStoragePoolObjLock(privconn->pools.objs[i]);
-        if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
-            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
-            virStoragePoolObjUnlock(privconn->pools.objs[i]);
-            goto error;
-        }
-        virStoragePoolObjUnlock(privconn->pools.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    return n;
-
- error:
-    for (n = 0; n < nnames; n++)
-        VIR_FREE(names[n]);
-    testDriverUnlock(privconn);
-    return -1;
-}
-
-static int
-testConnectNumOfDefinedStoragePools(virConnectPtr conn)
-{
-    testDriverPtr privconn = conn->privateData;
-    int numInactive = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    for (i = 0; i < privconn->pools.count; i++) {
-        virStoragePoolObjLock(privconn->pools.objs[i]);
-        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
-            numInactive++;
-        virStoragePoolObjUnlock(privconn->pools.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    return numInactive;
-}
-
-static int
-testConnectListDefinedStoragePools(virConnectPtr conn,
-                                   char **const names,
-                                   int nnames)
-{
-    testDriverPtr privconn = conn->privateData;
-    int n = 0;
-    size_t i;
-
-    testDriverLock(privconn);
-    memset(names, 0, sizeof(*names)*nnames);
-    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
-        virStoragePoolObjLock(privconn->pools.objs[i]);
-        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
-            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
-            virStoragePoolObjUnlock(privconn->pools.objs[i]);
-            goto error;
-        }
-        virStoragePoolObjUnlock(privconn->pools.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    return n;
-
- error:
-    for (n = 0; n < nnames; n++)
-        VIR_FREE(names[n]);
-    testDriverUnlock(privconn);
-    return -1;
-}
-
-static int
-testConnectListAllStoragePools(virConnectPtr conn,
-                               virStoragePoolPtr **pools,
-                               unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    int ret = -1;
-
-    virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
-
-    testDriverLock(privconn);
-    ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
-                                      NULL, flags);
-    testDriverUnlock(privconn);
-
-    return ret;
-}
-
-static int testStoragePoolIsActive(virStoragePoolPtr pool)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr obj;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
-    testDriverUnlock(privconn);
-    if (!obj) {
-        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
-        goto cleanup;
-    }
-    ret = virStoragePoolObjIsActive(obj);
-
- cleanup:
-    if (obj)
-        virStoragePoolObjUnlock(obj);
-    return ret;
-}
-
-static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr obj;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
-    testDriverUnlock(privconn);
-    if (!obj) {
-        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
-        goto cleanup;
-    }
-    ret = obj->configFile ? 1 : 0;
-
- cleanup:
-    if (obj)
-        virStoragePoolObjUnlock(obj);
-    return ret;
-}
-
-
-
-static int
-testStoragePoolCreate(virStoragePoolPtr pool,
-                      unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is already active"), pool->name);
-        goto cleanup;
-    }
-
-    privpool->active = 1;
-
-    event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
-                                            VIR_STORAGE_POOL_EVENT_STARTED,
-                                            0);
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static char *
-testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                  const char *type,
-                                  const char *srcSpec,
-                                  unsigned int flags)
-{
-    virStoragePoolSourcePtr source = NULL;
-    int pool_type;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    pool_type = virStoragePoolTypeFromString(type);
-    if (!pool_type) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("unknown storage pool type %s"), type);
-        goto cleanup;
-    }
-
-    if (srcSpec) {
-        source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
-        if (!source)
-            goto cleanup;
-    }
-
-    switch (pool_type) {
-
-    case VIR_STORAGE_POOL_LOGICAL:
-        ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
-        break;
-
-    case VIR_STORAGE_POOL_NETFS:
-        if (!source || !source->hosts[0].name) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           "%s", _("hostname must be specified for netfs sources"));
-            goto cleanup;
-        }
-
-        ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
-                                 source->hosts[0].name));
-        break;
-
-    default:
-        virReportError(VIR_ERR_NO_SUPPORT,
-                       _("pool type '%s' does not support source discovery"), type);
-    }
-
- cleanup:
-    virStoragePoolSourceFree(source);
-    return ret;
-}
-
-
-static virStoragePoolPtr
-testStoragePoolCreateXML(virConnectPtr conn,
-                         const char *xml,
-                         unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    virStoragePoolDefPtr def;
-    virStoragePoolObjPtr pool = NULL;
-    virStoragePoolPtr ret = NULL;
-    virObjectEventPtr event = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    if (!(def = virStoragePoolDefParseString(xml)))
-        goto cleanup;
-
-    pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
-    if (!pool)
-        pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
-    if (pool) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("storage pool already exists"));
-        goto cleanup;
-    }
-
-    if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
-        goto cleanup;
-    def = NULL;
-
-    if (testStoragePoolObjSetDefaults(pool) == -1) {
-        virStoragePoolObjRemove(&privconn->pools, pool);
-        pool = NULL;
-        goto cleanup;
-    }
-    pool->active = 1;
-
-    event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
-                                            VIR_STORAGE_POOL_EVENT_STARTED,
-                                            0);
-
-    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
-                            NULL, NULL);
-
- cleanup:
-    virStoragePoolDefFree(def);
-    testObjectEventQueue(privconn, event);
-    if (pool)
-        virStoragePoolObjUnlock(pool);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolDefineXML(virConnectPtr conn,
-                         const char *xml,
-                         unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-    virStoragePoolDefPtr def;
-    virStoragePoolObjPtr pool = NULL;
-    virStoragePoolPtr ret = NULL;
-    virObjectEventPtr event = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    if (!(def = virStoragePoolDefParseString(xml)))
-        goto cleanup;
-
-    def->capacity = defaultPoolCap;
-    def->allocation = defaultPoolAlloc;
-    def->available = defaultPoolCap - defaultPoolAlloc;
-
-    if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
-        goto cleanup;
-    def = NULL;
-
-    event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
-                                            VIR_STORAGE_POOL_EVENT_DEFINED,
-                                            0);
-
-    if (testStoragePoolObjSetDefaults(pool) == -1) {
-        virStoragePoolObjRemove(&privconn->pools, pool);
-        pool = NULL;
-        goto cleanup;
-    }
-
-    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
-                            NULL, NULL);
-
- cleanup:
-    virStoragePoolDefFree(def);
-    testObjectEventQueue(privconn, event);
-    if (pool)
-        virStoragePoolObjUnlock(pool);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int
-testStoragePoolUndefine(virStoragePoolPtr pool)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is already active"), pool->name);
-        goto cleanup;
-    }
-
-    event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
-                                            VIR_STORAGE_POOL_EVENT_UNDEFINED,
-                                            0);
-
-    virStoragePoolObjRemove(&privconn->pools, privpool);
-    privpool = NULL;
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    testObjectEventQueue(privconn, event);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-static int
-testStoragePoolBuild(virStoragePoolPtr pool,
-                     unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is already active"), pool->name);
-        goto cleanup;
-    }
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static int
-testStoragePoolDestroy(virStoragePoolPtr pool)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    privpool->active = 0;
-    event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
-                                            VIR_STORAGE_POOL_EVENT_STOPPED,
-                                            0);
-
-    if (privpool->configFile == NULL) {
-        virStoragePoolObjRemove(&privconn->pools, privpool);
-        privpool = NULL;
-    }
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    testDriverUnlock(privconn);
-    return ret;
-}
-
-
-static int
-testStoragePoolDelete(virStoragePoolPtr pool,
-                      unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is already active"), pool->name);
-        goto cleanup;
-    }
-
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static int
-testStoragePoolRefresh(virStoragePoolPtr pool,
-                       unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-    virObjectEventPtr event = NULL;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
-    ret = 0;
-
- cleanup:
-    testObjectEventQueue(privconn, event);
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static int
-testStoragePoolGetInfo(virStoragePoolPtr pool,
-                       virStoragePoolInfoPtr info)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    memset(info, 0, sizeof(virStoragePoolInfo));
-    if (privpool->active)
-        info->state = VIR_STORAGE_POOL_RUNNING;
-    else
-        info->state = VIR_STORAGE_POOL_INACTIVE;
-    info->capacity = privpool->def->capacity;
-    info->allocation = privpool->def->allocation;
-    info->available = privpool->def->available;
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static char *
-testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
-                          unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    ret = virStoragePoolDefFormat(privpool->def);
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static int
-testStoragePoolGetAutostart(virStoragePoolPtr pool,
-                            int *autostart)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!privpool->configFile) {
-        *autostart = 0;
-    } else {
-        *autostart = privpool->autostart;
-    }
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static int
-testStoragePoolSetAutostart(virStoragePoolPtr pool,
-                            int autostart)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!privpool->configFile) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       "%s", _("pool has no config file"));
-        goto cleanup;
-    }
-
-    autostart = (autostart != 0);
-    privpool->autostart = autostart;
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static int
-testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    ret = privpool->volumes.count;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static int
-testStoragePoolListVolumes(virStoragePoolPtr pool,
-                           char **const names,
-                           int maxnames)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    size_t i = 0;
-    int n = 0;
-
-    memset(names, 0, maxnames * sizeof(*names));
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
-        if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
-            goto cleanup;
-    }
-
-    virStoragePoolObjUnlock(privpool);
-    return n;
-
- cleanup:
-    for (n = 0; n < maxnames; n++)
-        VIR_FREE(names[i]);
-
-    memset(names, 0, maxnames * sizeof(*names));
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return -1;
-}
-
-static int
-testStoragePoolListAllVolumes(virStoragePoolPtr obj,
-                              virStorageVolPtr **vols,
-                              unsigned int flags)
-{
-    testDriverPtr privconn = obj->conn->privateData;
-    virStoragePoolObjPtr pool;
-    size_t i;
-    virStorageVolPtr *tmp_vols = NULL;
-    virStorageVolPtr vol = NULL;
-    int nvols = 0;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
-    testDriverUnlock(privconn);
-
-    if (!pool) {
-        virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
-                       _("no storage pool with matching uuid"));
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(pool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("storage pool is not active"));
-        goto cleanup;
-    }
-
-     /* Just returns the volumes count */
-    if (!vols) {
-        ret = pool->volumes.count;
-        goto cleanup;
-    }
-
-    if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
-         goto cleanup;
-
-    for (i = 0; i < pool->volumes.count; i++) {
-        if (!(vol = virGetStorageVol(obj->conn, pool->def->name,
-                                     pool->volumes.objs[i]->name,
-                                     pool->volumes.objs[i]->key,
-                                     NULL, NULL)))
-            goto cleanup;
-        tmp_vols[nvols++] = vol;
-    }
-
-    *vols = tmp_vols;
-    tmp_vols = NULL;
-    ret = nvols;
-
- cleanup:
-    if (tmp_vols) {
-        for (i = 0; i < nvols; i++) {
-            if (tmp_vols[i])
-                virStorageVolFree(tmp_vols[i]);
-        }
-        VIR_FREE(tmp_vols);
-    }
-
-    if (pool)
-        virStoragePoolObjUnlock(pool);
-
-    return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByName(virStoragePoolPtr pool,
-                           const char *name ATTRIBUTE_UNUSED)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol;
-    virStorageVolPtr ret = NULL;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefFindByName(privpool, name);
-
-    if (!privvol) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"), name);
-        goto cleanup;
-    }
-
-    ret = virGetStorageVol(pool->conn, privpool->def->name,
-                           privvol->name, privvol->key,
-                           NULL, NULL);
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static virStorageVolPtr
-testStorageVolLookupByKey(virConnectPtr conn,
-                          const char *key)
-{
-    testDriverPtr privconn = conn->privateData;
-    size_t i;
-    virStorageVolPtr ret = NULL;
-
-    testDriverLock(privconn);
-    for (i = 0; i < privconn->pools.count; i++) {
-        virStoragePoolObjLock(privconn->pools.objs[i]);
-        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
-            virStorageVolDefPtr privvol =
-                virStorageVolDefFindByKey(privconn->pools.objs[i], key);
-
-            if (privvol) {
-                ret = virGetStorageVol(conn,
-                                       privconn->pools.objs[i]->def->name,
-                                       privvol->name,
-                                       privvol->key,
-                                       NULL, NULL);
-                virStoragePoolObjUnlock(privconn->pools.objs[i]);
-                break;
-            }
-        }
-        virStoragePoolObjUnlock(privconn->pools.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    if (!ret)
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching key '%s'"), key);
-
-    return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByPath(virConnectPtr conn,
-                           const char *path)
-{
-    testDriverPtr privconn = conn->privateData;
-    size_t i;
-    virStorageVolPtr ret = NULL;
-
-    testDriverLock(privconn);
-    for (i = 0; i < privconn->pools.count; i++) {
-        virStoragePoolObjLock(privconn->pools.objs[i]);
-        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
-            virStorageVolDefPtr privvol =
-                virStorageVolDefFindByPath(privconn->pools.objs[i], path);
-
-            if (privvol) {
-                ret = virGetStorageVol(conn,
-                                       privconn->pools.objs[i]->def->name,
-                                       privvol->name,
-                                       privvol->key,
-                                       NULL, NULL);
-                virStoragePoolObjUnlock(privconn->pools.objs[i]);
-                break;
-            }
-        }
-        virStoragePoolObjUnlock(privconn->pools.objs[i]);
-    }
-    testDriverUnlock(privconn);
-
-    if (!ret)
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching path '%s'"), path);
-
-    return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXML(virStoragePoolPtr pool,
-                        const char *xmldesc,
-                        unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol = NULL;
-    virStorageVolPtr ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
-    if (privvol == NULL)
-        goto cleanup;
-
-    if (virStorageVolDefFindByName(privpool, privvol->name)) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("storage vol already exists"));
-        goto cleanup;
-    }
-
-    /* Make sure enough space */
-    if ((privpool->def->allocation + privvol->target.allocation) >
-         privpool->def->capacity) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Not enough free space in pool for volume '%s'"),
-                       privvol->name);
-        goto cleanup;
-    }
-
-    if (virAsprintf(&privvol->target.path, "%s/%s",
-                    privpool->def->target.path,
-                    privvol->name) == -1)
-        goto cleanup;
-
-    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
-        VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
-                                privpool->volumes.count, privvol) < 0)
-        goto cleanup;
-
-    privpool->def->allocation += privvol->target.allocation;
-    privpool->def->available = (privpool->def->capacity -
-                                privpool->def->allocation);
-
-    ret = virGetStorageVol(pool->conn, privpool->def->name,
-                           privvol->name, privvol->key,
-                           NULL, NULL);
-    privvol = NULL;
-
- cleanup:
-    virStorageVolDefFree(privvol);
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
-                            const char *xmldesc,
-                            virStorageVolPtr clonevol,
-                            unsigned int flags)
-{
-    testDriverPtr privconn = pool->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol = NULL, origvol = NULL;
-    virStorageVolPtr ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           pool->name);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), pool->name);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
-    if (privvol == NULL)
-        goto cleanup;
-
-    if (virStorageVolDefFindByName(privpool, privvol->name)) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("storage vol already exists"));
-        goto cleanup;
-    }
-
-    origvol = virStorageVolDefFindByName(privpool, clonevol->name);
-    if (!origvol) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"),
-                       clonevol->name);
-        goto cleanup;
-    }
-
-    /* Make sure enough space */
-    if ((privpool->def->allocation + privvol->target.allocation) >
-         privpool->def->capacity) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Not enough free space in pool for volume '%s'"),
-                       privvol->name);
-        goto cleanup;
-    }
-    privpool->def->available = (privpool->def->capacity -
-                                privpool->def->allocation);
-
-    if (virAsprintf(&privvol->target.path, "%s/%s",
-                    privpool->def->target.path,
-                    privvol->name) == -1)
-        goto cleanup;
-
-    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
-        VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
-                                privpool->volumes.count, privvol) < 0)
-        goto cleanup;
-
-    privpool->def->allocation += privvol->target.allocation;
-    privpool->def->available = (privpool->def->capacity -
-                                privpool->def->allocation);
-
-    ret = virGetStorageVol(pool->conn, privpool->def->name,
-                           privvol->name, privvol->key,
-                           NULL, NULL);
-    privvol = NULL;
-
- cleanup:
-    virStorageVolDefFree(privvol);
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static int
-testStorageVolDelete(virStorageVolPtr vol,
-                     unsigned int flags)
-{
-    testDriverPtr privconn = vol->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol;
-    size_t i;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           vol->pool);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-
-    privvol = virStorageVolDefFindByName(privpool, vol->name);
-
-    if (privvol == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"),
-                       vol->name);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), vol->pool);
-        goto cleanup;
-    }
-
-
-    privpool->def->allocation -= privvol->target.allocation;
-    privpool->def->available = (privpool->def->capacity -
-                                privpool->def->allocation);
-
-    for (i = 0; i < privpool->volumes.count; i++) {
-        if (privpool->volumes.objs[i] == privvol) {
-            virStorageVolDefFree(privvol);
-
-            VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
-            break;
-        }
-    }
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-static int testStorageVolumeTypeForPool(int pooltype)
-{
-
-    switch (pooltype) {
-        case VIR_STORAGE_POOL_DIR:
-        case VIR_STORAGE_POOL_FS:
-        case VIR_STORAGE_POOL_NETFS:
-            return VIR_STORAGE_VOL_FILE;
-        default:
-            return VIR_STORAGE_VOL_BLOCK;
-    }
-}
-
-static int
-testStorageVolGetInfo(virStorageVolPtr vol,
-                      virStorageVolInfoPtr info)
-{
-    testDriverPtr privconn = vol->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol;
-    int ret = -1;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           vol->pool);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefFindByName(privpool, vol->name);
-
-    if (privvol == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"),
-                       vol->name);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), vol->pool);
-        goto cleanup;
-    }
-
-    memset(info, 0, sizeof(*info));
-    info->type = testStorageVolumeTypeForPool(privpool->def->type);
-    info->capacity = privvol->target.capacity;
-    info->allocation = privvol->target.allocation;
-    ret = 0;
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static char *
-testStorageVolGetXMLDesc(virStorageVolPtr vol,
-                         unsigned int flags)
-{
-    testDriverPtr privconn = vol->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           vol->pool);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefFindByName(privpool, vol->name);
-
-    if (privvol == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"),
-                       vol->name);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), vol->pool);
-        goto cleanup;
-    }
-
-    ret = virStorageVolDefFormat(privpool->def, privvol);
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-static char *
-testStorageVolGetPath(virStorageVolPtr vol)
-{
-    testDriverPtr privconn = vol->conn->privateData;
-    virStoragePoolObjPtr privpool;
-    virStorageVolDefPtr privvol;
-    char *ret = NULL;
-
-    testDriverLock(privconn);
-    privpool = virStoragePoolObjFindByName(&privconn->pools,
-                                           vol->pool);
-    testDriverUnlock(privconn);
-
-    if (privpool == NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
-        goto cleanup;
-    }
-
-    privvol = virStorageVolDefFindByName(privpool, vol->name);
-
-    if (privvol == NULL) {
-        virReportError(VIR_ERR_NO_STORAGE_VOL,
-                       _("no storage vol with matching name '%s'"),
-                       vol->name);
-        goto cleanup;
-    }
-
-    if (!virStoragePoolObjIsActive(privpool)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("storage pool '%s' is not active"), vol->pool);
-        goto cleanup;
-    }
-
-    ignore_value(VIR_STRDUP(ret, privvol->target.path));
-
- cleanup:
-    if (privpool)
-        virStoragePoolObjUnlock(privpool);
-    return ret;
-}
-
-
-/* Node device implementations */
-
-static int
-testNodeNumOfDevices(virConnectPtr conn,
-                     const char *cap,
-                     unsigned int flags)
-{
-    testDriverPtr driver = conn->privateData;
-    int ndevs = 0;
-    size_t i;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(driver);
-    for (i = 0; i < driver->devs.count; i++)
-        if ((cap == NULL) ||
-            virNodeDeviceHasCap(driver->devs.objs[i], cap))
-            ++ndevs;
-    testDriverUnlock(driver);
-
-    return ndevs;
-}
-
-static int
-testNodeListDevices(virConnectPtr conn,
-                    const char *cap,
-                    char **const names,
-                    int maxnames,
-                    unsigned int flags)
-{
-    testDriverPtr driver = conn->privateData;
-    int ndevs = 0;
-    size_t i;
-
-    virCheckFlags(0, -1);
-
-    testDriverLock(driver);
-    for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
-        virNodeDeviceObjLock(driver->devs.objs[i]);
-        if (cap == NULL ||
-            virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
-            if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
-                virNodeDeviceObjUnlock(driver->devs.objs[i]);
-                goto failure;
-            }
-        }
-        virNodeDeviceObjUnlock(driver->devs.objs[i]);
-    }
-    testDriverUnlock(driver);
-
-    return ndevs;
-
- failure:
-    testDriverUnlock(driver);
-    --ndevs;
-    while (--ndevs >= 0)
-        VIR_FREE(names[ndevs]);
-    return -1;
-}
-
-static virNodeDevicePtr
-testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
-{
-    testDriverPtr driver = conn->privateData;
-    virNodeDeviceObjPtr obj;
-    virNodeDevicePtr ret = NULL;
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       name);
-        goto cleanup;
-    }
-
-    ret = virGetNodeDevice(conn, name);
-
- cleanup:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    return ret;
-}
-
-static char *
-testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
-                         unsigned int flags)
-{
-    testDriverPtr driver = dev->conn->privateData;
-    virNodeDeviceObjPtr obj;
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       dev->name);
-        goto cleanup;
-    }
-
-    ret = virNodeDeviceDefFormat(obj->def);
-
- cleanup:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    return ret;
-}
-
-static char *
-testNodeDeviceGetParent(virNodeDevicePtr dev)
-{
-    testDriverPtr driver = dev->conn->privateData;
-    virNodeDeviceObjPtr obj;
-    char *ret = NULL;
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       dev->name);
-        goto cleanup;
-    }
-
-    if (obj->def->parent) {
-        ignore_value(VIR_STRDUP(ret, obj->def->parent));
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("no parent for this device"));
-    }
-
- cleanup:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    return ret;
-}
-
-
-static int
-testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
-{
-    testDriverPtr driver = dev->conn->privateData;
-    virNodeDeviceObjPtr obj;
-    virNodeDevCapsDefPtr caps;
-    int ncaps = 0;
-    int ret = -1;
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       dev->name);
-        goto cleanup;
-    }
-
-    for (caps = obj->def->caps; caps; caps = caps->next)
-        ++ncaps;
-    ret = ncaps;
-
- cleanup:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    return ret;
-}
-
-
-static int
-testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
-{
-    testDriverPtr driver = dev->conn->privateData;
-    virNodeDeviceObjPtr obj;
-    virNodeDevCapsDefPtr caps;
-    int ncaps = 0;
-    int ret = -1;
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       dev->name);
-        goto cleanup;
-    }
-
-    for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
-        if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
-            goto cleanup;
-    }
-    ret = ncaps;
-
- cleanup:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    if (ret == -1) {
-        --ncaps;
-        while (--ncaps >= 0)
-            VIR_FREE(names[ncaps]);
-    }
-    return ret;
-}
-
-static virNodeDevicePtr
-testNodeDeviceCreateXML(virConnectPtr conn,
-                        const char *xmlDesc,
-                        unsigned int flags)
-{
-    testDriverPtr driver = conn->privateData;
-    virNodeDeviceDefPtr def = NULL;
-    virNodeDeviceObjPtr obj = NULL;
-    char *wwnn = NULL, *wwpn = NULL;
-    int parent_host = -1;
-    virNodeDevicePtr dev = NULL;
-    virNodeDevCapsDefPtr caps;
-    virObjectEventPtr event = NULL;
-
-    virCheckFlags(0, NULL);
-
-    testDriverLock(driver);
-
-    def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
-    if (def == NULL)
-        goto cleanup;
-
-    /* We run these next two simply for validation */
-    if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
-        goto cleanup;
-
-    if (virNodeDeviceGetParentHost(&driver->devs,
-                                   def->name,
-                                   def->parent,
-                                   &parent_host) == -1) {
-        goto cleanup;
-    }
-
-    /* 'name' is supposed to be filled in by the node device backend, which
-     * we don't have. Use WWPN instead. */
-    VIR_FREE(def->name);
-    if (VIR_STRDUP(def->name, wwpn) < 0)
-        goto cleanup;
-
-    /* Fill in a random 'host' and 'unique_id' value,
-     * since this would also come from the backend */
-    caps = def->caps;
-    while (caps) {
-        if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
-            continue;
-
-        caps->data.scsi_host.host = virRandomBits(10);
-        caps->data.scsi_host.unique_id = 2;
-        caps = caps->next;
-    }
-
-
-    if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
-        goto cleanup;
-    virNodeDeviceObjUnlock(obj);
-
-    event = virNodeDeviceEventLifecycleNew(def->name,
-                                           VIR_NODE_DEVICE_EVENT_CREATED,
-                                           0);
-
-    dev = virGetNodeDevice(conn, def->name);
-    def = NULL;
- cleanup:
-    testDriverUnlock(driver);
-    virNodeDeviceDefFree(def);
-    testObjectEventQueue(driver, event);
-    VIR_FREE(wwnn);
-    VIR_FREE(wwpn);
-    return dev;
-}
-
-static int
-testNodeDeviceDestroy(virNodeDevicePtr dev)
-{
-    int ret = 0;
-    testDriverPtr driver = dev->conn->privateData;
-    virNodeDeviceObjPtr obj = NULL;
-    char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
-    int parent_host = -1;
-    virObjectEventPtr event = NULL;
-
-    testDriverLock(driver);
-    obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-    testDriverUnlock(driver);
-
-    if (!obj) {
-        virReportError(VIR_ERR_NO_NODE_DEVICE,
-                       _("no node device with matching name '%s'"),
-                       dev->name);
-        goto out;
-    }
-
-    if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
-        goto out;
-
-    if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
-        goto out;
-
-    /* virNodeDeviceGetParentHost will cause the device object's lock to be
-     * taken, so we have to dup the parent's name and drop the lock
-     * before calling it.  We don't need the reference to the object
-     * any more once we have the parent's name.  */
-    virNodeDeviceObjUnlock(obj);
-
-    /* We do this just for basic validation */
-    if (virNodeDeviceGetParentHost(&driver->devs,
-                                   dev->name,
-                                   parent_name,
-                                   &parent_host) == -1) {
-        obj = NULL;
-        goto out;
-    }
-
-    event = virNodeDeviceEventLifecycleNew(dev->name,
-                                           VIR_NODE_DEVICE_EVENT_DELETED,
-                                           0);
-
-    virNodeDeviceObjLock(obj);
-    virNodeDeviceObjRemove(&driver->devs, &obj);
-
- out:
-    if (obj)
-        virNodeDeviceObjUnlock(obj);
-    testObjectEventQueue(driver, event);
-    VIR_FREE(parent_name);
-    VIR_FREE(wwnn);
-    VIR_FREE(wwpn);
-    return ret;
-}
-
-
-/* Domain event implementations */
-static int
-testConnectDomainEventRegister(virConnectPtr conn,
-                               virConnectDomainEventCallback callback,
-                               void *opaque,
-                               virFreeCallback freecb)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virDomainEventStateRegister(conn, driver->eventState,
-                                    callback, opaque, freecb) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-
-static int
-testConnectDomainEventDeregister(virConnectPtr conn,
-                                 virConnectDomainEventCallback callback)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virDomainEventStateDeregister(conn, driver->eventState,
-                                      callback) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-
-static int
-testConnectDomainEventRegisterAny(virConnectPtr conn,
-                                  virDomainPtr dom,
-                                  int eventID,
-                                  virConnectDomainEventGenericCallback callback,
-                                  void *opaque,
-                                  virFreeCallback freecb)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret;
-
-    if (virDomainEventStateRegisterID(conn, driver->eventState,
-                                      dom, eventID,
-                                      callback, opaque, freecb, &ret) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectDomainEventDeregisterAny(virConnectPtr conn,
-                                    int callbackID)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virObjectEventStateDeregisterID(conn, driver->eventState,
-                                        callbackID) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-
-static int
-testConnectNetworkEventRegisterAny(virConnectPtr conn,
-                                   virNetworkPtr net,
-                                   int eventID,
-                                   virConnectNetworkEventGenericCallback callback,
-                                   void *opaque,
-                                   virFreeCallback freecb)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret;
-
-    if (virNetworkEventStateRegisterID(conn, driver->eventState,
-                                       net, eventID, callback,
-                                       opaque, freecb, &ret) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectNetworkEventDeregisterAny(virConnectPtr conn,
-                                     int callbackID)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virObjectEventStateDeregisterID(conn, driver->eventState,
-                                        callbackID) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
-                                       virStoragePoolPtr pool,
-                                       int eventID,
-                                       virConnectStoragePoolEventGenericCallback callback,
-                                       void *opaque,
-                                       virFreeCallback freecb)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret;
-
-    if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
-                                           pool, eventID, callback,
-                                           opaque, freecb, &ret) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
-                                         int callbackID)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virObjectEventStateDeregisterID(conn, driver->eventState,
-                                        callbackID) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
-                                      virNodeDevicePtr dev,
-                                      int eventID,
-                                      virConnectNodeDeviceEventGenericCallback callback,
-                                      void *opaque,
-                                      virFreeCallback freecb)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret;
-
-    if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
-                                          dev, eventID, callback,
-                                          opaque, freecb, &ret) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int
-testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
-                                        int callbackID)
-{
-    testDriverPtr driver = conn->privateData;
-    int ret = 0;
-
-    if (virObjectEventStateDeregisterID(conn, driver->eventState,
-                                        callbackID) < 0)
-        ret = -1;
-
-    return ret;
-}
-
-static int testConnectListAllDomains(virConnectPtr conn,
-                                     virDomainPtr **domains,
-                                     unsigned int flags)
-{
-    testDriverPtr privconn = conn->privateData;
-
-    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
-
-    return virDomainObjListExport(privconn->domains, conn, domains,
-                                  NULL, flags);
-}
-
-static int
-testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
-                  unsigned char **cpumap,
-                  unsigned int *online,
-                  unsigned int flags)
-{
-    virCheckFlags(0, -1);
-
-    if (cpumap) {
-        if (VIR_ALLOC_N(*cpumap, 1) < 0)
-            return -1;
-        *cpumap[0] = 0x15;
-    }
-
-    if (online)
-        *online = 3;
-
-    return  8;
-}
-
-static char *
-testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
-                     virStreamPtr st,
-                     unsigned int screen ATTRIBUTE_UNUSED,
-                     unsigned int flags)
-{
-    char *ret = NULL;
-
-    virCheckFlags(0, NULL);
-
-    if (VIR_STRDUP(ret, "image/png") < 0)
-        return NULL;
-
-    if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
-        VIR_FREE(ret);
-
-    return ret;
-}
-
-static int
-testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
-                            const char *arch,
-                            char ***models,
-                            unsigned int flags)
-{
-    virCheckFlags(0, -1);
-    return cpuGetModels(arch, models);
-}
-
-static int
-testDomainManagedSave(virDomainPtr dom, unsigned int flags)
-{
-    testDriverPtr privconn = dom->conn->privateData;
-    virDomainObjPtr vm = NULL;
-    virObjectEventPtr event = NULL;
-    int ret = -1;
-
-    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
-                  VIR_DOMAIN_SAVE_RUNNING |
-                  VIR_DOMAIN_SAVE_PAUSED, -1);
-
-    if (!(vm = testDomObjFromDomain(dom)))
-        return -1;
-
-    if (!virDomainObjIsActive(vm)) {
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       "%s", _("domain is not running"));
-        goto cleanup;
-    }
-
-    if (!vm->persistent) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("cannot do managed save for transient domain"));
-        goto cleanup;
-    }
-
-    testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
-    event = virDomainEventLifecycleNewFromObj(vm,
-                                     VIR_DOMAIN_EVENT_STOPPED,
-                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
-    vm->hasManagedSave = true;
-
-    ret = 0;
- cleanup:
-    virDomainObjEndAPI(&vm);
-    testObjectEventQueue(privconn, event);
-
-    return ret;
-}
-
-
-static int
-testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
-{
-    virDomainObjPtr vm;
-    int ret;
-
-    virCheckFlags(0, -1);
-
-    if (!(vm = testDomObjFromDomain(dom)))
-        return -1;
-
-    ret = vm->hasManagedSave;
-
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-static int
-testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
-{
-    virDomainObjPtr vm;
-
-    virCheckFlags(0, -1);
-
-    if (!(vm = testDomObjFromDomain(dom)))
-        return -1;
-
-    vm->hasManagedSave = false;
-
-    virDomainObjEndAPI(&vm);
-    return 0;
-}
-
-
-/*
- * Snapshot APIs
- */
-
-static virDomainSnapshotObjPtr
-testSnapObjFromName(virDomainObjPtr vm,
-                    const char *name)
-{
-    virDomainSnapshotObjPtr snap = NULL;
-    snap = virDomainSnapshotFindByName(vm->snapshots, name);
-    if (!snap)
-        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
-                       _("no domain snapshot with matching name '%s'"),
-                       name);
-    return snap;
-}
-
-static virDomainSnapshotObjPtr
-testSnapObjFromSnapshot(virDomainObjPtr vm,
-                        virDomainSnapshotPtr snapshot)
-{
-    return testSnapObjFromName(vm, snapshot->name);
-}
-
-static virDomainObjPtr
-testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
-{
-    return testDomObjFromDomain(snapshot->domain);
-}
-
-static int
-testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    int n;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return -1;
-
-    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
-
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static int
-testDomainSnapshotListNames(virDomainPtr domain,
-                            char **names,
-                            int nameslen,
-                            unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    int n;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return -1;
-
-    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
-                                         flags);
-
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static int
-testDomainListAllSnapshots(virDomainPtr domain,
-                           virDomainSnapshotPtr **snaps,
-                           unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    int n;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return -1;
-
-    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
-
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static int
-testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
-                                    char **names,
-                                    int nameslen,
-                                    unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    int n = -1;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
-                                         flags);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static int
-testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
-                              unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    int n = -1;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static int
-testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
-                                  virDomainSnapshotPtr **snaps,
-                                  unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    int n = -1;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
-                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
-                               flags);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return n;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotLookupByName(virDomainPtr domain,
-                               const char *name,
-                               unsigned int flags)
-{
-    virDomainObjPtr vm;
-    virDomainSnapshotObjPtr snap = NULL;
-    virDomainSnapshotPtr snapshot = NULL;
-
-    virCheckFlags(0, NULL);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return NULL;
-
-    if (!(snap = testSnapObjFromName(vm, name)))
-        goto cleanup;
-
-    snapshot = virGetDomainSnapshot(domain, snap->def->name);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return snapshot;
-}
-
-static int
-testDomainHasCurrentSnapshot(virDomainPtr domain,
-                             unsigned int flags)
-{
-    virDomainObjPtr vm;
-    int ret;
-
-    virCheckFlags(0, -1);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return -1;
-
-    ret = (vm->current_snapshot != NULL);
-
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
-                            unsigned int flags)
-{
-    virDomainObjPtr vm;
-    virDomainSnapshotObjPtr snap = NULL;
-    virDomainSnapshotPtr parent = NULL;
-
-    virCheckFlags(0, NULL);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return NULL;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    if (!snap->def->parent) {
-        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
-                       _("snapshot '%s' does not have a parent"),
-                       snap->def->name);
-        goto cleanup;
-    }
-
-    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return parent;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCurrent(virDomainPtr domain,
-                          unsigned int flags)
-{
-    virDomainObjPtr vm;
-    virDomainSnapshotPtr snapshot = NULL;
-
-    virCheckFlags(0, NULL);
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        return NULL;
-
-    if (!vm->current_snapshot) {
-        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
-                       _("the domain does not have a current snapshot"));
-        goto cleanup;
-    }
-
-    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return snapshot;
-}
-
-static char *
-testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
-                             unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    char *xml = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-    testDriverPtr privconn = snapshot->domain->conn->privateData;
-
-    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return NULL;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    virUUIDFormat(snapshot->domain->uuid, uuidstr);
-
-    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
-                                     virDomainDefFormatConvertXMLFlags(flags),
-                                     0);
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return xml;
-}
-
-static int
-testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
-                            unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    int ret;
-
-    virCheckFlags(0, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    ret = (vm->current_snapshot &&
-           STREQ(snapshot->name, vm->current_snapshot->def->name));
-
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-
-static int
-testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
-                              unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    int ret = -1;
-
-    virCheckFlags(0, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!testSnapObjFromSnapshot(vm, snapshot))
-        goto cleanup;
-
-    ret = 1;
-
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-static int
-testDomainSnapshotAlignDisks(virDomainObjPtr vm,
-                             virDomainSnapshotDefPtr def,
-                             unsigned int flags)
-{
-    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
-    bool align_match = true;
-
-    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
-        align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
-        align_match = false;
-        if (virDomainObjIsActive(vm))
-            def->state = VIR_DOMAIN_DISK_SNAPSHOT;
-        else
-            def->state = VIR_DOMAIN_SHUTOFF;
-        def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
-    } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
-        def->state = virDomainObjGetState(vm, NULL);
-        align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
-        align_match = false;
-    } else {
-        def->state = virDomainObjGetState(vm, NULL);
-        def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
-                      VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
-                      VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
-    }
-
-    return virDomainSnapshotAlignDisks(def, align_location, align_match);
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCreateXML(virDomainPtr domain,
-                            const char *xmlDesc,
-                            unsigned int flags)
-{
-    testDriverPtr privconn = domain->conn->privateData;
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotDefPtr def = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    virDomainSnapshotPtr snapshot = NULL;
-    virObjectEventPtr event = NULL;
-    char *xml = NULL;
-    bool update_current = true;
-    bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
-    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
-
-    /*
-     * DISK_ONLY: Not implemented yet
-     * REUSE_EXT: Not implemented yet
-     *
-     * NO_METADATA: Explicitly not implemented
-     *
-     * REDEFINE + CURRENT: Implemented
-     * HALT: Implemented
-     * QUIESCE: Nothing to do
-     * ATOMIC: Nothing to do
-     * LIVE: Nothing to do
-     */
-    virCheckFlags(
-        VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
-        VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
-        VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
-        VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
-        VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
-        VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
-
-    if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
-        update_current = false;
-    if (redefine)
-        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
-
-    if (!(vm = testDomObjFromDomain(domain)))
-        goto cleanup;
-
-    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("cannot halt after transient domain snapshot"));
-        goto cleanup;
-    }
-
-    if (!(def = virDomainSnapshotDefParseString(xmlDesc,
-                                                privconn->caps,
-                                                privconn->xmlopt,
-                                                parse_flags)))
-        goto cleanup;
-
-    if (redefine) {
-        if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
-                                          &update_current, flags) < 0)
-            goto cleanup;
-    } else {
-        if (!(def->dom = virDomainDefCopy(vm->def,
-                                          privconn->caps,
-                                          privconn->xmlopt,
-                                          true)))
-            goto cleanup;
-
-        if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
-            goto cleanup;
-    }
-
-    if (!snap) {
-        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
-            goto cleanup;
-        def = NULL;
-    }
-
-    if (!redefine) {
-        if (vm->current_snapshot &&
-            (VIR_STRDUP(snap->def->parent,
-                        vm->current_snapshot->def->name) < 0))
-            goto cleanup;
-
-        if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
-            virDomainObjIsActive(vm)) {
-            testDomainShutdownState(domain, vm,
-                                    VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
-            event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
-                                    VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
-        }
-    }
-
-    snapshot = virGetDomainSnapshot(domain, snap->def->name);
- cleanup:
-    VIR_FREE(xml);
-    if (vm) {
-        if (snapshot) {
-            virDomainSnapshotObjPtr other;
-            if (update_current)
-                vm->current_snapshot = snap;
-            other = virDomainSnapshotFindByName(vm->snapshots,
-                                                snap->def->parent);
-            snap->parent = other;
-            other->nchildren++;
-            snap->sibling = other->first_child;
-            other->first_child = snap;
-        }
-        virDomainObjEndAPI(&vm);
-    }
-    testObjectEventQueue(privconn, event);
-    virDomainSnapshotDefFree(def);
-    return snapshot;
-}
-
-
-typedef struct _testSnapRemoveData testSnapRemoveData;
-typedef testSnapRemoveData *testSnapRemoveDataPtr;
-struct _testSnapRemoveData {
-    virDomainObjPtr vm;
-    bool current;
-};
-
-static int
-testDomainSnapshotDiscardAll(void *payload,
-                             const void *name ATTRIBUTE_UNUSED,
-                             void *data)
-{
-    virDomainSnapshotObjPtr snap = payload;
-    testSnapRemoveDataPtr curr = data;
-
-    if (snap->def->current)
-        curr->current = true;
-    virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
-    return 0;
-}
-
-typedef struct _testSnapReparentData testSnapReparentData;
-typedef testSnapReparentData *testSnapReparentDataPtr;
-struct _testSnapReparentData {
-    virDomainSnapshotObjPtr parent;
-    virDomainObjPtr vm;
-    int err;
-    virDomainSnapshotObjPtr last;
-};
-
-static int
-testDomainSnapshotReparentChildren(void *payload,
-                                   const void *name ATTRIBUTE_UNUSED,
-                                   void *data)
-{
-    virDomainSnapshotObjPtr snap = payload;
-    testSnapReparentDataPtr rep = data;
-
-    if (rep->err < 0)
-        return 0;
-
-    VIR_FREE(snap->def->parent);
-    snap->parent = rep->parent;
-
-    if (rep->parent->def &&
-        VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
-        rep->err = -1;
-        return 0;
-    }
-
-    if (!snap->sibling)
-        rep->last = snap;
-    return 0;
-}
-
-static int
-testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
-                         unsigned int flags)
-{
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    virDomainSnapshotObjPtr parentsnap = NULL;
-    int ret = -1;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
-                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
-                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
-        testSnapRemoveData rem;
-        rem.vm = vm;
-        rem.current = false;
-        virDomainSnapshotForEachDescendant(snap,
-                                           testDomainSnapshotDiscardAll,
-                                           &rem);
-        if (rem.current) {
-            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
-                snap->def->current = true;
-            vm->current_snapshot = snap;
-        }
-    } else if (snap->nchildren) {
-        testSnapReparentData rep;
-        rep.parent = snap->parent;
-        rep.vm = vm;
-        rep.err = 0;
-        rep.last = NULL;
-        virDomainSnapshotForEachChild(snap,
-                                      testDomainSnapshotReparentChildren,
-                                      &rep);
-        if (rep.err < 0)
-            goto cleanup;
-
-        /* Can't modify siblings during ForEachChild, so do it now.  */
-        snap->parent->nchildren += snap->nchildren;
-        rep.last->sibling = snap->parent->first_child;
-        snap->parent->first_child = snap->first_child;
-    }
-
-    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
-        snap->nchildren = 0;
-        snap->first_child = NULL;
-    } else {
-        virDomainSnapshotDropParent(snap);
-        if (snap == vm->current_snapshot) {
-            if (snap->def->parent) {
-                parentsnap = virDomainSnapshotFindByName(vm->snapshots,
-                                                         snap->def->parent);
-                if (!parentsnap) {
-                    VIR_WARN("missing parent snapshot matching name '%s'",
-                             snap->def->parent);
-                } else {
-                    parentsnap->def->current = true;
-                }
-            }
-            vm->current_snapshot = parentsnap;
-        }
-        virDomainSnapshotObjListRemove(vm->snapshots, snap);
-    }
-
-    ret = 0;
- cleanup:
-    virDomainObjEndAPI(&vm);
-    return ret;
-}
-
-static int
-testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
-                           unsigned int flags)
-{
-    testDriverPtr privconn = snapshot->domain->conn->privateData;
-    virDomainObjPtr vm = NULL;
-    virDomainSnapshotObjPtr snap = NULL;
-    virObjectEventPtr event = NULL;
-    virObjectEventPtr event2 = NULL;
-    virDomainDefPtr config = NULL;
-    int ret = -1;
-
-    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
-                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
-                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
-
-    /* We have the following transitions, which create the following events:
-     * 1. inactive -> inactive: none
-     * 2. inactive -> running:  EVENT_STARTED
-     * 3. inactive -> paused:   EVENT_STARTED, EVENT_PAUSED
-     * 4. running  -> inactive: EVENT_STOPPED
-     * 5. running  -> running:  none
-     * 6. running  -> paused:   EVENT_PAUSED
-     * 7. paused   -> inactive: EVENT_STOPPED
-     * 8. paused   -> running:  EVENT_RESUMED
-     * 9. paused   -> paused:   none
-     * Also, several transitions occur even if we fail partway through,
-     * and use of FORCE can cause multiple transitions.
-     */
-
-    if (!(vm = testDomObjFromSnapshot(snapshot)))
-        return -1;
-
-    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
-        goto cleanup;
-
-    if (!vm->persistent &&
-        snap->def->state != VIR_DOMAIN_RUNNING &&
-        snap->def->state != VIR_DOMAIN_PAUSED &&
-        (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
-                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("transient domain needs to request run or pause "
-                         "to revert to inactive snapshot"));
-        goto cleanup;
-    }
-
-    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
-        if (!snap->def->dom) {
-            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
-                           _("snapshot '%s' lacks domain '%s' rollback info"),
-                           snap->def->name, vm->def->name);
-            goto cleanup;
-        }
-        if (virDomainObjIsActive(vm) &&
-            !(snap->def->state == VIR_DOMAIN_RUNNING
-              || snap->def->state == VIR_DOMAIN_PAUSED) &&
-            (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
-                      VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
-            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
-                           _("must respawn guest to start inactive snapshot"));
-            goto cleanup;
-        }
-    }
-
-
-    if (vm->current_snapshot) {
-        vm->current_snapshot->def->current = false;
-        vm->current_snapshot = NULL;
-    }
-
-    snap->def->current = true;
-    config = virDomainDefCopy(snap->def->dom,
-                              privconn->caps, privconn->xmlopt, true);
-    if (!config)
-        goto cleanup;
-
-    if (snap->def->state == VIR_DOMAIN_RUNNING ||
-        snap->def->state == VIR_DOMAIN_PAUSED) {
-        /* Transitions 2, 3, 5, 6, 8, 9 */
-        bool was_running = false;
-        bool was_stopped = false;
-
-        if (virDomainObjIsActive(vm)) {
-            /* Transitions 5, 6, 8, 9 */
-            /* Check for ABI compatibility.  */
-            if (!virDomainDefCheckABIStability(vm->def, config)) {
-                virErrorPtr err = virGetLastError();
-
-                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
-                    /* Re-spawn error using correct category. */
-                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
-                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
-                                       err->str2);
-                    goto cleanup;
-                }
-
-                virResetError(err);
-                testDomainShutdownState(snapshot->domain, vm,
-                                        VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
-                event = virDomainEventLifecycleNewFromObj(vm,
-                            VIR_DOMAIN_EVENT_STOPPED,
-                            VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
-                testObjectEventQueue(privconn, event);
-                goto load;
-            }
-
-            if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
-                /* Transitions 5, 6 */
-                was_running = true;
-                virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
-                                     VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
-                /* Create an event now in case the restore fails, so
-                 * that user will be alerted that they are now paused.
-                 * If restore later succeeds, we might replace this. */
-                event = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_SUSPENDED,
-                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
-            }
-            virDomainObjAssignDef(vm, config, false, NULL);
-
-        } else {
-            /* Transitions 2, 3 */
-        load:
-            was_stopped = true;
-            virDomainObjAssignDef(vm, config, false, NULL);
-            if (testDomainStartState(privconn, vm,
-                                VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
-                goto cleanup;
-            event = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_STARTED,
-                                VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
-        }
-
-        /* Touch up domain state.  */
-        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
-            (snap->def->state == VIR_DOMAIN_PAUSED ||
-             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
-            /* Transitions 3, 6, 9 */
-            virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
-                                 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
-            if (was_stopped) {
-                /* Transition 3, use event as-is and add event2 */
-                event2 = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_SUSPENDED,
-                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
-            } /* else transition 6 and 9 use event as-is */
-        } else {
-            /* Transitions 2, 5, 8 */
-            virObjectUnref(event);
-            event = NULL;
-
-            if (was_stopped) {
-                /* Transition 2 */
-                event = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_STARTED,
-                                VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
-            } else if (was_running) {
-                /* Transition 8 */
-                event = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_RESUMED,
-                                VIR_DOMAIN_EVENT_RESUMED);
-            }
-        }
-    } else {
-        /* Transitions 1, 4, 7 */
-        virDomainObjAssignDef(vm, config, false, NULL);
-
-        if (virDomainObjIsActive(vm)) {
-            /* Transitions 4, 7 */
-            testDomainShutdownState(snapshot->domain, vm,
-                                    VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
-            event = virDomainEventLifecycleNewFromObj(vm,
-                                    VIR_DOMAIN_EVENT_STOPPED,
-                                    VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
-        }
-
-        if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
-                     VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
-            /* Flush first event, now do transition 2 or 3 */
-            bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
-
-            testObjectEventQueue(privconn, event);
-            event = virDomainEventLifecycleNewFromObj(vm,
-                            VIR_DOMAIN_EVENT_STARTED,
-                            VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
-            if (paused) {
-                event2 = virDomainEventLifecycleNewFromObj(vm,
-                                VIR_DOMAIN_EVENT_SUSPENDED,
-                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
-            }
-        }
-    }
-
-    vm->current_snapshot = snap;
-    ret = 0;
- cleanup:
-    if (event) {
-        testObjectEventQueue(privconn, event);
-        testObjectEventQueue(privconn, event2);
-    } else {
-        virObjectUnref(event2);
-    }
-    virDomainObjEndAPI(&vm);
-
-    return ret;
-}
-
-
-
-static virHypervisorDriver testHypervisorDriver = {
-    .name = "Test",
-    .connectOpen = testConnectOpen, /* 0.1.1 */
-    .connectClose = testConnectClose, /* 0.1.1 */
-    .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
-    .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
-    .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
-    .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
-    .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
-    .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
-    .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
-    .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
-    .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
-    .connectGetType = testConnectGetType, /* 2.3.0 */
-    .connectListDomains = testConnectListDomains, /* 0.1.1 */
-    .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
-    .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
-    .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
-    .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
-    .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
-    .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
-    .domainSuspend = testDomainSuspend, /* 0.1.1 */
-    .domainResume = testDomainResume, /* 0.1.1 */
-    .domainShutdown = testDomainShutdown, /* 0.1.1 */
-    .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
-    .domainReboot = testDomainReboot, /* 0.1.1 */
-    .domainDestroy = testDomainDestroy, /* 0.1.1 */
-    .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
-    .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
-    .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
-    .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
-    .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
-    .domainGetState = testDomainGetState, /* 0.9.2 */
-    .domainSave = testDomainSave, /* 0.3.2 */
-    .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
-    .domainRestore = testDomainRestore, /* 0.3.2 */
-    .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
-    .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
-    .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
-    .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
-    .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
-    .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
-    .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
-    .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
-    .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
-    .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
-    .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
-    .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
-    .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
-    .domainCreate = testDomainCreate, /* 0.1.11 */
-    .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
-    .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
-    .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
-    .domainUndefine = testDomainUndefine, /* 0.1.11 */
-    .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
-    .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
-    .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
-    .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
-    .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
-    .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
-    .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
-    .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
-    .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
-    .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
-    .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
-    .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
-    .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
-    .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
-    .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
-    .domainIsActive = testDomainIsActive, /* 0.7.3 */
-    .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
-    .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
-    .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
-    .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
-    .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
-    .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
-    .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
-    .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
-    .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
-    .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
-    .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
-    .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
-    .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
-
-    .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
-    .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
-    .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
-    .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
-    .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
-    .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
-    .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
-    .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
-    .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
-    .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
-    .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
-    .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
-    .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
-    .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
-    .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
-    .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
-
-    .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
-};
-
-static virNetworkDriver testNetworkDriver = {
-    .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
-    .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
-    .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
-    .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
-    .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
-    .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
-    .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
-    .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
-    .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
-    .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
-    .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
-    .networkUndefine = testNetworkUndefine, /* 0.3.2 */
-    .networkUpdate = testNetworkUpdate, /* 0.10.2 */
-    .networkCreate = testNetworkCreate, /* 0.3.2 */
-    .networkDestroy = testNetworkDestroy, /* 0.3.2 */
-    .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
-    .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
-    .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
-    .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
-    .networkIsActive = testNetworkIsActive, /* 0.7.3 */
-    .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
-};
-
-static virInterfaceDriver testInterfaceDriver = {
-    .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
-    .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
-    .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
-    .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
-    .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
-    .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
-    .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
-    .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
-    .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
-    .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
-    .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
-    .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
-    .interfaceChangeBegin = testInterfaceChangeBegin,   /* 0.9.2 */
-    .interfaceChangeCommit = testInterfaceChangeCommit,  /* 0.9.2 */
-    .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
-};
-
-
-static virStorageDriver testStorageDriver = {
-    .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
-    .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
-    .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
-    .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
-    .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
-    .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
-    .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
-    .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
-    .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
-    .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
-    .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
-    .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
-    .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
-    .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
-    .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
-    .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
-    .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
-    .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
-    .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
-    .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
-    .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
-    .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
-    .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
-    .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
-    .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
-    .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
-
-    .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
-    .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
-    .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
-    .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
-    .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
-    .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
-    .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
-    .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
-    .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
-    .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
-    .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
-};
-
-static virNodeDeviceDriver testNodeDeviceDriver = {
-    .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
-    .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
-    .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
-    .nodeListDevices = testNodeListDevices, /* 0.7.2 */
-    .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
-    .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
-    .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
-    .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
-    .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
-    .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
-    .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
-};
 
 static virConnectDriver testConnectDriver = {
     .hypervisorDriver = &testHypervisorDriver,
diff --git a/src/test/test_hypervisor_driver.c b/src/test/test_hypervisor_driver.c
new file mode 100644
index 0000000..96e04b6
--- /dev/null
+++ b/src/test/test_hypervisor_driver.c
@@ -0,0 +1,4152 @@
+/*
+ * test_hypervisor_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_hypervisor_driver.h"
+
+#include "test_private_driver.h"
+
+VIR_LOG_INIT("test.test_driver");
+
+static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
+
+static int
+testConnectAuthenticate(virConnectPtr conn,
+                        virConnectAuthPtr auth)
+{
+    testDriverPtr privconn = conn->privateData;
+    int ret = -1;
+    ssize_t i;
+    char *username = NULL, *password = NULL;
+
+    if (privconn->numAuths == 0)
+        return 0;
+
+    /* Authentication is required because the test XML contains a
+     * non-empty <auth/> section.  First we must ask for a username.
+     */
+    username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
+    if (!username) {
+        virReportError(VIR_ERR_AUTH_FAILED, "%s",
+                       _("authentication failed when asking for username"));
+        goto cleanup;
+    }
+
+    /* Does the username exist? */
+    for (i = 0; i < privconn->numAuths; ++i) {
+        if (STREQ(privconn->auths[i].username, username))
+            goto found_user;
+    }
+    i = -1;
+
+ found_user:
+    /* Even if we didn't find the user, we still ask for a password. */
+    if (i == -1 || privconn->auths[i].password != NULL) {
+        password = virAuthGetPassword(conn, auth, "test",
+                                      username, "localhost");
+        if (password == NULL) {
+            virReportError(VIR_ERR_AUTH_FAILED, "%s",
+                           _("authentication failed when asking for password"));
+            goto cleanup;
+        }
+    }
+
+    if (i == -1 ||
+        (password && STRNEQ(privconn->auths[i].password, password))) {
+        virReportError(VIR_ERR_AUTH_FAILED, "%s",
+                       _("authentication failed, see test XML for the correct username/password"));
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(username);
+    VIR_FREE(password);
+    return ret;
+}
+
+static int
+testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
+{
+    char *str;
+    long l;
+    int ret;
+
+    ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->nodes = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu nodes value"));
+        goto error;
+    }
+
+    ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->sockets = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu sockets value"));
+        goto error;
+    }
+
+    ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->cores = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu cores value"));
+        goto error;
+    }
+
+    ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->threads = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu threads value"));
+        goto error;
+    }
+
+    nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
+                      nodeInfo->sockets * nodeInfo->nodes);
+    ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
+    if (ret == 0) {
+        if (l < nodeInfo->cpus)
+            nodeInfo->cpus = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu active value"));
+        goto error;
+    }
+    ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->mhz = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node cpu mhz value"));
+        goto error;
+    }
+
+    str = virXPathString("string(/node/cpu/model[1])", ctxt);
+    if (str != NULL) {
+        if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Model %s too big for destination"), str);
+            VIR_FREE(str);
+            goto error;
+        }
+        VIR_FREE(str);
+    }
+
+    ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
+    if (ret == 0) {
+        nodeInfo->memory = l;
+    } else if (ret == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid node memory value"));
+        goto error;
+    }
+
+    return 0;
+ error:
+    return -1;
+}
+
+static char *testBuildFilename(const char *relativeTo,
+                               const char *filename)
+{
+    char *offset;
+    int baseLen;
+    char *ret;
+
+    if (!filename || filename[0] == '\0')
+        return NULL;
+    if (filename[0] == '/') {
+        ignore_value(VIR_STRDUP(ret, filename));
+        return ret;
+    }
+
+    offset = strrchr(relativeTo, '/');
+    if ((baseLen = (offset-relativeTo+1))) {
+        char *absFile;
+        int totalLen = baseLen + strlen(filename) + 1;
+        if (VIR_ALLOC_N(absFile, totalLen) < 0)
+            return NULL;
+        if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
+            VIR_FREE(absFile);
+            return NULL;
+        }
+        strcat(absFile, filename);
+        return absFile;
+    } else {
+        ignore_value(VIR_STRDUP(ret, filename));
+        return ret;
+    }
+}
+
+static xmlNodePtr
+testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
+{
+    xmlNodePtr ret = NULL;
+    xmlDocPtr doc = NULL;
+    char *absFile = NULL;
+    char *relFile = virXMLPropString(node, "file");
+
+    if (relFile != NULL) {
+        absFile = testBuildFilename(file, relFile);
+        VIR_FREE(relFile);
+        if (!absFile) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("resolving %s filename"), type);
+            return NULL;
+        }
+
+        if (!(doc = virXMLParse(absFile, NULL, type)))
+            goto error;
+
+        ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
+        if (!ret) {
+            virReportOOMError();
+            goto error;
+        }
+        xmlReplaceNode(node, ret);
+        xmlFreeNode(node);
+    } else {
+        ret = node;
+    }
+
+ error:
+    xmlFreeDoc(doc);
+    VIR_FREE(absFile);
+    return ret;
+}
+
+#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0";
+
+typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
+typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
+struct _testDomainNamespaceDef {
+    int runstate;
+    bool transient;
+    bool hasManagedSave;
+
+    unsigned int num_snap_nodes;
+    xmlNodePtr *snap_nodes;
+};
+
+static void
+testDomainDefNamespaceFree(void *data)
+{
+    testDomainNamespaceDefPtr nsdata = data;
+    size_t i;
+
+    if (!nsdata)
+        return;
+
+    for (i = 0; i < nsdata->num_snap_nodes; i++)
+        xmlFreeNode(nsdata->snap_nodes[i]);
+
+    VIR_FREE(nsdata->snap_nodes);
+    VIR_FREE(nsdata);
+}
+
+static int
+testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
+                            xmlNodePtr root ATTRIBUTE_UNUSED,
+                            xmlXPathContextPtr ctxt,
+                            void **data)
+{
+    testDomainNamespaceDefPtr nsdata = NULL;
+    xmlNodePtr *nodes = NULL;
+    int tmp, n;
+    size_t i;
+    unsigned int tmpuint;
+
+    if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
+                           BAD_CAST TEST_NAMESPACE_HREF) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to register xml namespace '%s'"),
+                       TEST_NAMESPACE_HREF);
+        return -1;
+    }
+
+    if (VIR_ALLOC(nsdata) < 0)
+        return -1;
+
+    n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
+    if (n < 0)
+        goto error;
+
+    if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
+        goto error;
+
+    for (i = 0; i < n; i++) {
+        xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
+        if (!newnode) {
+            virReportOOMError();
+            goto error;
+        }
+
+        nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
+        nsdata->num_snap_nodes++;
+    }
+    VIR_FREE(nodes);
+
+    tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
+    if (tmp == -1) {
+        virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
+        goto error;
+    }
+    nsdata->transient = tmp;
+
+    tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
+    if (tmp == -1) {
+        virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
+        goto error;
+    }
+    nsdata->hasManagedSave = tmp;
+
+    tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
+    if (tmp == 0) {
+        if (tmpuint >= VIR_DOMAIN_LAST) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("runstate '%d' out of range'"), tmpuint);
+            goto error;
+        }
+        nsdata->runstate = tmpuint;
+    } else if (tmp == -1) {
+        nsdata->runstate = VIR_DOMAIN_RUNNING;
+    } else if (tmp == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("invalid runstate"));
+        goto error;
+    }
+
+    if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+            _("transient domain cannot have runstate 'shutoff'"));
+        goto error;
+    }
+    if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+            _("domain with managedsave data can only have runstate 'shutoff'"));
+        goto error;
+    }
+
+    *data = nsdata;
+    return 0;
+
+ error:
+    VIR_FREE(nodes);
+    testDomainDefNamespaceFree(nsdata);
+    return -1;
+}
+
+static int
+testParseDomainSnapshots(testDriverPtr privconn,
+                         virDomainObjPtr domobj,
+                         const char *file,
+                         xmlXPathContextPtr ctxt)
+{
+    size_t i;
+    int ret = -1;
+    testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
+    xmlNodePtr *nodes = nsdata->snap_nodes;
+
+    for (i = 0; i < nsdata->num_snap_nodes; i++) {
+        virDomainSnapshotObjPtr snap;
+        virDomainSnapshotDefPtr def;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+                                                  "domainsnapshot");
+        if (!node)
+            goto error;
+
+        def = virDomainSnapshotDefParseNode(ctxt->doc, node,
+                                            privconn->caps,
+                                            privconn->xmlopt,
+                                            VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
+                                            VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
+                                            VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
+        if (!def)
+            goto error;
+
+        if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
+            virDomainSnapshotDefFree(def);
+            goto error;
+        }
+
+        if (def->current) {
+            if (domobj->current_snapshot) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("more than one snapshot claims to be active"));
+                goto error;
+            }
+
+            domobj->current_snapshot = snap;
+        }
+    }
+
+    if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Snapshots have inconsistent relations for "
+                         "domain %s"), domobj->def->name);
+        goto error;
+    }
+
+    ret = 0;
+ error:
+    return ret;
+}
+
+static void
+testDomainShutdownState(virDomainPtr domain,
+                        virDomainObjPtr privdom,
+                        virDomainShutoffReason reason)
+{
+    virDomainObjRemoveTransientDef(privdom);
+    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
+
+    if (domain)
+        domain->id = -1;
+}
+
+/* Set up domain runtime state */
+static int
+testDomainStartState(testDriverPtr privconn,
+                     virDomainObjPtr dom,
+                     virDomainRunningReason reason)
+{
+    int ret = -1;
+
+    virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
+    dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
+
+    if (virDomainObjSetDefTransient(privconn->caps,
+                                    privconn->xmlopt,
+                                    dom) < 0) {
+        goto cleanup;
+    }
+
+    dom->hasManagedSave = false;
+    ret = 0;
+ cleanup:
+    if (ret < 0)
+        testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
+    return ret;
+}
+
+static char *
+testDomainGenerateIfname(virDomainDefPtr domdef)
+{
+    int maxif = 1024;
+    int ifctr;
+    size_t i;
+
+    for (ifctr = 0; ifctr < maxif; ++ifctr) {
+        char *ifname;
+        int found = 0;
+
+        if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
+            return NULL;
+
+        /* Generate network interface names */
+        for (i = 0; i < domdef->nnets; i++) {
+            if (domdef->nets[i]->ifname &&
+                STREQ(domdef->nets[i]->ifname, ifname)) {
+                found = 1;
+                break;
+            }
+        }
+
+        if (!found)
+            return ifname;
+        VIR_FREE(ifname);
+    }
+
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("Exceeded max iface limit %d"), maxif);
+    return NULL;
+}
+
+static int
+testDomainGenerateIfnames(virDomainDefPtr domdef)
+{
+    size_t i = 0;
+
+    for (i = 0; i < domdef->nnets; i++) {
+        char *ifname;
+        if (domdef->nets[i]->ifname)
+            continue;
+
+        ifname = testDomainGenerateIfname(domdef);
+        if (!ifname)
+            return -1;
+
+        domdef->nets[i]->ifname = ifname;
+    }
+
+    return 0;
+}
+
+static int
+testParseDomains(testDriverPtr privconn,
+                 const char *file,
+                 xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+    virDomainObjPtr obj;
+
+    num = virXPathNodeSet("/node/domain", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        virDomainDefPtr def;
+        testDomainNamespaceDefPtr nsdata;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
+        if (!node)
+            goto error;
+
+        def = virDomainDefParseNode(ctxt->doc, node,
+                                    privconn->caps, privconn->xmlopt,
+                                    VIR_DOMAIN_DEF_PARSE_INACTIVE);
+        if (!def)
+            goto error;
+
+        if (testDomainGenerateIfnames(def) < 0 ||
+            !(obj = virDomainObjListAdd(privconn->domains,
+                                        def,
+                                        privconn->xmlopt,
+                                        0, NULL))) {
+            virDomainDefFree(def);
+            goto error;
+        }
+
+        if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
+            virObjectUnlock(obj);
+            goto error;
+        }
+
+        nsdata = def->namespaceData;
+        obj->persistent = !nsdata->transient;
+        obj->hasManagedSave = nsdata->hasManagedSave;
+
+        if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+            if (testDomainStartState(privconn, obj,
+                                     VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+                virObjectUnlock(obj);
+                goto error;
+            }
+        } else {
+            testDomainShutdownState(NULL, obj, 0);
+        }
+        virDomainObjSetState(obj, nsdata->runstate, 0);
+
+        virObjectUnlock(obj);
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testParseNetworks(testDriverPtr privconn,
+                  const char *file,
+                  xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+    virNetworkObjPtr obj;
+
+    num = virXPathNodeSet("/node/network", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        virNetworkDefPtr def;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
+        if (!node)
+            goto error;
+
+        def = virNetworkDefParseNode(ctxt->doc, node);
+        if (!def)
+            goto error;
+
+        if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
+            virNetworkDefFree(def);
+            goto error;
+        }
+
+        obj->active = 1;
+        virNetworkObjEndAPI(&obj);
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testParseInterfaces(testDriverPtr privconn,
+                    const char *file,
+                    xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+    virInterfaceObjPtr obj;
+
+    num = virXPathNodeSet("/node/interface", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        virInterfaceDefPtr def;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+                                                   "interface");
+        if (!node)
+            goto error;
+
+        def = virInterfaceDefParseNode(ctxt->doc, node);
+        if (!def)
+            goto error;
+
+        if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
+            virInterfaceDefFree(def);
+            goto error;
+        }
+
+        obj->active = 1;
+        virInterfaceObjUnlock(obj);
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testOpenVolumesForPool(const char *file,
+                       xmlXPathContextPtr ctxt,
+                       virStoragePoolObjPtr pool,
+                       int poolidx)
+{
+    char *vol_xpath;
+    size_t i;
+    int num, ret = -1;
+    xmlNodePtr *nodes = NULL;
+    virStorageVolDefPtr def = NULL;
+
+    /* Find storage volumes */
+    if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
+        goto error;
+
+    num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
+    VIR_FREE(vol_xpath);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+                                                   "volume");
+        if (!node)
+            goto error;
+
+        def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
+        if (!def)
+            goto error;
+
+        if (def->target.path == NULL) {
+            if (virAsprintf(&def->target.path, "%s/%s",
+                            pool->def->target.path,
+                            def->name) == -1)
+                goto error;
+        }
+
+        if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
+            goto error;
+        if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
+            goto error;
+
+        pool->def->allocation += def->target.allocation;
+        pool->def->available = (pool->def->capacity -
+                                pool->def->allocation);
+        def = NULL;
+    }
+
+    ret = 0;
+ error:
+    virStorageVolDefFree(def);
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testParseStorage(testDriverPtr privconn,
+                 const char *file,
+                 xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+    virStoragePoolObjPtr obj;
+
+    num = virXPathNodeSet("/node/pool", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        virStoragePoolDefPtr def;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+                                                   "pool");
+        if (!node)
+            goto error;
+
+        def = virStoragePoolDefParseNode(ctxt->doc, node);
+        if (!def)
+            goto error;
+
+        if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
+                                                def))) {
+            virStoragePoolDefFree(def);
+            goto error;
+        }
+
+        if (testStoragePoolObjSetDefaults(obj) == -1) {
+            virStoragePoolObjUnlock(obj);
+            goto error;
+        }
+        obj->active = 1;
+
+        /* Find storage volumes */
+        if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
+            virStoragePoolObjUnlock(obj);
+            goto error;
+        }
+
+        virStoragePoolObjUnlock(obj);
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testParseNodedevs(testDriverPtr privconn,
+                  const char *file,
+                  xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+    virNodeDeviceObjPtr obj;
+
+    num = virXPathNodeSet("/node/device", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        virNodeDeviceDefPtr def;
+        xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+                                                  "nodedev");
+        if (!node)
+            goto error;
+
+        def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
+        if (!def)
+            goto error;
+
+        if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
+            virNodeDeviceDefFree(def);
+            goto error;
+        }
+
+        virNodeDeviceObjUnlock(obj);
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testParseAuthUsers(testDriverPtr privconn,
+                   xmlXPathContextPtr ctxt)
+{
+    int num, ret = -1;
+    size_t i;
+    xmlNodePtr *nodes = NULL;
+
+    num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
+    if (num < 0)
+        goto error;
+
+    privconn->numAuths = num;
+    if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
+        goto error;
+
+    for (i = 0; i < num; i++) {
+        char *username, *password;
+
+        ctxt->node = nodes[i];
+        username = virXPathString("string(.)", ctxt);
+        if (!username || STREQ(username, "")) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("missing username in /node/auth/user field"));
+            VIR_FREE(username);
+            goto error;
+        }
+        /* This field is optional. */
+        password = virXMLPropString(nodes[i], "password");
+
+        privconn->auths[i].username = username;
+        privconn->auths[i].password = password;
+    }
+
+    ret = 0;
+ error:
+    VIR_FREE(nodes);
+    return ret;
+}
+
+static int
+testOpenParse(testDriverPtr privconn,
+              const char *file,
+              xmlXPathContextPtr ctxt)
+{
+    if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("Root element is not 'node'"));
+        goto error;
+    }
+
+    if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
+        goto error;
+    if (testParseDomains(privconn, file, ctxt) < 0)
+        goto error;
+    if (testParseNetworks(privconn, file, ctxt) < 0)
+        goto error;
+    if (testParseInterfaces(privconn, file, ctxt) < 0)
+        goto error;
+    if (testParseStorage(privconn, file, ctxt) < 0)
+        goto error;
+    if (testParseNodedevs(privconn, file, ctxt) < 0)
+        goto error;
+    if (testParseAuthUsers(privconn, ctxt) < 0)
+        goto error;
+
+    return 0;
+ error:
+    return -1;
+}
+
+static const char *defaultConnXML =
+"<node>"
+"<domain type='test'>"
+"  <name>test</name>"
+"  <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
+"  <memory>8388608</memory>"
+"  <currentMemory>2097152</currentMemory>"
+"  <vcpu>2</vcpu>"
+"  <os>"
+"    <type>hvm</type>"
+"  </os>"
+"</domain>"
+""
+"<network>"
+"  <name>default</name>"
+"  <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
+"  <bridge name='virbr0'/>"
+"  <forward/>"
+"  <ip address='192.168.122.1' netmask='255.255.255.0'>"
+"    <dhcp>"
+"      <range start='192.168.122.2' end='192.168.122.254'/>"
+"    </dhcp>"
+"  </ip>"
+"</network>"
+""
+"<interface type=\"ethernet\" name=\"eth1\">"
+"  <start mode=\"onboot\"/>"
+"  <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
+"  <mtu size=\"1492\"/>"
+"  <protocol family=\"ipv4\">"
+"    <ip address=\"192.168.0.5\" prefix=\"24\"/>"
+"    <route gateway=\"192.168.0.1\"/>"
+"  </protocol>"
+"</interface>"
+""
+"<pool type='dir'>"
+"  <name>default-pool</name>"
+"  <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
+"  <target>"
+"    <path>/default-pool</path>"
+"  </target>"
+"</pool>"
+""
+"<device>"
+"  <name>computer</name>"
+"  <capability type='system'>"
+"    <hardware>"
+"      <vendor>Libvirt</vendor>"
+"      <version>Test driver</version>"
+"      <serial>123456</serial>"
+"      <uuid>11111111-2222-3333-4444-555555555555</uuid>"
+"    </hardware>"
+"    <firmware>"
+"      <vendor>Libvirt</vendor>"
+"      <version>Test Driver</version>"
+"      <release_date>01/22/2007</release_date>"
+"    </firmware>"
+"  </capability>"
+"</device>"
+"<device>"
+"  <name>test-scsi-host-vport</name>"
+"  <parent>computer</parent>"
+"  <capability type='scsi_host'>"
+"    <host>1</host>"
+"    <capability type='fc_host'>"
+"      <wwnn>2000000012341234</wwnn>"
+"      <wwpn>1000000012341234</wwpn>"
+"    </capability>"
+"    <capability type='vport_ops'/>"
+"  </capability>"
+"</device>"
+"</node>";
+
+static void
+testDriverFree(testDriverPtr driver)
+{
+    if (!driver)
+        return;
+
+    virObjectUnref(driver->caps);
+    virObjectUnref(driver->xmlopt);
+    virObjectUnref(driver->domains);
+    virNodeDeviceObjListFree(&driver->devs);
+    virObjectUnref(driver->networks);
+    virInterfaceObjListFree(&driver->ifaces);
+    virStoragePoolObjListFree(&driver->pools);
+    virObjectEventStateFree(driver->eventState);
+    virMutexUnlock(&driver->lock);
+    virMutexDestroy(&driver->lock);
+
+    VIR_FREE(driver);
+}
+
+static testDriverPtr
+testDriverNew(void)
+{
+    virDomainXMLNamespace ns = {
+        .parse = testDomainDefNamespaceParse,
+        .free = testDomainDefNamespaceFree,
+    };
+    testDriverPtr ret;
+
+    if (VIR_ALLOC(ret) < 0)
+        return NULL;
+
+    if (virMutexInit(&ret->lock) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("cannot initialize mutex"));
+        goto error;
+    }
+
+    if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
+        !(ret->eventState = virObjectEventStateNew()) ||
+        !(ret->domains = virDomainObjListNew()) ||
+        !(ret->networks = virNetworkObjListNew()))
+        goto error;
+
+    virAtomicIntSet(&ret->nextDomID, 1);
+
+    return ret;
+
+ error:
+    testDriverFree(ret);
+    return NULL;
+}
+
+#define TEST_EMULATOR "/usr/bin/test-hv"
+
+static virCapsPtr
+testBuildCapabilities(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    virCapsPtr caps;
+    virCapsGuestPtr guest;
+    int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
+                          VIR_DOMAIN_OSTYPE_XEN };
+    size_t i, j;
+
+    if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
+        goto error;
+
+    if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
+        goto error;
+    if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
+        goto error;
+
+    if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
+        goto error;
+
+    caps->host.pagesSize[caps->host.nPagesSize++] = 4;
+    caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
+
+    for (i = 0; i < privconn->numCells; i++) {
+        virCapsHostNUMACellCPUPtr cpu_cells;
+        virCapsHostNUMACellPageInfoPtr pages;
+        size_t nPages;
+
+        if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
+            VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
+                VIR_FREE(cpu_cells);
+                goto error;
+            }
+
+        nPages = caps->host.nPagesSize;
+
+        memcpy(cpu_cells, privconn->cells[i].cpus,
+               sizeof(*cpu_cells) * privconn->cells[i].numCpus);
+
+        for (j = 0; j < nPages; j++)
+            pages[j].size = caps->host.pagesSize[j];
+
+        pages[0].avail = privconn->cells[i].mem / pages[0].size;
+
+        if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
+                                           privconn->cells[i].numCpus,
+                                           cpu_cells, 0, NULL, nPages, pages) < 0)
+            goto error;
+    }
+
+    for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
+        if ((guest = virCapabilitiesAddGuest(caps,
+                                             guest_types[i],
+                                             VIR_ARCH_I686,
+                                             TEST_EMULATOR,
+                                             NULL,
+                                             0,
+                                             NULL)) == NULL)
+            goto error;
+
+        if (virCapabilitiesAddGuestDomain(guest,
+                                          VIR_DOMAIN_VIRT_TEST,
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            goto error;
+
+        if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
+            goto error;
+        if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
+            goto error;
+    }
+
+    caps->host.nsecModels = 1;
+    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
+        goto error;
+    if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
+        goto error;
+
+    if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
+        goto error;
+
+    return caps;
+
+ error:
+    virObjectUnref(caps);
+    return NULL;
+}
+
+#define TEST_MODEL "i686"
+
+static const virNodeInfo defaultNodeInfo = {
+    TEST_MODEL,
+    1024*1024*3, /* 3 GB */
+    16,
+    1400,
+    2,
+    2,
+    2,
+    2,
+};
+
+static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+
+static testDriverPtr defaultConn;
+static int defaultConnections;
+
+/* Simultaneous test:///default connections should share the same
+ * common state (among other things, this allows testing event
+ * detection in one connection for an action caused in another).  */
+static int
+testOpenDefault(virConnectPtr conn)
+{
+    int u;
+    testDriverPtr privconn = NULL;
+    xmlDocPtr doc = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+
+    virMutexLock(&defaultLock);
+    if (defaultConnections++) {
+        conn->privateData = defaultConn;
+        virMutexUnlock(&defaultLock);
+        return VIR_DRV_OPEN_SUCCESS;
+    }
+
+    if (!(privconn = testDriverNew()))
+        goto error;
+
+    conn->privateData = privconn;
+
+    memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+    /* Numa setup */
+    privconn->numCells = 2;
+    for (u = 0; u < privconn->numCells; ++u) {
+        privconn->cells[u].numCpus = 8;
+        privconn->cells[u].mem = (u + 1) * 2048 * 1024;
+        privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
+    }
+    for (u = 0; u < 16; u++) {
+        virBitmapPtr siblings = virBitmapNew(16);
+        if (!siblings)
+            goto error;
+        ignore_value(virBitmapSetBit(siblings, u));
+        privconn->cells[u / 8].cpus[(u % 8)].id = u;
+        privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
+        privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
+        privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
+    }
+
+    if (!(privconn->caps = testBuildCapabilities(conn)))
+        goto error;
+
+    if (!(doc = virXMLParseStringCtxt(defaultConnXML,
+                                      _("(test driver)"), &ctxt)))
+        goto error;
+
+    if (testOpenParse(privconn, NULL, ctxt) < 0)
+        goto error;
+
+    defaultConn = privconn;
+
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(doc);
+    virMutexUnlock(&defaultLock);
+
+    return VIR_DRV_OPEN_SUCCESS;
+
+ error:
+    testDriverFree(privconn);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(doc);
+    conn->privateData = NULL;
+    defaultConnections--;
+    virMutexUnlock(&defaultLock);
+    return VIR_DRV_OPEN_ERROR;
+}
+
+static int
+testOpenFromFile(virConnectPtr conn, const char *file)
+{
+    xmlDocPtr doc = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    testDriverPtr privconn;
+
+    if (!(privconn = testDriverNew()))
+        return VIR_DRV_OPEN_ERROR;
+
+    testDriverLock(privconn);
+    conn->privateData = privconn;
+
+    if (!(privconn->caps = testBuildCapabilities(conn)))
+        goto error;
+
+    if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
+        goto error;
+
+    privconn->numCells = 0;
+    memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+    if (testOpenParse(privconn, file, ctxt) < 0)
+        goto error;
+
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(doc);
+    testDriverUnlock(privconn);
+
+    return 0;
+
+ error:
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(doc);
+    testDriverFree(privconn);
+    conn->privateData = NULL;
+    return VIR_DRV_OPEN_ERROR;
+}
+
+static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
+                                        virConnectAuthPtr auth,
+                                        virConfPtr conf ATTRIBUTE_UNUSED,
+                                        unsigned int flags)
+{
+    int ret;
+
+    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+    if (!conn->uri)
+        return VIR_DRV_OPEN_DECLINED;
+
+    if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
+        return VIR_DRV_OPEN_DECLINED;
+
+    /* Remote driver should handle these. */
+    if (conn->uri->server)
+        return VIR_DRV_OPEN_DECLINED;
+
+    /* From this point on, the connection is for us. */
+    if (!conn->uri->path
+        || conn->uri->path[0] == '\0'
+        || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("testOpen: supply a path or use test:///default"));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    if (STREQ(conn->uri->path, "/default"))
+        ret = testOpenDefault(conn);
+    else
+        ret = testOpenFromFile(conn,
+                               conn->uri->path);
+
+    if (ret != VIR_DRV_OPEN_SUCCESS)
+        return ret;
+
+    /* Fake authentication. */
+    if (testConnectAuthenticate(conn, auth) < 0)
+        return VIR_DRV_OPEN_ERROR;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int testConnectClose(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    bool dflt = false;
+
+    if (privconn == defaultConn) {
+        dflt = true;
+        virMutexLock(&defaultLock);
+        if (--defaultConnections) {
+            virMutexUnlock(&defaultLock);
+            return 0;
+        }
+    }
+
+    testDriverLock(privconn);
+    testDriverFree(privconn);
+
+    if (dflt) {
+        defaultConn = NULL;
+        virMutexUnlock(&defaultLock);
+    }
+
+    conn->privateData = NULL;
+    return 0;
+}
+
+static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                 unsigned long *hvVer)
+{
+    *hvVer = 2;
+    return 0;
+}
+
+static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return virGetHostname();
+}
+
+static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                  const char *type ATTRIBUTE_UNUSED)
+{
+    return 32;
+}
+
+int testNodeGetInfo(virConnectPtr conn,
+                           virNodeInfoPtr info)
+{
+    testDriverPtr privconn = conn->privateData;
+    testDriverLock(privconn);
+    memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
+    testDriverUnlock(privconn);
+    return 0;
+}
+
+#define TEST_NB_CPU_STATS 4
+
+static int
+testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
+                    int cpuNum ATTRIBUTE_UNUSED,
+                    virNodeCPUStatsPtr params,
+                    int *nparams,
+                    unsigned int flags)
+{
+    size_t i = 0;
+
+    virCheckFlags(0, -1);
+
+    if (params == NULL) {
+        *nparams = TEST_NB_CPU_STATS;
+        return 0;
+    }
+
+    for (i = 0; i < *nparams && i < 4; i++) {
+        switch (i) {
+        case 0:
+            if (virHostCPUStatsAssign(&params[i],
+                                      VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
+                return -1;
+            break;
+        case 1:
+            if (virHostCPUStatsAssign(&params[i],
+                                      VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
+                return -1;
+            break;
+        case 2:
+            if (virHostCPUStatsAssign(&params[i],
+                                      VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
+                return -1;
+            break;
+        case 3:
+            if (virHostCPUStatsAssign(&params[i],
+                                      VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
+                return -1;
+            break;
+        }
+    }
+
+    *nparams = i;
+    return 0;
+}
+
+static unsigned long long
+testNodeGetFreeMemory(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    unsigned int freeMem = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+
+    for (i = 0; i < privconn->numCells; i++)
+        freeMem += privconn->cells[i].freeMem;
+
+    testDriverUnlock(privconn);
+    return freeMem;
+}
+
+static int
+testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
+                     unsigned int npages,
+                     unsigned int *pages ATTRIBUTE_UNUSED,
+                     int startCell ATTRIBUTE_UNUSED,
+                     unsigned int cellCount,
+                     unsigned long long *counts,
+                     unsigned int flags)
+{
+    size_t i = 0, j = 0;
+    int x = 6;
+
+    virCheckFlags(0, -1);
+
+    for (i = 0; i < cellCount; i++) {
+        for (j = 0; j < npages; j++) {
+            x = x * 2 + 7;
+            counts[(i * npages) +  j] = x;
+        }
+    }
+
+    return 0;
+}
+
+static char *testConnectGetCapabilities(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    char *xml;
+    testDriverLock(privconn);
+    xml = virCapabilitiesFormatXML(privconn->caps);
+    testDriverUnlock(privconn);
+    return xml;
+}
+
+static char *
+testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      unsigned int flags)
+{
+    char *ret;
+    const char *sysinfo = "<sysinfo type='smbios'>\n"
+           "  <bios>\n"
+           "    <entry name='vendor'>LENOVO</entry>\n"
+           "    <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
+           "    <entry name='date'>05/07/2014</entry>\n"
+           "    <entry name='release'>2.61</entry>\n"
+           "  </bios>\n"
+           "</sysinfo>\n";
+
+    virCheckFlags(0, NULL);
+
+    ignore_value(VIR_STRDUP(ret, sysinfo));
+    return ret;
+}
+
+static const char *
+testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return "TEST";
+}
+
+static int testConnectListDomains(virConnectPtr conn,
+                                  int *ids,
+                                  int maxids)
+{
+    testDriverPtr privconn = conn->privateData;
+
+    return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
+                                        NULL, NULL);
+}
+
+static int testConnectNumOfDomains(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    int count;
+
+    testDriverLock(privconn);
+    count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
+    testDriverUnlock(privconn);
+
+    return count;
+}
+
+static int testConnectListAllDomains(virConnectPtr conn,
+                                     virDomainPtr **domains,
+                                     unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+
+    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
+
+    return virDomainObjListExport(privconn->domains, conn, domains,
+                                  NULL, flags);
+}
+
+static virDomainPtr
+testDomainCreateXML(virConnectPtr conn, const char *xml,
+                      unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    virDomainPtr ret = NULL;
+    virDomainDefPtr def;
+    virDomainObjPtr dom = NULL;
+    virObjectEventPtr event = NULL;
+    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
+
+    if (flags & VIR_DOMAIN_START_VALIDATE)
+        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+    testDriverLock(privconn);
+    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+                                       parse_flags)) == NULL)
+        goto cleanup;
+
+    if (testDomainGenerateIfnames(def) < 0)
+        goto cleanup;
+    if (!(dom = virDomainObjListAdd(privconn->domains,
+                                    def,
+                                    privconn->xmlopt,
+                                    VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+                                    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+                                    NULL)))
+        goto cleanup;
+    def = NULL;
+
+    if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+        if (!dom->persistent) {
+            virDomainObjListRemove(privconn->domains, dom);
+            dom = NULL;
+        }
+        goto cleanup;
+    }
+
+    event = virDomainEventLifecycleNewFromObj(dom,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+    if (ret)
+        ret->id = dom->def->id;
+
+ cleanup:
+    if (dom)
+        virObjectUnlock(dom);
+    testObjectEventQueue(privconn, event);
+    virDomainDefFree(def);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+
+static virDomainPtr testDomainLookupByID(virConnectPtr conn,
+                                         int id)
+{
+    testDriverPtr privconn = conn->privateData;
+    virDomainPtr ret = NULL;
+    virDomainObjPtr dom;
+
+    if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
+        virReportError(VIR_ERR_NO_DOMAIN, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+    if (ret)
+        ret->id = dom->def->id;
+
+ cleanup:
+    if (dom)
+        virObjectUnlock(dom);
+    return ret;
+}
+
+static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
+                                           const unsigned char *uuid)
+{
+    testDriverPtr privconn = conn->privateData;
+    virDomainPtr ret = NULL;
+    virDomainObjPtr dom;
+
+    if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
+        virReportError(VIR_ERR_NO_DOMAIN, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+    if (ret)
+        ret->id = dom->def->id;
+
+ cleanup:
+    if (dom)
+        virObjectUnlock(dom);
+    return ret;
+}
+
+static virDomainPtr testDomainLookupByName(virConnectPtr conn,
+                                           const char *name)
+{
+    testDriverPtr privconn = conn->privateData;
+    virDomainPtr ret = NULL;
+    virDomainObjPtr dom;
+
+    if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
+        virReportError(VIR_ERR_NO_DOMAIN, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+    if (ret)
+        ret->id = dom->def->id;
+
+ cleanup:
+    virDomainObjEndAPI(&dom);
+    return ret;
+}
+
+static virDomainObjPtr
+testDomObjFromDomain(virDomainPtr domain)
+{
+    virDomainObjPtr vm;
+    testDriverPtr driver = domain->conn->privateData;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+    vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
+    if (!vm) {
+        virUUIDFormat(domain->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_DOMAIN,
+                       _("no domain with matching uuid '%s' (%s)"),
+                       uuidstr, domain->name);
+    }
+
+    return vm;
+}
+
+static int testDomainSuspend(virDomainPtr domain)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+    int state;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    state = virDomainObjGetState(privdom, NULL);
+    if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
+                       domain->name);
+        goto cleanup;
+    }
+
+    virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_SUSPENDED,
+                                     VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int testDomainResume(virDomainPtr domain)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
+                       domain->name);
+        goto cleanup;
+    }
+
+    virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                         VIR_DOMAIN_RUNNING_UNPAUSED);
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_RESUMED,
+                                     VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int testDomainShutdownFlags(virDomainPtr domain,
+                                   unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("domain '%s' not running"), domain->name);
+        goto cleanup;
+    }
+
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+    if (!privdom->persistent)
+        virDomainObjListRemove(privconn->domains, privdom);
+
+    ret = 0;
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int testDomainShutdown(virDomainPtr domain)
+{
+    return testDomainShutdownFlags(domain, 0);
+}
+
+/* Similar behaviour as shutdown */
+static int testDomainReboot(virDomainPtr domain,
+                            unsigned int action ATTRIBUTE_UNUSED)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
+                         VIR_DOMAIN_SHUTDOWN_USER);
+
+    switch (privdom->def->onReboot) {
+    case VIR_DOMAIN_LIFECYCLE_DESTROY:
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_RESTART:
+        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_BOOTED);
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_PRESERVE:
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
+        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_BOOTED);
+        break;
+
+    default:
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+        break;
+    }
+
+    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+        event = virDomainEventLifecycleNewFromObj(privdom,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+        if (!privdom->persistent)
+            virDomainObjListRemove(privconn->domains, privdom);
+    }
+
+    ret = 0;
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int testDomainDestroy(virDomainPtr domain)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+
+    if (!privdom->persistent)
+        virDomainObjListRemove(privconn->domains, privdom);
+
+    ret = 0;
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static char *
+testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+    char *ret;
+
+    ignore_value(VIR_STRDUP(ret, "linux"));
+    return ret;
+}
+
+static unsigned long long
+testDomainGetMaxMemory(virDomainPtr domain)
+{
+    virDomainObjPtr privdom;
+    unsigned long long ret = 0;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return 0;
+
+    ret = virDomainDefGetMemoryTotal(privdom->def);
+
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testDomainSetMaxMemory(virDomainPtr domain,
+                                  unsigned long memory)
+{
+    virDomainObjPtr privdom;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    /* XXX validate not over host memory wrt to other domains */
+    virDomainDefSetMemoryTotal(privdom->def, memory);
+
+    virDomainObjEndAPI(&privdom);
+    return 0;
+}
+
+static int testDomainSetMemory(virDomainPtr domain,
+                               unsigned long memory)
+{
+    virDomainObjPtr privdom;
+    int ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privdom->def->mem.cur_balloon = memory;
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testDomainGetInfo(virDomainPtr domain,
+                             virDomainInfoPtr info)
+{
+    struct timeval tv;
+    virDomainObjPtr privdom;
+    int ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("getting time of day"));
+        goto cleanup;
+    }
+
+    info->state = virDomainObjGetState(privdom, NULL);
+    info->memory = privdom->def->mem.cur_balloon;
+    info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
+    info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
+    info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainGetState(virDomainPtr domain,
+                   int *state,
+                   int *reason,
+                   unsigned int flags)
+{
+    virDomainObjPtr privdom;
+
+    virCheckFlags(0, -1);
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    *state = virDomainObjGetState(privdom, reason);
+
+    virDomainObjEndAPI(&privdom);
+
+    return 0;
+}
+
+#define TEST_SAVE_MAGIC "TestGuestMagic"
+
+static int
+testDomainSaveFlags(virDomainPtr domain, const char *path,
+                    const char *dxml, unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    char *xml = NULL;
+    int fd = -1;
+    int len;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+    if (dxml) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("xml modification unsupported"));
+        return -1;
+    }
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    xml = virDomainDefFormat(privdom->def, privconn->caps,
+                             VIR_DOMAIN_DEF_FORMAT_SECURE);
+
+    if (xml == NULL) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' failed to allocate space for metadata"),
+                             domain->name);
+        goto cleanup;
+    }
+
+    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' to '%s': open failed"),
+                             domain->name, path);
+        goto cleanup;
+    }
+    len = strlen(xml);
+    if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' to '%s': write failed"),
+                             domain->name, path);
+        goto cleanup;
+    }
+    if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' to '%s': write failed"),
+                             domain->name, path);
+        goto cleanup;
+    }
+    if (safewrite(fd, xml, len) < 0) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' to '%s': write failed"),
+                             domain->name, path);
+        goto cleanup;
+    }
+
+    if (VIR_CLOSE(fd) < 0) {
+        virReportSystemError(errno,
+                             _("saving domain '%s' to '%s': write failed"),
+                             domain->name, path);
+        goto cleanup;
+    }
+    fd = -1;
+
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
+
+    if (!privdom->persistent)
+        virDomainObjListRemove(privconn->domains, privdom);
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(xml);
+
+    /* Don't report failure in close or unlink, because
+     * in either case we're already in a failure scenario
+     * and have reported a earlier error */
+    if (ret != 0) {
+        VIR_FORCE_CLOSE(fd);
+        unlink(path);
+    }
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int
+testDomainSave(virDomainPtr domain,
+               const char *path)
+{
+    return testDomainSaveFlags(domain, path, NULL, 0);
+}
+
+static int
+testDomainRestoreFlags(virConnectPtr conn,
+                       const char *path,
+                       const char *dxml,
+                       unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    char *xml = NULL;
+    char magic[15];
+    int fd = -1;
+    int len;
+    virDomainDefPtr def = NULL;
+    virDomainObjPtr dom = NULL;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+    if (dxml) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("xml modification unsupported"));
+        return -1;
+    }
+
+    if ((fd = open(path, O_RDONLY)) < 0) {
+        virReportSystemError(errno,
+                             _("cannot read domain image '%s'"),
+                             path);
+        goto cleanup;
+    }
+    if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
+        virReportSystemError(errno,
+                             _("incomplete save header in '%s'"),
+                             path);
+        goto cleanup;
+    }
+    if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("mismatched header magic"));
+        goto cleanup;
+    }
+    if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
+        virReportSystemError(errno,
+                             _("failed to read metadata length in '%s'"),
+                             path);
+        goto cleanup;
+    }
+    if (len < 1 || len > 8192) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("length of metadata out of range"));
+        goto cleanup;
+    }
+    if (VIR_ALLOC_N(xml, len+1) < 0)
+        goto cleanup;
+    if (saferead(fd, xml, len) != len) {
+        virReportSystemError(errno,
+                             _("incomplete metadata in '%s'"), path);
+        goto cleanup;
+    }
+    xml[len] = '\0';
+
+    def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
+    if (!def)
+        goto cleanup;
+
+    if (testDomainGenerateIfnames(def) < 0)
+        goto cleanup;
+    if (!(dom = virDomainObjListAdd(privconn->domains,
+                                    def,
+                                    privconn->xmlopt,
+                                    VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+                                    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+                                    NULL)))
+        goto cleanup;
+    def = NULL;
+
+    if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
+        if (!dom->persistent) {
+            virDomainObjListRemove(privconn->domains, dom);
+            dom = NULL;
+        }
+        goto cleanup;
+    }
+
+    event = virDomainEventLifecycleNewFromObj(dom,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
+    ret = 0;
+
+ cleanup:
+    virDomainDefFree(def);
+    VIR_FREE(xml);
+    VIR_FORCE_CLOSE(fd);
+    if (dom)
+        virObjectUnlock(dom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int
+testDomainRestore(virConnectPtr conn,
+                  const char *path)
+{
+    return testDomainRestoreFlags(conn, path, NULL, 0);
+}
+
+static int testDomainCoreDumpWithFormat(virDomainPtr domain,
+                                        const char *to,
+                                        unsigned int dumpformat,
+                                        unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    int fd = -1;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(VIR_DUMP_CRASH, -1);
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+        virReportSystemError(errno,
+                             _("domain '%s' coredump: failed to open %s"),
+                             domain->name, to);
+        goto cleanup;
+    }
+    if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+        virReportSystemError(errno,
+                             _("domain '%s' coredump: failed to write header to %s"),
+                             domain->name, to);
+        goto cleanup;
+    }
+    if (VIR_CLOSE(fd) < 0) {
+        virReportSystemError(errno,
+                             _("domain '%s' coredump: write failed: %s"),
+                             domain->name, to);
+        goto cleanup;
+    }
+
+    /* we don't support non-raw formats in test driver */
+    if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("kdump-compressed format is not supported here"));
+        goto cleanup;
+    }
+
+    if (flags & VIR_DUMP_CRASH) {
+        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
+        event = virDomainEventLifecycleNewFromObj(privdom,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
+        if (!privdom->persistent)
+            virDomainObjListRemove(privconn->domains, privdom);
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+
+static int
+testDomainCoreDump(virDomainPtr domain,
+                   const char *to,
+                   unsigned int flags)
+{
+    return testDomainCoreDumpWithFormat(domain, to,
+                                        VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
+}
+
+static int
+testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
+                        unsigned int flags)
+{
+    testDriverPtr driver = domain->conn->privateData;
+    virDomainObjPtr privdom = NULL;
+    virDomainDefPtr def;
+    virDomainDefPtr persistentDef;
+    int ret = -1, maxvcpus;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+    if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
+        return -1;
+
+    if (nrCpus > maxvcpus) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("requested cpu amount exceeds maximum supported amount "
+                         "(%d > %d)"), nrCpus, maxvcpus);
+        return -1;
+    }
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
+        goto cleanup;
+
+    if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("requested cpu amount exceeds maximum (%d > %d)"),
+                       nrCpus, virDomainDefGetVcpusMax(def));
+        goto cleanup;
+    }
+
+    if (persistentDef &&
+        !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
+        virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("requested cpu amount exceeds maximum (%d > %d)"),
+                       nrCpus, virDomainDefGetVcpusMax(persistentDef));
+        goto cleanup;
+    }
+
+    if (def &&
+        virDomainDefSetVcpus(def, nrCpus) < 0)
+        goto cleanup;
+
+    if (persistentDef) {
+        if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
+            if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
+                                        driver->xmlopt) < 0)
+                goto cleanup;
+        } else {
+            if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
+                goto cleanup;
+        }
+    }
+
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
+{
+    return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
+}
+
+static int testDomainGetVcpus(virDomainPtr domain,
+                              virVcpuInfoPtr info,
+                              int maxinfo,
+                              unsigned char *cpumaps,
+                              int maplen)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virDomainDefPtr def;
+    size_t i;
+    int maxcpu, hostcpus;
+    int ret = -1;
+    struct timeval tv;
+    unsigned long long statbase;
+    virBitmapPtr allcpumap = NULL;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (!virDomainObjIsActive(privdom)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("cannot list vcpus for an inactive domain"));
+        goto cleanup;
+    }
+
+    def = privdom->def;
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("getting time of day"));
+        goto cleanup;
+    }
+
+    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+
+    hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
+    maxcpu = maplen * 8;
+    if (maxcpu > hostcpus)
+        maxcpu = hostcpus;
+
+    if (!(allcpumap = virBitmapNew(hostcpus)))
+        goto cleanup;
+
+    virBitmapSetAll(allcpumap);
+
+    /* Clamp to actual number of vcpus */
+    if (maxinfo > virDomainDefGetVcpus(privdom->def))
+        maxinfo = virDomainDefGetVcpus(privdom->def);
+
+    memset(info, 0, sizeof(*info) * maxinfo);
+    memset(cpumaps, 0, maxinfo * maplen);
+
+    for (i = 0; i < maxinfo; i++) {
+        virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
+        virBitmapPtr bitmap = NULL;
+
+        if (!vcpu->online)
+            continue;
+
+        if (vcpu->cpumask)
+            bitmap = vcpu->cpumask;
+        else if (def->cpumask)
+            bitmap = def->cpumask;
+        else
+            bitmap = allcpumap;
+
+        if (cpumaps)
+            virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
+
+        info[i].number = i;
+        info[i].state = VIR_VCPU_RUNNING;
+        info[i].cpu = virBitmapLastSetBit(bitmap);
+
+        /* Fake an increasing cpu time value */
+        info[i].cpuTime = statbase / 10;
+    }
+
+    ret = maxinfo;
+ cleanup:
+    virBitmapFree(allcpumap);
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testDomainPinVcpu(virDomainPtr domain,
+                             unsigned int vcpu,
+                             unsigned char *cpumap,
+                             int maplen)
+{
+    virDomainVcpuDefPtr vcpuinfo;
+    virDomainObjPtr privdom;
+    virDomainDefPtr def;
+    int ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    def = privdom->def;
+
+    if (!virDomainObjIsActive(privdom)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("cannot pin vcpus on an inactive domain"));
+        goto cleanup;
+    }
+
+    if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
+        !vcpuinfo->online) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("requested vcpu '%d' is not present in the domain"),
+                       vcpu);
+        goto cleanup;
+    }
+
+    virBitmapFree(vcpuinfo->cpumask);
+
+    if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainGetVcpuPinInfo(virDomainPtr dom,
+                        int ncpumaps,
+                        unsigned char *cpumaps,
+                        int maplen,
+                        unsigned int flags)
+{
+    testDriverPtr driver = dom->conn->privateData;
+    virDomainObjPtr privdom;
+    virDomainDefPtr def;
+    int ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(dom)))
+        return -1;
+
+    if (!(def = virDomainObjGetOneDef(privdom, flags)))
+        goto cleanup;
+
+    ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
+                                           VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
+                                           NULL);
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+    virDomainObjPtr vm;
+    virDomainDefPtr def;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (!(def = virDomainObjGetOneDef(vm, flags)))
+        goto cleanup;
+
+    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
+        ret = virDomainDefGetVcpusMax(def);
+    else
+        ret = virDomainDefGetVcpus(def);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+static int
+testDomainGetMaxVcpus(virDomainPtr domain)
+{
+    return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
+                                            VIR_DOMAIN_VCPU_MAXIMUM));
+}
+
+static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainDefPtr def;
+    virDomainObjPtr privdom;
+    char *ret = NULL;
+
+    /* Flags checked by virDomainDefFormat */
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return NULL;
+
+    def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
+        privdom->newDef ? privdom->newDef : privdom->def;
+
+    ret = virDomainDefFormat(def, privconn->caps,
+                             virDomainDefFormatConvertXMLFlags(flags));
+
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testConnectNumOfDefinedDomains(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+
+    return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
+}
+
+static int testConnectListDefinedDomains(virConnectPtr conn,
+                                         char **const names,
+                                         int maxnames)
+{
+
+    testDriverPtr privconn = conn->privateData;
+
+    memset(names, 0, sizeof(*names)*maxnames);
+    return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
+                                            NULL, NULL);
+}
+
+static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Domain '%s' is already running"), domain->name);
+        goto cleanup;
+    }
+
+    if (testDomainStartState(privconn, privdom,
+                             VIR_DOMAIN_RUNNING_BOOTED) < 0)
+        goto cleanup;
+    domain->id = privdom->def->id;
+
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testDomainCreate(virDomainPtr domain)
+{
+    return testDomainCreateWithFlags(domain, 0);
+}
+
+static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
+                                             const char *xml,
+                                             unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    virDomainPtr ret = NULL;
+    virDomainDefPtr def;
+    virDomainObjPtr dom = NULL;
+    virObjectEventPtr event = NULL;
+    virDomainDefPtr oldDef = NULL;
+    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
+
+    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
+        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+                                       parse_flags)) == NULL)
+        goto cleanup;
+
+    if (testDomainGenerateIfnames(def) < 0)
+        goto cleanup;
+    if (!(dom = virDomainObjListAdd(privconn->domains,
+                                    def,
+                                    privconn->xmlopt,
+                                    0,
+                                    &oldDef)))
+        goto cleanup;
+    def = NULL;
+    dom->persistent = 1;
+
+    event = virDomainEventLifecycleNewFromObj(dom,
+                                     VIR_DOMAIN_EVENT_DEFINED,
+                                     !oldDef ?
+                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
+                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+
+    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+    if (ret)
+        ret->id = dom->def->id;
+
+ cleanup:
+    virDomainDefFree(def);
+    virDomainDefFree(oldDef);
+    if (dom)
+        virObjectUnlock(dom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static virDomainPtr
+testDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+    return testDomainDefineXMLFlags(conn, xml, 0);
+}
+
+static int testDomainUndefineFlags(virDomainPtr domain,
+                                   unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr privdom;
+    virObjectEventPtr event = NULL;
+    int nsnapshots;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
+                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
+
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    if (privdom->hasManagedSave &&
+        !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("Refusing to undefine while domain managed "
+                         "save image exists"));
+        goto cleanup;
+    }
+
+    /* Requiring an inactive VM is part of the documented API for
+     * UNDEFINE_SNAPSHOTS_METADATA
+     */
+    if (!virDomainObjIsActive(privdom) &&
+        (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
+                                                  NULL, 0))) {
+        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("cannot delete inactive domain with %d "
+                             "snapshots"),
+                           nsnapshots);
+            goto cleanup;
+        }
+
+        /* There isn't actually anything to do, we are just emulating qemu
+         * behavior here. */
+    }
+
+    event = virDomainEventLifecycleNewFromObj(privdom,
+                                     VIR_DOMAIN_EVENT_UNDEFINED,
+                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+    privdom->hasManagedSave = false;
+
+    if (virDomainObjIsActive(privdom))
+        privdom->persistent = 0;
+    else
+        virDomainObjListRemove(privconn->domains, privdom);
+
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    testObjectEventQueue(privconn, event);
+    return ret;
+}
+
+static int testDomainUndefine(virDomainPtr domain)
+{
+    return testDomainUndefineFlags(domain, 0);
+}
+
+static int testDomainGetAutostart(virDomainPtr domain,
+                                  int *autostart)
+{
+    virDomainObjPtr privdom;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    *autostart = privdom->autostart;
+
+    virDomainObjEndAPI(&privdom);
+    return 0;
+}
+
+
+static int testDomainSetAutostart(virDomainPtr domain,
+                                  int autostart)
+{
+    virDomainObjPtr privdom;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    privdom->autostart = autostart ? 1 : 0;
+
+    virDomainObjEndAPI(&privdom);
+    return 0;
+}
+
+static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
+                                        int *nparams)
+{
+    char *type = NULL;
+
+    if (nparams)
+        *nparams = 1;
+
+    ignore_value(VIR_STRDUP(type, "fair"));
+
+    return type;
+}
+
+static int
+testDomainGetSchedulerParametersFlags(virDomainPtr domain,
+                                      virTypedParameterPtr params,
+                                      int *nparams,
+                                      unsigned int flags)
+{
+    virDomainObjPtr privdom;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
+                                VIR_TYPED_PARAM_UINT, 50) < 0)
+        goto cleanup;
+    /* XXX */
+    /*params[0].value.ui = privdom->weight;*/
+
+    *nparams = 1;
+    ret = 0;
+
+ cleanup:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainGetSchedulerParameters(virDomainPtr domain,
+                                 virTypedParameterPtr params,
+                                 int *nparams)
+{
+    return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int
+testDomainSetSchedulerParametersFlags(virDomainPtr domain,
+                                      virTypedParameterPtr params,
+                                      int nparams,
+                                      unsigned int flags)
+{
+    virDomainObjPtr privdom;
+    int ret = -1;
+    size_t i;
+
+    virCheckFlags(0, -1);
+    if (virTypedParamsValidate(params, nparams,
+                               VIR_DOMAIN_SCHEDULER_WEIGHT,
+                               VIR_TYPED_PARAM_UINT,
+                               NULL) < 0)
+        return -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    for (i = 0; i < nparams; i++) {
+        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
+            /* XXX */
+            /*privdom->weight = params[i].value.ui;*/
+        }
+    }
+
+    ret = 0;
+
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testDomainSetSchedulerParameters(virDomainPtr domain,
+                                 virTypedParameterPtr params,
+                                 int nparams)
+{
+    return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int testDomainBlockStats(virDomainPtr domain,
+                                const char *path,
+                                virDomainBlockStatsPtr stats)
+{
+    virDomainObjPtr privdom;
+    struct timeval tv;
+    unsigned long long statbase;
+    int ret = -1;
+
+    if (!*path) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("summary statistics are not supported yet"));
+        return ret;
+    }
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return ret;
+
+    if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("invalid path: %s"), path);
+        goto error;
+    }
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("getting time of day"));
+        goto error;
+    }
+
+    /* No significance to these numbers, just enough to mix it up*/
+    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+    stats->rd_req = statbase / 10;
+    stats->rd_bytes = statbase / 20;
+    stats->wr_req = statbase / 30;
+    stats->wr_bytes = statbase / 40;
+    stats->errs = tv.tv_sec / 2;
+
+    ret = 0;
+ error:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testDomainInterfaceStats(virDomainPtr domain,
+                                    const char *path,
+                                    virDomainInterfaceStatsPtr stats)
+{
+    virDomainObjPtr privdom;
+    struct timeval tv;
+    unsigned long long statbase;
+    size_t i;
+    int found = 0, ret = -1;
+
+    if (!(privdom = testDomObjFromDomain(domain)))
+        return -1;
+
+    for (i = 0; i < privdom->def->nnets; i++) {
+        if (privdom->def->nets[i]->ifname &&
+            STREQ(privdom->def->nets[i]->ifname, path)) {
+            found = 1;
+            break;
+        }
+    }
+
+    if (!found) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("invalid path, '%s' is not a known interface"), path);
+        goto error;
+    }
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("getting time of day"));
+        goto error;
+    }
+
+    /* No significance to these numbers, just enough to mix it up*/
+    statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+    stats->rx_bytes = statbase / 10;
+    stats->rx_packets = statbase / 100;
+    stats->rx_errs = tv.tv_sec / 1;
+    stats->rx_drop = tv.tv_sec / 2;
+    stats->tx_bytes = statbase / 20;
+    stats->tx_packets = statbase / 110;
+    stats->tx_errs = tv.tv_sec / 3;
+    stats->tx_drop = tv.tv_sec / 4;
+
+    ret = 0;
+ error:
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testNodeGetCellsFreeMemory(virConnectPtr conn,
+                                      unsigned long long *freemems,
+                                      int startCell, int maxCells)
+{
+    testDriverPtr privconn = conn->privateData;
+    int cell;
+    size_t i;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    if (startCell > privconn->numCells) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("Range exceeds available cells"));
+        goto cleanup;
+    }
+
+    for (cell = startCell, i = 0;
+         (cell < privconn->numCells && i < maxCells);
+         ++cell, ++i) {
+        freemems[i] = privconn->cells[cell].mem;
+    }
+    ret = i;
+
+ cleanup:
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+/* Domain event implementations */
+static int
+testConnectDomainEventRegister(virConnectPtr conn,
+                               virConnectDomainEventCallback callback,
+                               void *opaque,
+                               virFreeCallback freecb)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virDomainEventStateRegister(conn, driver->eventState,
+                                    callback, opaque, freecb) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+
+static int
+testConnectDomainEventDeregister(virConnectPtr conn,
+                                 virConnectDomainEventCallback callback)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virDomainEventStateDeregister(conn, driver->eventState,
+                                      callback) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+
+static int
+testConnectDomainEventRegisterAny(virConnectPtr conn,
+                                  virDomainPtr dom,
+                                  int eventID,
+                                  virConnectDomainEventGenericCallback callback,
+                                  void *opaque,
+                                  virFreeCallback freecb)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret;
+
+    if (virDomainEventStateRegisterID(conn, driver->eventState,
+                                      dom, eventID,
+                                      callback, opaque, freecb, &ret) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int
+testConnectDomainEventDeregisterAny(virConnectPtr conn,
+                                    int callbackID)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virObjectEventStateDeregisterID(conn, driver->eventState,
+                                        callbackID) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return 1;
+}
+
+static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return 1;
+}
+
+static int testDomainIsActive(virDomainPtr dom)
+{
+    virDomainObjPtr obj;
+    int ret;
+
+    if (!(obj = testDomObjFromDomain(dom)))
+        return -1;
+
+    ret = virDomainObjIsActive(obj);
+    virDomainObjEndAPI(&obj);
+    return ret;
+}
+
+static int testDomainIsPersistent(virDomainPtr dom)
+{
+    virDomainObjPtr obj;
+    int ret;
+
+    if (!(obj = testDomObjFromDomain(dom)))
+        return -1;
+
+    ret = obj->persistent;
+
+    virDomainObjEndAPI(&obj);
+    return ret;
+}
+
+static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+static int
+testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
+                  unsigned char **cpumap,
+                  unsigned int *online,
+                  unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    if (cpumap) {
+        if (VIR_ALLOC_N(*cpumap, 1) < 0)
+            return -1;
+        *cpumap[0] = 0x15;
+    }
+
+    if (online)
+        *online = 3;
+
+    return  8;
+}
+
+static char *
+testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
+                     virStreamPtr st,
+                     unsigned int screen ATTRIBUTE_UNUSED,
+                     unsigned int flags)
+{
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (VIR_STRDUP(ret, "image/png") < 0)
+        return NULL;
+
+    if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
+        VIR_FREE(ret);
+
+    return ret;
+}
+
+static char *testDomainGetMetadata(virDomainPtr dom,
+                                   int type,
+                                   const char *uri,
+                                   unsigned int flags)
+{
+    virDomainObjPtr privdom;
+    char *ret;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, NULL);
+
+    if (!(privdom = testDomObjFromDomain(dom)))
+        return NULL;
+
+    ret = virDomainObjGetMetadata(privdom, type, uri, flags);
+
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int testDomainSetMetadata(virDomainPtr dom,
+                                 int type,
+                                 const char *metadata,
+                                 const char *key,
+                                 const char *uri,
+                                 unsigned int flags)
+{
+    testDriverPtr privconn = dom->conn->privateData;
+    virDomainObjPtr privdom;
+    int ret;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+    if (!(privdom = testDomObjFromDomain(dom)))
+        return -1;
+
+    ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
+                                  privconn->caps, privconn->xmlopt,
+                                  NULL, NULL, flags);
+
+    virDomainObjEndAPI(&privdom);
+    return ret;
+}
+
+static int
+testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
+                            const char *arch,
+                            char ***models,
+                            unsigned int flags)
+{
+    virCheckFlags(0, -1);
+    return cpuGetModels(arch, models);
+}
+
+static int
+testDomainManagedSave(virDomainPtr dom, unsigned int flags)
+{
+    testDriverPtr privconn = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virObjectEventPtr event = NULL;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
+                  VIR_DOMAIN_SAVE_RUNNING |
+                  VIR_DOMAIN_SAVE_PAUSED, -1);
+
+    if (!(vm = testDomObjFromDomain(dom)))
+        return -1;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    if (!vm->persistent) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("cannot do managed save for transient domain"));
+        goto cleanup;
+    }
+
+    testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
+    event = virDomainEventLifecycleNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
+    vm->hasManagedSave = true;
+
+    ret = 0;
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    testObjectEventQueue(privconn, event);
+
+    return ret;
+}
+
+static int
+testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
+{
+    virDomainObjPtr vm;
+    int ret;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromDomain(dom)))
+        return -1;
+
+    ret = vm->hasManagedSave;
+
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+static int
+testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
+{
+    virDomainObjPtr vm;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromDomain(dom)))
+        return -1;
+
+    vm->hasManagedSave = false;
+
+    virDomainObjEndAPI(&vm);
+    return 0;
+}
+
+/*
+ * Snapshot APIs
+ */
+
+static virDomainSnapshotObjPtr
+testSnapObjFromName(virDomainObjPtr vm,
+                    const char *name)
+{
+    virDomainSnapshotObjPtr snap = NULL;
+    snap = virDomainSnapshotFindByName(vm->snapshots, name);
+    if (!snap)
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+                       _("no domain snapshot with matching name '%s'"),
+                       name);
+    return snap;
+}
+
+static virDomainSnapshotObjPtr
+testSnapObjFromSnapshot(virDomainObjPtr vm,
+                        virDomainSnapshotPtr snapshot)
+{
+    return testSnapObjFromName(vm, snapshot->name);
+}
+
+static virDomainObjPtr
+testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
+{
+    return testDomObjFromDomain(snapshot->domain);
+}
+
+static int
+testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int n;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return -1;
+
+    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
+
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static int
+testDomainSnapshotListNames(virDomainPtr domain,
+                            char **names,
+                            int nameslen,
+                            unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int n;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return -1;
+
+    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
+                                         flags);
+
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static int
+testDomainListAllSnapshots(virDomainPtr domain,
+                           virDomainSnapshotPtr **snaps,
+                           unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int n;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return -1;
+
+    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
+
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static int
+testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+                                    char **names,
+                                    int nameslen,
+                                    unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
+                                         flags);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static int
+testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
+                              unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static int
+testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+                                  virDomainSnapshotPtr **snaps,
+                                  unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    int n = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
+                               flags);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return n;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotLookupByName(virDomainPtr domain,
+                               const char *name,
+                               unsigned int flags)
+{
+    virDomainObjPtr vm;
+    virDomainSnapshotObjPtr snap = NULL;
+    virDomainSnapshotPtr snapshot = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return NULL;
+
+    if (!(snap = testSnapObjFromName(vm, name)))
+        goto cleanup;
+
+    snapshot = virGetDomainSnapshot(domain, snap->def->name);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return snapshot;
+}
+
+static int
+testDomainHasCurrentSnapshot(virDomainPtr domain,
+                             unsigned int flags)
+{
+    virDomainObjPtr vm;
+    int ret;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return -1;
+
+    ret = (vm->current_snapshot != NULL);
+
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
+                            unsigned int flags)
+{
+    virDomainObjPtr vm;
+    virDomainSnapshotObjPtr snap = NULL;
+    virDomainSnapshotPtr parent = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return NULL;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    if (!snap->def->parent) {
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+                       _("snapshot '%s' does not have a parent"),
+                       snap->def->name);
+        goto cleanup;
+    }
+
+    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return parent;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCurrent(virDomainPtr domain,
+                          unsigned int flags)
+{
+    virDomainObjPtr vm;
+    virDomainSnapshotPtr snapshot = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        return NULL;
+
+    if (!vm->current_snapshot) {
+        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
+                       _("the domain does not have a current snapshot"));
+        goto cleanup;
+    }
+
+    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return snapshot;
+}
+
+static char *
+testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+                             unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    char *xml = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    testDriverPtr privconn = snapshot->domain->conn->privateData;
+
+    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return NULL;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
+                                     virDomainDefFormatConvertXMLFlags(flags),
+                                     0);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return xml;
+}
+
+static int
+testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
+                            unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int ret;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    ret = (vm->current_snapshot &&
+           STREQ(snapshot->name, vm->current_snapshot->def->name));
+
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+
+static int
+testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
+                              unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!testSnapObjFromSnapshot(vm, snapshot))
+        goto cleanup;
+
+    ret = 1;
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+static int
+testDomainSnapshotAlignDisks(virDomainObjPtr vm,
+                             virDomainSnapshotDefPtr def,
+                             unsigned int flags)
+{
+    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+    bool align_match = true;
+
+    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
+        align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+        align_match = false;
+        if (virDomainObjIsActive(vm))
+            def->state = VIR_DOMAIN_DISK_SNAPSHOT;
+        else
+            def->state = VIR_DOMAIN_SHUTOFF;
+        def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+    } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+        def->state = virDomainObjGetState(vm, NULL);
+        align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+        align_match = false;
+    } else {
+        def->state = virDomainObjGetState(vm, NULL);
+        def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
+                      VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
+                      VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+    }
+
+    return virDomainSnapshotAlignDisks(def, align_location, align_match);
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCreateXML(virDomainPtr domain,
+                            const char *xmlDesc,
+                            unsigned int flags)
+{
+    testDriverPtr privconn = domain->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotDefPtr def = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    virDomainSnapshotPtr snapshot = NULL;
+    virObjectEventPtr event = NULL;
+    char *xml = NULL;
+    bool update_current = true;
+    bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
+    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
+
+    /*
+     * DISK_ONLY: Not implemented yet
+     * REUSE_EXT: Not implemented yet
+     *
+     * NO_METADATA: Explicitly not implemented
+     *
+     * REDEFINE + CURRENT: Implemented
+     * HALT: Implemented
+     * QUIESCE: Nothing to do
+     * ATOMIC: Nothing to do
+     * LIVE: Nothing to do
+     */
+    virCheckFlags(
+        VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
+        VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
+        VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
+        VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
+        VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
+        VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
+
+    if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
+        update_current = false;
+    if (redefine)
+        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
+
+    if (!(vm = testDomObjFromDomain(domain)))
+        goto cleanup;
+
+    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("cannot halt after transient domain snapshot"));
+        goto cleanup;
+    }
+
+    if (!(def = virDomainSnapshotDefParseString(xmlDesc,
+                                                privconn->caps,
+                                                privconn->xmlopt,
+                                                parse_flags)))
+        goto cleanup;
+
+    if (redefine) {
+        if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
+                                          &update_current, flags) < 0)
+            goto cleanup;
+    } else {
+        if (!(def->dom = virDomainDefCopy(vm->def,
+                                          privconn->caps,
+                                          privconn->xmlopt,
+                                          true)))
+            goto cleanup;
+
+        if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
+            goto cleanup;
+    }
+
+    if (!snap) {
+        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
+            goto cleanup;
+        def = NULL;
+    }
+
+    if (!redefine) {
+        if (vm->current_snapshot &&
+            (VIR_STRDUP(snap->def->parent,
+                        vm->current_snapshot->def->name) < 0))
+            goto cleanup;
+
+        if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
+            virDomainObjIsActive(vm)) {
+            testDomainShutdownState(domain, vm,
+                                    VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+            event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+                                    VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+        }
+    }
+
+    snapshot = virGetDomainSnapshot(domain, snap->def->name);
+ cleanup:
+    VIR_FREE(xml);
+    if (vm) {
+        if (snapshot) {
+            virDomainSnapshotObjPtr other;
+            if (update_current)
+                vm->current_snapshot = snap;
+            other = virDomainSnapshotFindByName(vm->snapshots,
+                                                snap->def->parent);
+            snap->parent = other;
+            other->nchildren++;
+            snap->sibling = other->first_child;
+            other->first_child = snap;
+        }
+        virDomainObjEndAPI(&vm);
+    }
+    testObjectEventQueue(privconn, event);
+    virDomainSnapshotDefFree(def);
+    return snapshot;
+}
+
+
+typedef struct _testSnapRemoveData testSnapRemoveData;
+typedef testSnapRemoveData *testSnapRemoveDataPtr;
+struct _testSnapRemoveData {
+    virDomainObjPtr vm;
+    bool current;
+};
+
+static int
+testDomainSnapshotDiscardAll(void *payload,
+                             const void *name ATTRIBUTE_UNUSED,
+                             void *data)
+{
+    virDomainSnapshotObjPtr snap = payload;
+    testSnapRemoveDataPtr curr = data;
+
+    if (snap->def->current)
+        curr->current = true;
+    virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
+    return 0;
+}
+
+typedef struct _testSnapReparentData testSnapReparentData;
+typedef testSnapReparentData *testSnapReparentDataPtr;
+struct _testSnapReparentData {
+    virDomainSnapshotObjPtr parent;
+    virDomainObjPtr vm;
+    int err;
+    virDomainSnapshotObjPtr last;
+};
+
+static int
+testDomainSnapshotReparentChildren(void *payload,
+                                   const void *name ATTRIBUTE_UNUSED,
+                                   void *data)
+{
+    virDomainSnapshotObjPtr snap = payload;
+    testSnapReparentDataPtr rep = data;
+
+    if (rep->err < 0)
+        return 0;
+
+    VIR_FREE(snap->def->parent);
+    snap->parent = rep->parent;
+
+    if (rep->parent->def &&
+        VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
+        rep->err = -1;
+        return 0;
+    }
+
+    if (!snap->sibling)
+        rep->last = snap;
+    return 0;
+}
+
+static int
+testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+                         unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    virDomainSnapshotObjPtr parentsnap = NULL;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
+        testSnapRemoveData rem;
+        rem.vm = vm;
+        rem.current = false;
+        virDomainSnapshotForEachDescendant(snap,
+                                           testDomainSnapshotDiscardAll,
+                                           &rem);
+        if (rem.current) {
+            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
+                snap->def->current = true;
+            vm->current_snapshot = snap;
+        }
+    } else if (snap->nchildren) {
+        testSnapReparentData rep;
+        rep.parent = snap->parent;
+        rep.vm = vm;
+        rep.err = 0;
+        rep.last = NULL;
+        virDomainSnapshotForEachChild(snap,
+                                      testDomainSnapshotReparentChildren,
+                                      &rep);
+        if (rep.err < 0)
+            goto cleanup;
+
+        /* Can't modify siblings during ForEachChild, so do it now.  */
+        snap->parent->nchildren += snap->nchildren;
+        rep.last->sibling = snap->parent->first_child;
+        snap->parent->first_child = snap->first_child;
+    }
+
+    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
+        snap->nchildren = 0;
+        snap->first_child = NULL;
+    } else {
+        virDomainSnapshotDropParent(snap);
+        if (snap == vm->current_snapshot) {
+            if (snap->def->parent) {
+                parentsnap = virDomainSnapshotFindByName(vm->snapshots,
+                                                         snap->def->parent);
+                if (!parentsnap) {
+                    VIR_WARN("missing parent snapshot matching name '%s'",
+                             snap->def->parent);
+                } else {
+                    parentsnap->def->current = true;
+                }
+            }
+            vm->current_snapshot = parentsnap;
+        }
+        virDomainSnapshotObjListRemove(vm->snapshots, snap);
+    }
+
+    ret = 0;
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+static int
+testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
+                           unsigned int flags)
+{
+    testDriverPtr privconn = snapshot->domain->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainSnapshotObjPtr snap = NULL;
+    virObjectEventPtr event = NULL;
+    virObjectEventPtr event2 = NULL;
+    virDomainDefPtr config = NULL;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
+                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
+
+    /* We have the following transitions, which create the following events:
+     * 1. inactive -> inactive: none
+     * 2. inactive -> running:  EVENT_STARTED
+     * 3. inactive -> paused:   EVENT_STARTED, EVENT_PAUSED
+     * 4. running  -> inactive: EVENT_STOPPED
+     * 5. running  -> running:  none
+     * 6. running  -> paused:   EVENT_PAUSED
+     * 7. paused   -> inactive: EVENT_STOPPED
+     * 8. paused   -> running:  EVENT_RESUMED
+     * 9. paused   -> paused:   none
+     * Also, several transitions occur even if we fail partway through,
+     * and use of FORCE can cause multiple transitions.
+     */
+
+    if (!(vm = testDomObjFromSnapshot(snapshot)))
+        return -1;
+
+    if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+        goto cleanup;
+
+    if (!vm->persistent &&
+        snap->def->state != VIR_DOMAIN_RUNNING &&
+        snap->def->state != VIR_DOMAIN_PAUSED &&
+        (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("transient domain needs to request run or pause "
+                         "to revert to inactive snapshot"));
+        goto cleanup;
+    }
+
+    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+        if (!snap->def->dom) {
+            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
+                           _("snapshot '%s' lacks domain '%s' rollback info"),
+                           snap->def->name, vm->def->name);
+            goto cleanup;
+        }
+        if (virDomainObjIsActive(vm) &&
+            !(snap->def->state == VIR_DOMAIN_RUNNING
+              || snap->def->state == VIR_DOMAIN_PAUSED) &&
+            (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+                      VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+                           _("must respawn guest to start inactive snapshot"));
+            goto cleanup;
+        }
+    }
+
+
+    if (vm->current_snapshot) {
+        vm->current_snapshot->def->current = false;
+        vm->current_snapshot = NULL;
+    }
+
+    snap->def->current = true;
+    config = virDomainDefCopy(snap->def->dom,
+                              privconn->caps, privconn->xmlopt, true);
+    if (!config)
+        goto cleanup;
+
+    if (snap->def->state == VIR_DOMAIN_RUNNING ||
+        snap->def->state == VIR_DOMAIN_PAUSED) {
+        /* Transitions 2, 3, 5, 6, 8, 9 */
+        bool was_running = false;
+        bool was_stopped = false;
+
+        if (virDomainObjIsActive(vm)) {
+            /* Transitions 5, 6, 8, 9 */
+            /* Check for ABI compatibility.  */
+            if (!virDomainDefCheckABIStability(vm->def, config)) {
+                virErrorPtr err = virGetLastError();
+
+                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+                    /* Re-spawn error using correct category. */
+                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
+                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+                                       err->str2);
+                    goto cleanup;
+                }
+
+                virResetError(err);
+                testDomainShutdownState(snapshot->domain, vm,
+                                        VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+                event = virDomainEventLifecycleNewFromObj(vm,
+                            VIR_DOMAIN_EVENT_STOPPED,
+                            VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+                testObjectEventQueue(privconn, event);
+                goto load;
+            }
+
+            if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+                /* Transitions 5, 6 */
+                was_running = true;
+                virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+                                     VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+                /* Create an event now in case the restore fails, so
+                 * that user will be alerted that they are now paused.
+                 * If restore later succeeds, we might replace this. */
+                event = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_SUSPENDED,
+                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+            }
+            virDomainObjAssignDef(vm, config, false, NULL);
+
+        } else {
+            /* Transitions 2, 3 */
+        load:
+            was_stopped = true;
+            virDomainObjAssignDef(vm, config, false, NULL);
+            if (testDomainStartState(privconn, vm,
+                                VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
+                goto cleanup;
+            event = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_STARTED,
+                                VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+        }
+
+        /* Touch up domain state.  */
+        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
+            (snap->def->state == VIR_DOMAIN_PAUSED ||
+             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+            /* Transitions 3, 6, 9 */
+            virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+                                 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+            if (was_stopped) {
+                /* Transition 3, use event as-is and add event2 */
+                event2 = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_SUSPENDED,
+                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+            } /* else transition 6 and 9 use event as-is */
+        } else {
+            /* Transitions 2, 5, 8 */
+            virObjectUnref(event);
+            event = NULL;
+
+            if (was_stopped) {
+                /* Transition 2 */
+                event = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_STARTED,
+                                VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+            } else if (was_running) {
+                /* Transition 8 */
+                event = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_RESUMED,
+                                VIR_DOMAIN_EVENT_RESUMED);
+            }
+        }
+    } else {
+        /* Transitions 1, 4, 7 */
+        virDomainObjAssignDef(vm, config, false, NULL);
+
+        if (virDomainObjIsActive(vm)) {
+            /* Transitions 4, 7 */
+            testDomainShutdownState(snapshot->domain, vm,
+                                    VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+            event = virDomainEventLifecycleNewFromObj(vm,
+                                    VIR_DOMAIN_EVENT_STOPPED,
+                                    VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+        }
+
+        if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+                     VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
+            /* Flush first event, now do transition 2 or 3 */
+            bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
+
+            testObjectEventQueue(privconn, event);
+            event = virDomainEventLifecycleNewFromObj(vm,
+                            VIR_DOMAIN_EVENT_STARTED,
+                            VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+            if (paused) {
+                event2 = virDomainEventLifecycleNewFromObj(vm,
+                                VIR_DOMAIN_EVENT_SUSPENDED,
+                                VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+            }
+        }
+    }
+
+    vm->current_snapshot = snap;
+    ret = 0;
+ cleanup:
+    if (event) {
+        testObjectEventQueue(privconn, event);
+        testObjectEventQueue(privconn, event2);
+    } else {
+        virObjectUnref(event2);
+    }
+    virDomainObjEndAPI(&vm);
+
+    return ret;
+}
+
+static char *
+testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
+                       const char **xmlCPUs,
+                       unsigned int ncpus,
+                       unsigned int flags)
+{
+    char *cpu;
+
+    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
+
+    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
+
+    return cpu;
+}
+
+virHypervisorDriver testHypervisorDriver = {
+    .name = "Test",
+    .connectOpen = testConnectOpen, /* 0.1.1 */
+    .connectClose = testConnectClose, /* 0.1.1 */
+    .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
+    .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
+    .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
+    .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
+    .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
+    .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
+    .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
+    .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
+    .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
+    .connectGetType = testConnectGetType, /* 2.3.0 */
+    .connectListDomains = testConnectListDomains, /* 0.1.1 */
+    .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
+    .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
+    .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
+    .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
+    .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
+    .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
+    .domainSuspend = testDomainSuspend, /* 0.1.1 */
+    .domainResume = testDomainResume, /* 0.1.1 */
+    .domainShutdown = testDomainShutdown, /* 0.1.1 */
+    .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
+    .domainReboot = testDomainReboot, /* 0.1.1 */
+    .domainDestroy = testDomainDestroy, /* 0.1.1 */
+    .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
+    .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
+    .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
+    .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
+    .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
+    .domainGetState = testDomainGetState, /* 0.9.2 */
+    .domainSave = testDomainSave, /* 0.3.2 */
+    .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
+    .domainRestore = testDomainRestore, /* 0.3.2 */
+    .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
+    .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
+    .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
+    .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
+    .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
+    .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
+    .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
+    .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
+    .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
+    .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
+    .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
+    .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
+    .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
+    .domainCreate = testDomainCreate, /* 0.1.11 */
+    .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
+    .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
+    .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
+    .domainUndefine = testDomainUndefine, /* 0.1.11 */
+    .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
+    .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
+    .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
+    .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
+    .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
+    .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
+    .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
+    .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
+    .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
+    .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
+    .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
+    .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
+    .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
+    .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
+    .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
+    .domainIsActive = testDomainIsActive, /* 0.7.3 */
+    .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
+    .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
+    .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
+    .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
+    .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
+    .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
+    .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
+    .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
+    .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
+    .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
+    .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
+    .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
+    .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
+
+    .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
+    .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
+    .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
+    .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
+    .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
+    .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
+    .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
+    .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
+    .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
+    .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
+    .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
+    .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
+    .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
+    .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
+    .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
+    .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
+
+    .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
+};
diff --git a/src/test/test_hypervisor_driver.h b/src/test/test_hypervisor_driver.h
new file mode 100644
index 0000000..ffca9c2
--- /dev/null
+++ b/src/test/test_hypervisor_driver.h
@@ -0,0 +1 @@
+extern virHypervisorDriver testHypervisorDriver;
diff --git a/src/test/test_interface_driver.c b/src/test/test_interface_driver.c
new file mode 100644
index 0000000..a749b9f
--- /dev/null
+++ b/src/test/test_interface_driver.c
@@ -0,0 +1,487 @@
+/*
+ * test_interface_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_interface_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfInterfaces(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    size_t i;
+    int count = 0;
+
+    testDriverLock(privconn);
+    for (i = 0; (i < privconn->ifaces.count); i++) {
+        virInterfaceObjLock(privconn->ifaces.objs[i]);
+        if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+            count++;
+        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+    }
+    testDriverUnlock(privconn);
+    return count;
+}
+
+static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+    testDriverPtr privconn = conn->privateData;
+    int n = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    memset(names, 0, sizeof(*names)*nnames);
+    for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+        virInterfaceObjLock(privconn->ifaces.objs[i]);
+        if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+            if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+                virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+                goto error;
+            }
+        }
+        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    return n;
+
+ error:
+    for (n = 0; n < nnames; n++)
+        VIR_FREE(names[n]);
+    testDriverUnlock(privconn);
+    return -1;
+}
+
+static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    size_t i;
+    int count = 0;
+
+    testDriverLock(privconn);
+    for (i = 0; i < privconn->ifaces.count; i++) {
+        virInterfaceObjLock(privconn->ifaces.objs[i]);
+        if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+            count++;
+        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+    }
+    testDriverUnlock(privconn);
+    return count;
+}
+
+static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+    testDriverPtr privconn = conn->privateData;
+    int n = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    memset(names, 0, sizeof(*names)*nnames);
+    for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+        virInterfaceObjLock(privconn->ifaces.objs[i]);
+        if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+            if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+                virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+                goto error;
+            }
+        }
+        virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    return n;
+
+ error:
+    for (n = 0; n < nnames; n++)
+        VIR_FREE(names[n]);
+    testDriverUnlock(privconn);
+    return -1;
+}
+
+static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
+                                                 const char *name)
+{
+    testDriverPtr privconn = conn->privateData;
+    virInterfaceObjPtr iface;
+    virInterfacePtr ret = NULL;
+
+    testDriverLock(privconn);
+    iface = virInterfaceFindByName(&privconn->ifaces, name);
+    testDriverUnlock(privconn);
+
+    if (iface == NULL) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+    if (iface)
+        virInterfaceObjUnlock(iface);
+    return ret;
+}
+
+static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
+                                                      const char *mac)
+{
+    testDriverPtr privconn = conn->privateData;
+    virInterfaceObjPtr iface;
+    int ifacect;
+    virInterfacePtr ret = NULL;
+
+    testDriverLock(privconn);
+    ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
+    testDriverUnlock(privconn);
+
+    if (ifacect == 0) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+
+    if (ifacect > 1) {
+        virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+    if (iface)
+        virInterfaceObjUnlock(iface);
+    return ret;
+}
+
+static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
+                                     unsigned int flags)
+{
+    testDriverPtr privconn = iface->conn->privateData;
+    virInterfaceObjPtr privinterface;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    privinterface = virInterfaceFindByName(&privconn->ifaces,
+                                           iface->name);
+    testDriverUnlock(privconn);
+
+    if (privinterface == NULL) {
+        virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
+        goto cleanup;
+    }
+
+    ret = virInterfaceDefFormat(privinterface->def);
+
+ cleanup:
+    if (privinterface)
+        virInterfaceObjUnlock(privinterface);
+    return ret;
+}
+
+static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
+                                              unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    virInterfaceDefPtr def;
+    virInterfaceObjPtr iface = NULL;
+    virInterfacePtr ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
+        goto cleanup;
+
+    if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
+        goto cleanup;
+    def = NULL;
+
+    ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+    virInterfaceDefFree(def);
+    if (iface)
+        virInterfaceObjUnlock(iface);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testInterfaceUndefine(virInterfacePtr iface)
+{
+    testDriverPtr privconn = iface->conn->privateData;
+    virInterfaceObjPtr privinterface;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privinterface = virInterfaceFindByName(&privconn->ifaces,
+                                           iface->name);
+
+    if (privinterface == NULL) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+
+    virInterfaceRemove(&privconn->ifaces,
+                       privinterface);
+    ret = 0;
+
+ cleanup:
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testInterfaceCreate(virInterfacePtr iface,
+                               unsigned int flags)
+{
+    testDriverPtr privconn = iface->conn->privateData;
+    virInterfaceObjPtr privinterface;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privinterface = virInterfaceFindByName(&privconn->ifaces,
+                                           iface->name);
+
+    if (privinterface == NULL) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+
+    if (privinterface->active != 0) {
+        virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+        goto cleanup;
+    }
+
+    privinterface->active = 1;
+    ret = 0;
+
+ cleanup:
+    if (privinterface)
+        virInterfaceObjUnlock(privinterface);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testInterfaceDestroy(virInterfacePtr iface,
+                                unsigned int flags)
+{
+    testDriverPtr privconn = iface->conn->privateData;
+    virInterfaceObjPtr privinterface;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privinterface = virInterfaceFindByName(&privconn->ifaces,
+                                           iface->name);
+
+    if (privinterface == NULL) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+
+    if (privinterface->active == 0) {
+        virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+        goto cleanup;
+    }
+
+    privinterface->active = 0;
+    ret = 0;
+
+ cleanup:
+    if (privinterface)
+        virInterfaceObjUnlock(privinterface);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testInterfaceIsActive(virInterfacePtr iface)
+{
+    testDriverPtr privconn = iface->conn->privateData;
+    virInterfaceObjPtr obj;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
+    testDriverUnlock(privconn);
+    if (!obj) {
+        virReportError(VIR_ERR_NO_INTERFACE, NULL);
+        goto cleanup;
+    }
+    ret = virInterfaceObjIsActive(obj);
+
+ cleanup:
+    if (obj)
+        virInterfaceObjUnlock(obj);
+    return ret;
+}
+
+static int testInterfaceChangeBegin(virConnectPtr conn,
+                                    unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    if (privconn->transaction_running) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("there is another transaction running."));
+        goto cleanup;
+    }
+
+    privconn->transaction_running = true;
+
+    if (virInterfaceObjListClone(&privconn->ifaces,
+                                 &privconn->backupIfaces) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int testInterfaceChangeCommit(virConnectPtr conn,
+                                     unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+
+    if (!privconn->transaction_running) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("no transaction running, "
+                         "nothing to be committed."));
+        goto cleanup;
+    }
+
+    virInterfaceObjListFree(&privconn->backupIfaces);
+    privconn->transaction_running = false;
+
+    ret = 0;
+
+ cleanup:
+    testDriverUnlock(privconn);
+
+    return ret;
+}
+
+static int testInterfaceChangeRollback(virConnectPtr conn,
+                                       unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+
+    if (!privconn->transaction_running) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("no transaction running, "
+                         "nothing to rollback."));
+        goto cleanup;
+    }
+
+    virInterfaceObjListFree(&privconn->ifaces);
+    privconn->ifaces.count = privconn->backupIfaces.count;
+    privconn->ifaces.objs = privconn->backupIfaces.objs;
+    privconn->backupIfaces.count = 0;
+    privconn->backupIfaces.objs = NULL;
+
+    privconn->transaction_running = false;
+
+    ret = 0;
+
+ cleanup:
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+virInterfaceDriver testInterfaceDriver = {
+    .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
+    .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
+    .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
+    .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
+    .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
+    .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
+    .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
+    .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
+    .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
+    .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
+    .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
+    .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
+    .interfaceChangeBegin = testInterfaceChangeBegin,   /* 0.9.2 */
+    .interfaceChangeCommit = testInterfaceChangeCommit,  /* 0.9.2 */
+    .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
+};
diff --git a/src/test/test_interface_driver.h b/src/test/test_interface_driver.h
new file mode 100644
index 0000000..34cdc43
--- /dev/null
+++ b/src/test/test_interface_driver.h
@@ -0,0 +1 @@
+extern virInterfaceDriver testInterfaceDriver;
diff --git a/src/test/test_network_driver.c b/src/test/test_network_driver.c
new file mode 100644
index 0000000..34b30fb
--- /dev/null
+++ b/src/test/test_network_driver.c
@@ -0,0 +1,540 @@
+/*
+ * test_network_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+#include "test_network_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfNetworks(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    int numActive;
+
+    numActive = virNetworkObjListNumOfNetworks(privconn->networks,
+                                               true, NULL, conn);
+    return numActive;
+}
+
+static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
+    testDriverPtr privconn = conn->privateData;
+    int n;
+
+    n = virNetworkObjListGetNames(privconn->networks,
+                                  true, names, nnames, NULL, conn);
+    return n;
+}
+
+static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    int numInactive;
+
+    numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
+                                                 false, NULL, conn);
+    return numInactive;
+}
+
+static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
+    testDriverPtr privconn = conn->privateData;
+    int n;
+
+    n = virNetworkObjListGetNames(privconn->networks,
+                                  false, names, nnames, NULL, conn);
+    return n;
+}
+
+static int
+testConnectListAllNetworks(virConnectPtr conn,
+                           virNetworkPtr **nets,
+                           unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+
+    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
+
+    return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
+}
+
+static int testNetworkIsActive(virNetworkPtr net)
+{
+    testDriverPtr privconn = net->conn->privateData;
+    virNetworkObjPtr obj;
+    int ret = -1;
+
+    obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NETWORK, NULL);
+        goto cleanup;
+    }
+    ret = virNetworkObjIsActive(obj);
+
+ cleanup:
+    virNetworkObjEndAPI(&obj);
+    return ret;
+}
+
+static int testNetworkIsPersistent(virNetworkPtr net)
+{
+    testDriverPtr privconn = net->conn->privateData;
+    virNetworkObjPtr obj;
+    int ret = -1;
+
+    obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+    if (!obj) {
+        virReportError(VIR_ERR_NO_NETWORK, NULL);
+        goto cleanup;
+    }
+    ret = obj->persistent;
+
+ cleanup:
+    virNetworkObjEndAPI(&obj);
+    return ret;
+}
+
+
+static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
+{
+    testDriverPtr privconn = conn->privateData;
+    virNetworkDefPtr def;
+    virNetworkObjPtr net = NULL;
+    virNetworkPtr ret = NULL;
+    virObjectEventPtr event = NULL;
+
+    if ((def = virNetworkDefParseString(xml)) == NULL)
+        goto cleanup;
+
+    if (!(net = virNetworkAssignDef(privconn->networks, def,
+                                    VIR_NETWORK_OBJ_LIST_ADD_LIVE |
+                                    VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
+        goto cleanup;
+    def = NULL;
+    net->active = 1;
+
+    event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+                                        VIR_NETWORK_EVENT_STARTED,
+                                        0);
+
+    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+    virNetworkDefFree(def);
+    testObjectEventQueue(privconn, event);
+    virNetworkObjEndAPI(&net);
+    return ret;
+}
+
+static
+virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
+{
+    testDriverPtr privconn = conn->privateData;
+    virNetworkDefPtr def;
+    virNetworkObjPtr net = NULL;
+    virNetworkPtr ret = NULL;
+    virObjectEventPtr event = NULL;
+
+    if ((def = virNetworkDefParseString(xml)) == NULL)
+        goto cleanup;
+
+    if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
+        goto cleanup;
+    def = NULL;
+
+    event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+                                        VIR_NETWORK_EVENT_DEFINED,
+                                        0);
+
+    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+    virNetworkDefFree(def);
+    testObjectEventQueue(privconn, event);
+    virNetworkObjEndAPI(&net);
+    return ret;
+}
+
+static int testNetworkUndefine(virNetworkPtr network)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virNetworkObjIsActive(privnet)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("Network '%s' is still running"), network->name);
+        goto cleanup;
+    }
+
+    event = virNetworkEventLifecycleNew(network->name, network->uuid,
+                                        VIR_NETWORK_EVENT_UNDEFINED,
+                                        0);
+
+    virNetworkRemoveInactive(privconn->networks, privnet);
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static int
+testNetworkUpdate(virNetworkPtr net,
+                  unsigned int command,
+                  unsigned int section,
+                  int parentIndex,
+                  const char *xml,
+                  unsigned int flags)
+{
+    testDriverPtr privconn = net->conn->privateData;
+    virNetworkObjPtr network = NULL;
+    int isActive, ret = -1;
+
+    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
+                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
+                  -1);
+
+    network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+    if (!network) {
+        virReportError(VIR_ERR_NO_NETWORK,
+                       "%s", _("no network with matching uuid"));
+        goto cleanup;
+    }
+
+    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
+     * is active, else change CONFIG
+    */
+    isActive = virNetworkObjIsActive(network);
+    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
+                   | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
+        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
+        if (isActive)
+            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
+        else
+            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
+    }
+
+    /* update the network config in memory/on disk */
+    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
+       goto cleanup;
+
+    ret = 0;
+ cleanup:
+    virNetworkObjEndAPI(&network);
+    return ret;
+}
+
+static int testNetworkCreate(virNetworkPtr network)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virNetworkObjIsActive(privnet)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("Network '%s' is already running"), network->name);
+        goto cleanup;
+    }
+
+    privnet->active = 1;
+    event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+                                        VIR_NETWORK_EVENT_STARTED,
+                                        0);
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static int testNetworkDestroy(virNetworkPtr network)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privnet->active = 0;
+    event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+                                        VIR_NETWORK_EVENT_STOPPED,
+                                        0);
+    if (!privnet->persistent)
+        virNetworkRemoveInactive(privconn->networks, privnet);
+
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static char *testNetworkGetXMLDesc(virNetworkPtr network,
+                                   unsigned int flags)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    ret = virNetworkDefFormat(privnet->def, flags);
+
+ cleanup:
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static char *testNetworkGetBridgeName(virNetworkPtr network) {
+    testDriverPtr privconn = network->conn->privateData;
+    char *bridge = NULL;
+    virNetworkObjPtr privnet;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!(privnet->def->bridge)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("network '%s' does not have a bridge name."),
+                       privnet->def->name);
+        goto cleanup;
+    }
+
+    ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
+
+ cleanup:
+    virNetworkObjEndAPI(&privnet);
+    return bridge;
+}
+
+static int testNetworkGetAutostart(virNetworkPtr network,
+                                   int *autostart)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    int ret = -1;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    *autostart = privnet->autostart;
+    ret = 0;
+
+ cleanup:
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static int testNetworkSetAutostart(virNetworkPtr network,
+                                   int autostart)
+{
+    testDriverPtr privconn = network->conn->privateData;
+    virNetworkObjPtr privnet;
+    int ret = -1;
+
+    privnet = virNetworkObjFindByName(privconn->networks, network->name);
+    if (privnet == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privnet->autostart = autostart ? 1 : 0;
+    ret = 0;
+
+ cleanup:
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
+                                             const unsigned char *uuid)
+{
+    testDriverPtr privconn = conn->privateData;
+    virNetworkObjPtr net;
+    virNetworkPtr ret = NULL;
+
+    net = virNetworkObjFindByUUID(privconn->networks, uuid);
+    if (net == NULL) {
+        virReportError(VIR_ERR_NO_NETWORK, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+    virNetworkObjEndAPI(&net);
+    return ret;
+}
+
+static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
+                                             const char *name)
+{
+    testDriverPtr privconn = conn->privateData;
+    virNetworkObjPtr net;
+    virNetworkPtr ret = NULL;
+
+    net = virNetworkObjFindByName(privconn->networks, name);
+    if (net == NULL) {
+        virReportError(VIR_ERR_NO_NETWORK, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+    virNetworkObjEndAPI(&net);
+    return ret;
+}
+
+static int
+testConnectNetworkEventRegisterAny(virConnectPtr conn,
+                                   virNetworkPtr net,
+                                   int eventID,
+                                   virConnectNetworkEventGenericCallback callback,
+                                   void *opaque,
+                                   virFreeCallback freecb)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret;
+
+    if (virNetworkEventStateRegisterID(conn, driver->eventState,
+                                       net, eventID, callback,
+                                       opaque, freecb, &ret) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int
+testConnectNetworkEventDeregisterAny(virConnectPtr conn,
+                                     int callbackID)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virObjectEventStateDeregisterID(conn, driver->eventState,
+                                        callbackID) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+virNetworkDriver testNetworkDriver = {
+    .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
+    .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
+    .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
+    .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
+    .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
+    .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
+    .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
+    .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
+    .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
+    .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
+    .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
+    .networkUndefine = testNetworkUndefine, /* 0.3.2 */
+    .networkUpdate = testNetworkUpdate, /* 0.10.2 */
+    .networkCreate = testNetworkCreate, /* 0.3.2 */
+    .networkDestroy = testNetworkDestroy, /* 0.3.2 */
+    .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
+    .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
+    .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
+    .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
+    .networkIsActive = testNetworkIsActive, /* 0.7.3 */
+    .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_network_driver.h b/src/test/test_network_driver.h
new file mode 100644
index 0000000..a87b7a4
--- /dev/null
+++ b/src/test/test_network_driver.h
@@ -0,0 +1 @@
+extern virNetworkDriver testNetworkDriver;
diff --git a/src/test/test_private_driver.h b/src/test/test_private_driver.h
new file mode 100644
index 0000000..751933c
--- /dev/null
+++ b/src/test/test_private_driver.h
@@ -0,0 +1,70 @@
+#ifndef __TEST_DRIVER_H__
+# define __TEST_DRIVER_H__
+
+# define MAX_CPUS 128
+
+struct _testCell {
+    unsigned long mem;
+    unsigned long freeMem;
+    int numCpus;
+    virCapsHostNUMACellCPU cpus[MAX_CPUS];
+};
+typedef struct _testCell testCell;
+typedef struct _testCell *testCellPtr;
+
+# define MAX_CELLS 128
+
+struct _testAuth {
+    char *username;
+    char *password;
+};
+typedef struct _testAuth testAuth;
+typedef struct _testAuth *testAuthPtr;
+
+struct _testDriver {
+    virMutex lock;
+
+    virNodeInfo nodeInfo;
+    virInterfaceObjList ifaces;
+    bool transaction_running;
+    virInterfaceObjList backupIfaces;
+    virStoragePoolObjList pools;
+    virNodeDeviceObjList devs;
+    int numCells;
+    testCell cells[MAX_CELLS];
+    size_t numAuths;
+    testAuthPtr auths;
+
+    /* virAtomic access only */
+    volatile int nextDomID;
+
+    /* immutable pointer, immutable object after being initialized with
+     * testBuildCapabilities */
+    virCapsPtr caps;
+
+    /* immutable pointer, immutable object */
+    virDomainXMLOptionPtr xmlopt;
+
+    /* immutable pointer, self-locking APIs */
+    virDomainObjListPtr domains;
+    virNetworkObjListPtr networks;
+    virObjectEventStatePtr eventState;
+};
+typedef struct _testDriver testDriver;
+typedef testDriver *testDriverPtr;
+
+# define VIR_FROM_THIS VIR_FROM_TEST
+
+extern unsigned long long defaultPoolAlloc;
+
+extern unsigned long long defaultPoolCap;
+
+void testDriverLock(testDriverPtr driver);
+void testDriverUnlock(testDriverPtr driver);
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+
+void testObjectEventQueue(testDriverPtr driver,
+                          virObjectEventPtr event);
+
+#endif /* __TEST_DRIVER_H__ */
diff --git a/src/test/test_storage_driver.c b/src/test/test_storage_driver.c
new file mode 100644
index 0000000..bda43c1
--- /dev/null
+++ b/src/test/test_storage_driver.c
@@ -0,0 +1,1517 @@
+/*
+ * test_storage_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_storage_driver.h"
+
+#include "test_private_driver.h"
+
+static int
+testConnectNumOfStoragePools(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    int numActive = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    for (i = 0; i < privconn->pools.count; i++)
+        if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
+            numActive++;
+    testDriverUnlock(privconn);
+
+    return numActive;
+}
+
+static int
+testConnectListStoragePools(virConnectPtr conn,
+                            char **const names,
+                            int nnames)
+{
+    testDriverPtr privconn = conn->privateData;
+    int n = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    memset(names, 0, sizeof(*names)*nnames);
+    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+        virStoragePoolObjLock(privconn->pools.objs[i]);
+        if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+            virStoragePoolObjUnlock(privconn->pools.objs[i]);
+            goto error;
+        }
+        virStoragePoolObjUnlock(privconn->pools.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    return n;
+
+ error:
+    for (n = 0; n < nnames; n++)
+        VIR_FREE(names[n]);
+    testDriverUnlock(privconn);
+    return -1;
+}
+
+static int
+testConnectNumOfDefinedStoragePools(virConnectPtr conn)
+{
+    testDriverPtr privconn = conn->privateData;
+    int numInactive = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    for (i = 0; i < privconn->pools.count; i++) {
+        virStoragePoolObjLock(privconn->pools.objs[i]);
+        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
+            numInactive++;
+        virStoragePoolObjUnlock(privconn->pools.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    return numInactive;
+}
+
+static int
+testConnectListDefinedStoragePools(virConnectPtr conn,
+                                   char **const names,
+                                   int nnames)
+{
+    testDriverPtr privconn = conn->privateData;
+    int n = 0;
+    size_t i;
+
+    testDriverLock(privconn);
+    memset(names, 0, sizeof(*names)*nnames);
+    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+        virStoragePoolObjLock(privconn->pools.objs[i]);
+        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+            virStoragePoolObjUnlock(privconn->pools.objs[i]);
+            goto error;
+        }
+        virStoragePoolObjUnlock(privconn->pools.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    return n;
+
+ error:
+    for (n = 0; n < nnames; n++)
+        VIR_FREE(names[n]);
+    testDriverUnlock(privconn);
+    return -1;
+}
+
+static int
+testConnectListAllStoragePools(virConnectPtr conn,
+                               virStoragePoolPtr **pools,
+                               unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    int ret = -1;
+
+    virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
+
+    testDriverLock(privconn);
+    ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
+                                      NULL, flags);
+    testDriverUnlock(privconn);
+
+    return ret;
+}
+
+static const char *defaultPoolSourcesLogicalXML =
+"<sources>\n"
+"  <source>\n"
+"    <device path='/dev/sda20'/>\n"
+"    <name>testvg1</name>\n"
+"    <format type='lvm2'/>\n"
+"  </source>\n"
+"  <source>\n"
+"    <device path='/dev/sda21'/>\n"
+"    <name>testvg2</name>\n"
+"    <format type='lvm2'/>\n"
+"  </source>\n"
+"</sources>\n";
+
+static const char *defaultPoolSourcesNetFSXML =
+"<sources>\n"
+"  <source>\n"
+"    <host name='%s'/>\n"
+"    <dir path='/testshare'/>\n"
+"    <format type='nfs'/>\n"
+"  </source>\n"
+"</sources>\n";
+
+static char *
+testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                  const char *type,
+                                  const char *srcSpec,
+                                  unsigned int flags)
+{
+    virStoragePoolSourcePtr source = NULL;
+    int pool_type;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    pool_type = virStoragePoolTypeFromString(type);
+    if (!pool_type) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unknown storage pool type %s"), type);
+        goto cleanup;
+    }
+
+    if (srcSpec) {
+        source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
+        if (!source)
+            goto cleanup;
+    }
+
+    switch (pool_type) {
+
+    case VIR_STORAGE_POOL_LOGICAL:
+        ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
+        break;
+
+    case VIR_STORAGE_POOL_NETFS:
+        if (!source || !source->hosts[0].name) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           "%s", _("hostname must be specified for netfs sources"));
+            goto cleanup;
+        }
+
+        ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
+                                 source->hosts[0].name));
+        break;
+
+    default:
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       _("pool type '%s' does not support source discovery"), type);
+    }
+
+ cleanup:
+    virStoragePoolSourceFree(source);
+    return ret;
+}
+
+static int
+testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
+                                       virStoragePoolPtr pool,
+                                       int eventID,
+                                       virConnectStoragePoolEventGenericCallback callback,
+                                       void *opaque,
+                                       virFreeCallback freecb)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret;
+
+    if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
+                                           pool, eventID, callback,
+                                           opaque, freecb, &ret) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int
+testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
+                                         int callbackID)
+{
+    testDriverPtr driver = conn->privateData;
+    int ret = 0;
+
+    if (virObjectEventStateDeregisterID(conn, driver->eventState,
+                                        callbackID) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByName(virConnectPtr conn,
+                            const char *name)
+{
+    testDriverPtr privconn = conn->privateData;
+    virStoragePoolObjPtr pool;
+    virStoragePoolPtr ret = NULL;
+
+    testDriverLock(privconn);
+    pool = virStoragePoolObjFindByName(&privconn->pools, name);
+    testDriverUnlock(privconn);
+
+    if (pool == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+    return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByVolume(virStorageVolPtr vol)
+{
+    return testStoragePoolLookupByName(vol->conn, vol->pool);
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByUUID(virConnectPtr conn,
+                            const unsigned char *uuid)
+{
+    testDriverPtr privconn = conn->privateData;
+    virStoragePoolObjPtr pool;
+    virStoragePoolPtr ret = NULL;
+
+    testDriverLock(privconn);
+    pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
+    testDriverUnlock(privconn);
+
+    if (pool == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+        goto cleanup;
+    }
+
+    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+    return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolCreateXML(virConnectPtr conn,
+                         const char *xml,
+                         unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    virStoragePoolDefPtr def;
+    virStoragePoolObjPtr pool = NULL;
+    virStoragePoolPtr ret = NULL;
+    virObjectEventPtr event = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    if (!(def = virStoragePoolDefParseString(xml)))
+        goto cleanup;
+
+    pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
+    if (!pool)
+        pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
+    if (pool) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("storage pool already exists"));
+        goto cleanup;
+    }
+
+    if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+        goto cleanup;
+    def = NULL;
+
+    if (testStoragePoolObjSetDefaults(pool) == -1) {
+        virStoragePoolObjRemove(&privconn->pools, pool);
+        pool = NULL;
+        goto cleanup;
+    }
+    pool->active = 1;
+
+    event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+                                            VIR_STORAGE_POOL_EVENT_STARTED,
+                                            0);
+
+    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    virStoragePoolDefFree(def);
+    testObjectEventQueue(privconn, event);
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolDefineXML(virConnectPtr conn,
+                         const char *xml,
+                         unsigned int flags)
+{
+    testDriverPtr privconn = conn->privateData;
+    virStoragePoolDefPtr def;
+    virStoragePoolObjPtr pool = NULL;
+    virStoragePoolPtr ret = NULL;
+    virObjectEventPtr event = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    if (!(def = virStoragePoolDefParseString(xml)))
+        goto cleanup;
+
+    def->capacity = defaultPoolCap;
+    def->allocation = defaultPoolAlloc;
+    def->available = defaultPoolCap - defaultPoolAlloc;
+
+    if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+        goto cleanup;
+    def = NULL;
+
+    event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+                                            VIR_STORAGE_POOL_EVENT_DEFINED,
+                                            0);
+
+    if (testStoragePoolObjSetDefaults(pool) == -1) {
+        virStoragePoolObjRemove(&privconn->pools, pool);
+        pool = NULL;
+        goto cleanup;
+    }
+
+    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    virStoragePoolDefFree(def);
+    testObjectEventQueue(privconn, event);
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int
+testStoragePoolUndefine(virStoragePoolPtr pool)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is already active"), pool->name);
+        goto cleanup;
+    }
+
+    event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+                                            VIR_STORAGE_POOL_EVENT_UNDEFINED,
+                                            0);
+
+    virStoragePoolObjRemove(&privconn->pools, privpool);
+    privpool = NULL;
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    testObjectEventQueue(privconn, event);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int
+testStoragePoolBuild(virStoragePoolPtr pool,
+                     unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is already active"), pool->name);
+        goto cleanup;
+    }
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolDestroy(virStoragePoolPtr pool)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    privpool->active = 0;
+    event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
+                                            VIR_STORAGE_POOL_EVENT_STOPPED,
+                                            0);
+
+    if (privpool->configFile == NULL) {
+        virStoragePoolObjRemove(&privconn->pools, privpool);
+        privpool = NULL;
+    }
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    testDriverUnlock(privconn);
+    return ret;
+}
+
+static int
+testStoragePoolDelete(virStoragePoolPtr pool,
+                      unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is already active"), pool->name);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolRefresh(virStoragePoolPtr pool,
+                       unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolGetInfo(virStoragePoolPtr pool,
+                       virStoragePoolInfoPtr info)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    memset(info, 0, sizeof(virStoragePoolInfo));
+    if (privpool->active)
+        info->state = VIR_STORAGE_POOL_RUNNING;
+    else
+        info->state = VIR_STORAGE_POOL_INACTIVE;
+    info->capacity = privpool->def->capacity;
+    info->allocation = privpool->def->allocation;
+    info->available = privpool->def->available;
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static char *
+testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
+                          unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    ret = virStoragePoolDefFormat(privpool->def);
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolGetAutostart(virStoragePoolPtr pool,
+                            int *autostart)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!privpool->configFile) {
+        *autostart = 0;
+    } else {
+        *autostart = privpool->autostart;
+    }
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolSetAutostart(virStoragePoolPtr pool,
+                            int autostart)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!privpool->configFile) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("pool has no config file"));
+        goto cleanup;
+    }
+
+    autostart = (autostart != 0);
+    privpool->autostart = autostart;
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    ret = privpool->volumes.count;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStoragePoolListVolumes(virStoragePoolPtr pool,
+                           char **const names,
+                           int maxnames)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    size_t i = 0;
+    int n = 0;
+
+    memset(names, 0, maxnames * sizeof(*names));
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
+        if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
+            goto cleanup;
+    }
+
+    virStoragePoolObjUnlock(privpool);
+    return n;
+
+ cleanup:
+    for (n = 0; n < maxnames; n++)
+        VIR_FREE(names[i]);
+
+    memset(names, 0, maxnames * sizeof(*names));
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return -1;
+}
+
+static int
+testStoragePoolListAllVolumes(virStoragePoolPtr obj,
+                              virStorageVolPtr **vols,
+                              unsigned int flags)
+{
+    testDriverPtr privconn = obj->conn->privateData;
+    virStoragePoolObjPtr pool;
+    size_t i;
+    virStorageVolPtr *tmp_vols = NULL;
+    virStorageVolPtr vol = NULL;
+    int nvols = 0;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
+    testDriverUnlock(privconn);
+
+    if (!pool) {
+        virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
+                       _("no storage pool with matching uuid"));
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("storage pool is not active"));
+        goto cleanup;
+    }
+
+     /* Just returns the volumes count */
+    if (!vols) {
+        ret = pool->volumes.count;
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
+         goto cleanup;
+
+    for (i = 0; i < pool->volumes.count; i++) {
+        if (!(vol = virGetStorageVol(obj->conn, pool->def->name,
+                                     pool->volumes.objs[i]->name,
+                                     pool->volumes.objs[i]->key,
+                                     NULL, NULL)))
+            goto cleanup;
+        tmp_vols[nvols++] = vol;
+    }
+
+    *vols = tmp_vols;
+    tmp_vols = NULL;
+    ret = nvols;
+
+ cleanup:
+    if (tmp_vols) {
+        for (i = 0; i < nvols; i++)
+            virObjectUnref(tmp_vols[i]);
+        VIR_FREE(tmp_vols);
+    }
+
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+
+    return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByName(virStoragePoolPtr pool,
+                           const char *name ATTRIBUTE_UNUSED)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol;
+    virStorageVolPtr ret = NULL;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefFindByName(privpool, name);
+
+    if (!privvol) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"), name);
+        goto cleanup;
+    }
+
+    ret = virGetStorageVol(pool->conn, privpool->def->name,
+                           privvol->name, privvol->key,
+                           NULL, NULL);
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByKey(virConnectPtr conn,
+                          const char *key)
+{
+    testDriverPtr privconn = conn->privateData;
+    size_t i;
+    virStorageVolPtr ret = NULL;
+
+    testDriverLock(privconn);
+    for (i = 0; i < privconn->pools.count; i++) {
+        virStoragePoolObjLock(privconn->pools.objs[i]);
+        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+            virStorageVolDefPtr privvol =
+                virStorageVolDefFindByKey(privconn->pools.objs[i], key);
+
+            if (privvol) {
+                ret = virGetStorageVol(conn,
+                                       privconn->pools.objs[i]->def->name,
+                                       privvol->name,
+                                       privvol->key,
+                                       NULL, NULL);
+                virStoragePoolObjUnlock(privconn->pools.objs[i]);
+                break;
+            }
+        }
+        virStoragePoolObjUnlock(privconn->pools.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    if (!ret)
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching key '%s'"), key);
+
+    return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByPath(virConnectPtr conn,
+                           const char *path)
+{
+    testDriverPtr privconn = conn->privateData;
+    size_t i;
+    virStorageVolPtr ret = NULL;
+
+    testDriverLock(privconn);
+    for (i = 0; i < privconn->pools.count; i++) {
+        virStoragePoolObjLock(privconn->pools.objs[i]);
+        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+            virStorageVolDefPtr privvol =
+                virStorageVolDefFindByPath(privconn->pools.objs[i], path);
+
+            if (privvol) {
+                ret = virGetStorageVol(conn,
+                                       privconn->pools.objs[i]->def->name,
+                                       privvol->name,
+                                       privvol->key,
+                                       NULL, NULL);
+                virStoragePoolObjUnlock(privconn->pools.objs[i]);
+                break;
+            }
+        }
+        virStoragePoolObjUnlock(privconn->pools.objs[i]);
+    }
+    testDriverUnlock(privconn);
+
+    if (!ret)
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching path '%s'"), path);
+
+    return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXML(virStoragePoolPtr pool,
+                        const char *xmldesc,
+                        unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol = NULL;
+    virStorageVolPtr ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+    if (privvol == NULL)
+        goto cleanup;
+
+    if (virStorageVolDefFindByName(privpool, privvol->name)) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("storage vol already exists"));
+        goto cleanup;
+    }
+
+    /* Make sure enough space */
+    if ((privpool->def->allocation + privvol->target.allocation) >
+         privpool->def->capacity) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Not enough free space in pool for volume '%s'"),
+                       privvol->name);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&privvol->target.path, "%s/%s",
+                    privpool->def->target.path,
+                    privvol->name) == -1)
+        goto cleanup;
+
+    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+        VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+                                privpool->volumes.count, privvol) < 0)
+        goto cleanup;
+
+    privpool->def->allocation += privvol->target.allocation;
+    privpool->def->available = (privpool->def->capacity -
+                                privpool->def->allocation);
+
+    ret = virGetStorageVol(pool->conn, privpool->def->name,
+                           privvol->name, privvol->key,
+                           NULL, NULL);
+    privvol = NULL;
+
+ cleanup:
+    virStorageVolDefFree(privvol);
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
+                            const char *xmldesc,
+                            virStorageVolPtr clonevol,
+                            unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol = NULL, origvol = NULL;
+    virStorageVolPtr ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), pool->name);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+    if (privvol == NULL)
+        goto cleanup;
+
+    if (virStorageVolDefFindByName(privpool, privvol->name)) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("storage vol already exists"));
+        goto cleanup;
+    }
+
+    origvol = virStorageVolDefFindByName(privpool, clonevol->name);
+    if (!origvol) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"),
+                       clonevol->name);
+        goto cleanup;
+    }
+
+    /* Make sure enough space */
+    if ((privpool->def->allocation + privvol->target.allocation) >
+         privpool->def->capacity) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Not enough free space in pool for volume '%s'"),
+                       privvol->name);
+        goto cleanup;
+    }
+    privpool->def->available = (privpool->def->capacity -
+                                privpool->def->allocation);
+
+    if (virAsprintf(&privvol->target.path, "%s/%s",
+                    privpool->def->target.path,
+                    privvol->name) == -1)
+        goto cleanup;
+
+    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+        VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+                                privpool->volumes.count, privvol) < 0)
+        goto cleanup;
+
+    privpool->def->allocation += privvol->target.allocation;
+    privpool->def->available = (privpool->def->capacity -
+                                privpool->def->allocation);
+
+    ret = virGetStorageVol(pool->conn, privpool->def->name,
+                           privvol->name, privvol->key,
+                           NULL, NULL);
+    privvol = NULL;
+
+ cleanup:
+    virStorageVolDefFree(privvol);
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int
+testStorageVolDelete(virStorageVolPtr vol,
+                     unsigned int flags)
+{
+    testDriverPtr privconn = vol->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol;
+    size_t i;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           vol->pool);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+
+    privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+    if (privvol == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"),
+                       vol->name);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), vol->pool);
+        goto cleanup;
+    }
+
+
+    privpool->def->allocation -= privvol->target.allocation;
+    privpool->def->available = (privpool->def->capacity -
+                                privpool->def->allocation);
+
+    for (i = 0; i < privpool->volumes.count; i++) {
+        if (privpool->volumes.objs[i] == privvol) {
+            virStorageVolDefFree(privvol);
+
+            VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
+            break;
+        }
+    }
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static int testStorageVolumeTypeForPool(int pooltype)
+{
+
+    switch (pooltype) {
+        case VIR_STORAGE_POOL_DIR:
+        case VIR_STORAGE_POOL_FS:
+        case VIR_STORAGE_POOL_NETFS:
+            return VIR_STORAGE_VOL_FILE;
+        default:
+            return VIR_STORAGE_VOL_BLOCK;
+    }
+}
+
+static int
+testStorageVolGetInfo(virStorageVolPtr vol,
+                      virStorageVolInfoPtr info)
+{
+    testDriverPtr privconn = vol->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           vol->pool);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+    if (privvol == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"),
+                       vol->name);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), vol->pool);
+        goto cleanup;
+    }
+
+    memset(info, 0, sizeof(*info));
+    info->type = testStorageVolumeTypeForPool(privpool->def->type);
+    info->capacity = privvol->target.capacity;
+    info->allocation = privvol->target.allocation;
+    ret = 0;
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static char *
+testStorageVolGetXMLDesc(virStorageVolPtr vol,
+                         unsigned int flags)
+{
+    testDriverPtr privconn = vol->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           vol->pool);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+    if (privvol == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"),
+                       vol->name);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), vol->pool);
+        goto cleanup;
+    }
+
+    ret = virStorageVolDefFormat(privpool->def, privvol);
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+static char *
+testStorageVolGetPath(virStorageVolPtr vol)
+{
+    testDriverPtr privconn = vol->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    virStorageVolDefPtr privvol;
+    char *ret = NULL;
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           vol->pool);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+    if (privvol == NULL) {
+        virReportError(VIR_ERR_NO_STORAGE_VOL,
+                       _("no storage vol with matching name '%s'"),
+                       vol->name);
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is not active"), vol->pool);
+        goto cleanup;
+    }
+
+    ignore_value(VIR_STRDUP(ret, privvol->target.path));
+
+ cleanup:
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
+{
+
+    pool->def->capacity = defaultPoolCap;
+    pool->def->allocation = defaultPoolAlloc;
+    pool->def->available = defaultPoolCap - defaultPoolAlloc;
+
+    return VIR_STRDUP(pool->configFile, "");
+}
+
+static int testStoragePoolIsActive(virStoragePoolPtr pool)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr obj;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+    testDriverUnlock(privconn);
+    if (!obj) {
+        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+        goto cleanup;
+    }
+    ret = virStoragePoolObjIsActive(obj);
+
+ cleanup:
+    if (obj)
+        virStoragePoolObjUnlock(obj);
+    return ret;
+}
+
+static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr obj;
+    int ret = -1;
+
+    testDriverLock(privconn);
+    obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+    testDriverUnlock(privconn);
+    if (!obj) {
+        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+        goto cleanup;
+    }
+    ret = obj->configFile ? 1 : 0;
+
+ cleanup:
+    if (obj)
+        virStoragePoolObjUnlock(obj);
+    return ret;
+}
+
+static int
+testStoragePoolCreate(virStoragePoolPtr pool,
+                      unsigned int flags)
+{
+    testDriverPtr privconn = pool->conn->privateData;
+    virStoragePoolObjPtr privpool;
+    int ret = -1;
+    virObjectEventPtr event = NULL;
+
+    virCheckFlags(0, -1);
+
+    testDriverLock(privconn);
+    privpool = virStoragePoolObjFindByName(&privconn->pools,
+                                           pool->name);
+    testDriverUnlock(privconn);
+
+    if (privpool == NULL) {
+        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto cleanup;
+    }
+
+    if (virStoragePoolObjIsActive(privpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("storage pool '%s' is already active"), pool->name);
+        goto cleanup;
+    }
+
+    privpool->active = 1;
+
+    event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+                                            VIR_STORAGE_POOL_EVENT_STARTED,
+                                            0);
+    ret = 0;
+
+ cleanup:
+    testObjectEventQueue(privconn, event);
+    if (privpool)
+        virStoragePoolObjUnlock(privpool);
+    return ret;
+}
+
+virStorageDriver testStorageDriver = {
+    .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
+    .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
+    .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
+    .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
+    .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
+    .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
+    .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
+    .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
+    .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
+    .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
+    .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
+    .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
+    .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
+    .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
+    .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
+    .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
+    .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
+    .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
+    .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
+    .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
+    .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
+    .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
+    .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
+    .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
+    .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
+    .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
+
+    .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
+    .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
+    .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
+    .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
+    .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
+    .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
+    .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
+    .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
+    .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
+    .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
+    .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_storage_driver.h b/src/test/test_storage_driver.h
new file mode 100644
index 0000000..fd29eda
--- /dev/null
+++ b/src/test/test_storage_driver.h
@@ -0,0 +1 @@
+extern virStorageDriver testStorageDriver;
-- 
2.9.3

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list





[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]