]> xenbits.xensource.com Git - libvirt.git/commitdiff
event: share state driver between test:///default connections
authorEric Blake <eblake@redhat.com>
Wed, 1 Jan 2014 16:30:12 +0000 (09:30 -0700)
committerEric Blake <eblake@redhat.com>
Tue, 7 Jan 2014 15:30:32 +0000 (08:30 -0700)
Prior to this patch, every test:/// URI has its own event manager,
which means that registering for an event can only ever receive
events from the connection where it issued the API that triggered
the event.  But the whole idea of events is to be able to learn
about something where an API call did NOT trigger the action.

In order to actually test asynchronous events, I wanted to be able
to tie multiple test connections to the same state.  Use of a file
in a test URI is still per-connection state, but now parallel
connections to test:///default (from the same binary, of course)
now share common state and can affect one another.

The updated testsuite fails without the rest of this patch.
Valgrind didn't report any leaks.

* src/test/test_driver.c (testConnectOpen): Move per-connection
state initialization...
(testOpenFromFile): ...here.
(defaultConn, defaultConnections, defaultLock, testOnceInit): New
shared state.
(testOpenDefault): Only initialize on first connection.
(testConnectClose): Don't clobber state if still shared.
* tests/objecteventtest.c (testDomainStartStopEvent): Enhance to
cover this.
(timeout, mymain): Ensure test fails rather than blocks.

Signed-off-by: Eric Blake <eblake@redhat.com>
src/test/test_driver.c
tests/objecteventtest.c

index d0f3fa872b8cd5efda7a57e1aed32ce597096ee1..b8bd6f4a9269adbd629be63f63247ed54fdb4267 100644 (file)
@@ -105,6 +105,10 @@ struct _testConn {
 typedef struct _testConn testConn;
 typedef struct _testConn *testConnPtr;
 
+static testConn defaultConn;
+static int defaultConnections;
+static virMutex defaultLock;
+
 #define TEST_MODEL "i686"
 #define TEST_MODEL_WORDSIZE 32
 #define TEST_EMULATOR "/usr/bin/test-hv"
@@ -125,6 +129,14 @@ static int testConnectClose(virConnectPtr conn);
 static void testObjectEventQueue(testConnPtr driver,
                                  virObjectEventPtr event);
 
+static int
+testOnceInit(void)
+{
+    return virMutexInit(&defaultLock);
+}
+
+VIR_ONCE_GLOBAL_INIT(test)
+
 
 static void testDriverLock(testConnPtr driver)
 {
@@ -665,9 +677,15 @@ cleanup:
     return ret;
 }
 
-static int testOpenDefault(virConnectPtr conn) {
+
+/* 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;
-    testConnPtr privconn;
+    testConnPtr privconn = &defaultConn;
     virDomainDefPtr domdef = NULL;
     virDomainObjPtr domobj = NULL;
     virNetworkDefPtr netdef = NULL;
@@ -679,18 +697,26 @@ static int testOpenDefault(virConnectPtr conn) {
     virNodeDeviceDefPtr nodedef = NULL;
     virNodeDeviceObjPtr nodeobj = NULL;
 
-    if (VIR_ALLOC(privconn) < 0)
-        return VIR_DRV_OPEN_ERROR;
+    virMutexLock(&defaultLock);
+    if (defaultConnections++) {
+        conn->privateData = &defaultConn;
+        virMutexUnlock(&defaultLock);
+        return VIR_DRV_OPEN_SUCCESS;
+    }
+
     if (virMutexInit(&privconn->lock) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot initialize mutex"));
-        VIR_FREE(privconn);
+        defaultConnections--;
+        virMutexUnlock(&defaultLock);
         return VIR_DRV_OPEN_ERROR;
     }
 
-    testDriverLock(privconn);
     conn->privateData = privconn;
 
+    if (!(privconn->domainEventState = virObjectEventStateNew()))
+        goto error;
+
     if (!(privconn->domains = virDomainObjListNew()))
         goto error;
 
@@ -791,7 +817,7 @@ static int testOpenDefault(virConnectPtr conn) {
     }
     virNodeDeviceObjUnlock(nodeobj);
 
-    testDriverUnlock(privconn);
+    virMutexUnlock(&defaultLock);
 
     return VIR_DRV_OPEN_SUCCESS;
 
@@ -802,10 +828,12 @@ error:
     virStoragePoolObjListFree(&privconn->pools);
     virNodeDeviceObjListFree(&privconn->devs);
     virObjectUnref(privconn->caps);
-    testDriverUnlock(privconn);
+    virObjectEventStateFree(privconn->domainEventState);
+    virMutexDestroy(&privconn->lock);
     conn->privateData = NULL;
-    VIR_FREE(privconn);
     virDomainDefFree(domdef);
+    defaultConnections--;
+    virMutexUnlock(&defaultLock);
     return VIR_DRV_OPEN_ERROR;
 }
 
@@ -1327,6 +1355,9 @@ error:
     return ret;
 }
 
+
+/* No shared state between simultaneous test connections initialized
+ * from a file.  */
 static int
 testOpenFromFile(virConnectPtr conn, const char *file)
 {
@@ -1355,6 +1386,9 @@ testOpenFromFile(virConnectPtr conn, const char *file)
     if (!(privconn->xmlopt = testBuildXMLConfig()))
         goto error;
 
+    if (!(privconn->domainEventState = virObjectEventStateNew()))
+        goto error;
+
     if (!(doc = virXMLParseFileCtxt(file, &ctxt))) {
         goto error;
     }
@@ -1398,6 +1432,7 @@ testOpenFromFile(virConnectPtr conn, const char *file)
     virInterfaceObjListFree(&privconn->ifaces);
     virStoragePoolObjListFree(&privconn->pools);
     VIR_FREE(privconn->path);
+    virObjectEventStateFree(privconn->domainEventState);
     testDriverUnlock(privconn);
     VIR_FREE(privconn);
     conn->privateData = NULL;
@@ -1410,10 +1445,12 @@ static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
                                         unsigned int flags)
 {
     int ret;
-    testConnPtr privconn;
 
     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
 
+    if (testInitialize() < 0)
+        return VIR_DRV_OPEN_ERROR;
+
     if (!conn->uri)
         return VIR_DRV_OPEN_DECLINED;
 
@@ -1442,24 +1479,24 @@ static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
     if (ret != VIR_DRV_OPEN_SUCCESS)
         return ret;
 
-    privconn = conn->privateData;
-    testDriverLock(privconn);
-
-    privconn->domainEventState = virObjectEventStateNew();
-    if (!privconn->domainEventState) {
-        testDriverUnlock(privconn);
-        testConnectClose(conn);
-        return VIR_DRV_OPEN_ERROR;
-    }
-
-    testDriverUnlock(privconn);
-
     return VIR_DRV_OPEN_SUCCESS;
 }
 
 static int testConnectClose(virConnectPtr conn)
 {
     testConnPtr privconn = conn->privateData;
+
+    if (testInitialize() < 0)
+        return -1;
+
+    if (privconn == &defaultConn) {
+        virMutexLock(&defaultLock);
+        if (--defaultConnections) {
+            virMutexUnlock(&defaultLock);
+            return 0;
+        }
+    }
+
     testDriverLock(privconn);
     virObjectUnref(privconn->caps);
     virObjectUnref(privconn->xmlopt);
@@ -1474,7 +1511,10 @@ static int testConnectClose(virConnectPtr conn)
     testDriverUnlock(privconn);
     virMutexDestroy(&privconn->lock);
 
-    VIR_FREE(privconn);
+    if (privconn == &defaultConn)
+        virMutexUnlock(&defaultLock);
+    else
+        VIR_FREE(privconn);
     conn->privateData = NULL;
     return 0;
 }
index 833c0fc142af9575ef50f0b28cd3dc0aec3a8dc7..6f657d25b14ffe9a70fcf7e18ea2c850556bdd30 100644 (file)
@@ -265,8 +265,10 @@ testDomainStartStopEvent(const void *data)
     lifecycleEventCounter counter;
     int eventId = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
     int id;
-    int ret = 0;
+    int ret = -1;
     virDomainPtr dom;
+    virConnectPtr conn2 = NULL;
+    virDomainPtr dom2 = NULL;
 
     lifecycleEventCounter_reset(&counter);
 
@@ -282,20 +284,40 @@ testDomainStartStopEvent(const void *data)
     virDomainDestroy(dom);
     virDomainCreate(dom);
 
-    if (virEventRunDefaultImpl() < 0) {
-        ret = -1;
+    if (virEventRunDefaultImpl() < 0)
         goto cleanup;
-    }
 
     if (counter.startEvents != 1 || counter.stopEvents != 1 ||
-            counter.unexpectedEvents > 0) {
-        ret = -1;
+            counter.unexpectedEvents > 0)
+        goto cleanup;
+
+    /* Repeat the test, but this time, trigger the events via an
+     * alternate connection.  */
+    if (!(conn2 = virConnectOpen("test:///default")))
+        goto cleanup;
+    if (!(dom2 = virDomainLookupByName(conn2, "test")))
         goto cleanup;
-    }
 
+    if (virDomainDestroy(dom2) < 0)
+        goto cleanup;
+    if (virDomainCreate(dom2) < 0)
+        goto cleanup;
+
+    if (virEventRunDefaultImpl() < 0)
+        goto cleanup;
+
+    if (counter.startEvents != 2 || counter.stopEvents != 2 ||
+            counter.unexpectedEvents > 0)
+        goto cleanup;
+
+    ret = 0;
 cleanup:
     virConnectDomainEventDeregisterAny(test->conn, id);
     virDomainFree(dom);
+    if (dom2)
+        virDomainFree(dom2);
+    if (conn2)
+        virConnectClose(conn2);
 
     return ret;
 }
@@ -419,14 +441,26 @@ cleanup:
     return ret;
 }
 
+static void
+timeout(int id ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
+{
+    fputs("test taking too long; giving up", stderr);
+    _exit(EXIT_FAILURE);
+}
+
 static int
 mymain(void)
 {
     objecteventTest test;
     int ret = EXIT_SUCCESS;
+    int timer;
 
     virEventRegisterDefaultImpl();
 
+    /* Set up a timer to abort this test if it takes 10 seconds.  */
+    if ((timer = virEventAddTimeout(10 * 1000, timeout, NULL, NULL)) < 0)
+        return EXIT_FAILURE;
+
     if (!(test.conn = virConnectOpen("test:///default")))
         return EXIT_FAILURE;
 
@@ -460,6 +494,7 @@ mymain(void)
     virNetworkUndefine(test.net);
     virNetworkFree(test.net);
     virConnectClose(test.conn);
+    virEventRemoveTimeout(timer);
 
     return ret;
 }