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"
static void testObjectEventQueue(testConnPtr driver,
virObjectEventPtr event);
+static int
+testOnceInit(void)
+{
+ return virMutexInit(&defaultLock);
+}
+
+VIR_ONCE_GLOBAL_INIT(test)
+
static void testDriverLock(testConnPtr driver)
{
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;
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;
}
virNodeDeviceObjUnlock(nodeobj);
- testDriverUnlock(privconn);
+ virMutexUnlock(&defaultLock);
return VIR_DRV_OPEN_SUCCESS;
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;
}
return ret;
}
+
+/* No shared state between simultaneous test connections initialized
+ * from a file. */
static int
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;
}
virInterfaceObjListFree(&privconn->ifaces);
virStoragePoolObjListFree(&privconn->pools);
VIR_FREE(privconn->path);
+ virObjectEventStateFree(privconn->domainEventState);
testDriverUnlock(privconn);
VIR_FREE(privconn);
conn->privateData = NULL;
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;
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);
testDriverUnlock(privconn);
virMutexDestroy(&privconn->lock);
- VIR_FREE(privconn);
+ if (privconn == &defaultConn)
+ virMutexUnlock(&defaultLock);
+ else
+ VIR_FREE(privconn);
conn->privateData = NULL;
return 0;
}
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);
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;
}
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;
virNetworkUndefine(test.net);
virNetworkFree(test.net);
virConnectClose(test.conn);
+ virEventRemoveTimeout(timer);
return ret;
}