diff --git a/src/test/test_driver.c b/src/test/test_driver.c index d0f3fa872b8cd5efda7a57e1aed32ce597096ee1..b8bd6f4a9269adbd629be63f63247ed54fdb4267 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -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; } diff --git a/tests/objecteventtest.c b/tests/objecteventtest.c index 833c0fc142af9575ef50f0b28cd3dc0aec3a8dc7..6f657d25b14ffe9a70fcf7e18ea2c850556bdd30 100644 --- a/tests/objecteventtest.c +++ b/tests/objecteventtest.c @@ -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; }