From: Daniel P. Berrange Date: Tue, 6 Jun 2006 03:32:51 +0000 (+0000) Subject: Added 'mock' hypervisor driver for use by unit tests X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=e5bb0cb05237229d8cfbaf9b19f909795d158b52;p=libvirt.git Added 'mock' hypervisor driver for use by unit tests --- diff --git a/ChangeLog b/ChangeLog index 4e874cde9b..9def3aaa20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Jun 05 22:31:20 EDT 2006 Daniel P. Berrange + + * src/test.c, src/test.h: New 'mock' hypervisor driver providing + a way to write predictable unit tests which exercise libvirt APIs. + * src/libvirt.c, src/Makefile.am: Integrate test hypervisor driver + Fri May 26 11:59:20 EDT 2006 Daniel P. Berrange * src/hash.c, src/internal.h: Switch the uuid parameter in virGetDomain diff --git a/src/Makefile.am b/src/Makefile.am index a4471e8b0b..2f814bf058 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \ libvirt_la_SOURCES = \ libvirt.c internal.h \ hash.c hash.h \ + test.c test.h \ xml.c xml.h \ xen_internal.c xen_internal.h \ xs_internal.c xs_internal.h \ diff --git a/src/libvirt.c b/src/libvirt.c index aba1ba7095..f03a244c1f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -29,6 +29,7 @@ #include "xend_internal.h" #include "xs_internal.h" #include "xml.h" +#include "test.h" /* * TODO: @@ -70,6 +71,7 @@ virInitialize(void) xenHypervisorRegister(); xenDaemonRegister(); xenStoreRegister(); + testRegister(); return(0); } diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000000..ab161a911c --- /dev/null +++ b/src/test.c @@ -0,0 +1,350 @@ +/* + * test.c: A "mock" hypervisor for use by application unit tests + * + * Copyright (C) 2006 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Berrange + */ + +#include +#include +#include +#include + +#include "internal.h" +#include "test.h" + +static virDriver testDriver = { + "Test", + NULL, /* init */ + testOpen, /* open */ + testClose, /* close */ + NULL, /* type */ + testGetVersion, /* version */ + testNodeGetInfo, /* nodeGetInfo */ + testListDomains, /* listDomains */ + testNumOfDomains, /* numOfDomains */ + NULL, /* domainCreateLinux */ + testLookupDomainByID, /* domainLookupByID */ + testLookupDomainByUUID, /* domainLookupByUUID */ + testLookupDomainByName, /* domainLookupByName */ + testPauseDomain, /* domainSuspend */ + testResumeDomain, /* domainResume */ + NULL, /* domainShutdown */ + NULL, /* domainReboot */ + testDestroyDomain, /* domainDestroy */ + NULL, /* domainFree */ + NULL, /* domainGetName */ + NULL, /* domainGetID */ + NULL, /* domainGetUUID */ + NULL, /* domainGetOSType */ + NULL, /* domainGetMaxMemory */ + testSetMaxMemory, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + testGetDomainInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL /* domainRestore */ +}; + +typedef struct _testDev { + char name[20]; + virDeviceMode mode; +} testDev; + +#define MAX_DEVICES 10 + +typedef struct _testDom { + int active; + char name[20]; + unsigned char uuid[16]; + virDomainKernel kernel; + virDomainInfo info; + virDomainRestart onRestart; + int numDevices; + testDev devices[MAX_DEVICES]; +} testDom; + +#define MAX_DOMAINS 20 + +typedef struct _testCon { + int active; + int numDomains; + testDom domains[MAX_DOMAINS]; +} testCon; + +#define MAX_CONNECTIONS 5 + +typedef struct _testNode { + int numConnections; + testCon connections[MAX_CONNECTIONS]; +} testNode; + +/* XXX, how about we stuff this in a SHM + segment so multiple apps can run tests + against the mock hypervisor concurrently. + Would need a pthread process shared mutex + too probably */ +static testNode *node = NULL; + +static virNodeInfo nodeInfo = { + "i86", + 1024*1024*3, /* 3 GB */ + 16, + 1400, + 2, + 2, + 2, + 2, +}; + +static void +testError(virConnectPtr con, + virDomainPtr dom, + virErrorNumber error, + const char *info) +{ + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + __virRaiseError(con, dom, VIR_FROM_XEN, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info, 0); +} + + +/** + * testRegister: + * + * Registers the test driver + */ +void testRegister(void) +{ + virRegisterDriver(&testDriver); +} + + +int testOpen(virConnectPtr conn, + const char *name, + int flags) +{ + xmlURIPtr uri; + int i, j; + + if (!name) { + return -1; + } + + uri = xmlParseURI(name); + if (uri == NULL) { + if (!(flags & VIR_DRV_OPEN_QUIET)) + testError(conn, NULL, VIR_ERR_NO_SUPPORT, name); + return(-1); + } + + if (!uri->scheme || + strcmp(uri->scheme, "test") || + !uri->path || + strcmp(uri->path, "/default")) { + xmlFreeURI(uri); + return -1; + } + + + xmlFreeURI(uri); + + if (node == NULL) { + node = calloc(1, sizeof(testNode)); + if (!node) { + testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot allocate memory"); + return -1; + } + } + + for (i = 0 ; i < MAX_CONNECTIONS ; i++) { + if (!node->connections[i].active) { + struct timeval tv; + + if (gettimeofday(&tv, NULL) < 0) { + testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday"); + return -1; + } + + conn->handle = i; + node->connections[i].active = 1; + + node->connections[i].numDomains = 1; + node->connections[i].domains[0].active = 1; + strcpy(node->connections[i].domains[0].name, "Domain-0"); + for (j = 0 ; j < 16 ; j++) { + node->connections[i].domains[0].uuid[j] = (j * 75)%255; + } + node->connections[i].domains[0].info.maxMem = 8192 * 1024; + node->connections[i].domains[0].info.memory = 2048 * 1024; + node->connections[i].domains[0].info.state = VIR_DOMAIN_RUNNING; + node->connections[i].domains[0].info.nrVirtCpu = 2; + node->connections[i].domains[0].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); + return 0; + } + } + + + testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "too make connections"); + return -1; +} + +int testClose(virConnectPtr conn) +{ + testCon *con = &node->connections[conn->handle]; + con->active = 0; + conn->handle = -1; + memset(con, 0, sizeof(testCon)); + return 0; +} + +int testGetVersion(virConnectPtr conn, + unsigned long *hvVer) +{ + *hvVer = 1; + return 0; +} + +int testNodeGetInfo(virConnectPtr conn, + virNodeInfoPtr info) +{ + memcpy(info, &nodeInfo, sizeof(nodeInfo)); + return 0; +} + +int testNumOfDomains(virConnectPtr conn) +{ + testCon *con = &node->connections[conn->handle]; + return con->numDomains; +} + +virDomainPtr testLookupDomainByID(virConnectPtr conn, + int id) +{ + testCon *con = &node->connections[conn->handle]; + virDomainPtr dom; + if (!con->domains[id].active) { + return NULL; + } + dom = virGetDomain(conn, con->domains[id].name, con->domains[id].uuid); + if (dom == NULL) { + testError(conn, NULL, VIR_ERR_NO_MEMORY, "Allocating domain"); + return(NULL); + } + dom->handle = id; + return dom; +} + +virDomainPtr testLookupDomainByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + testCon *con = &node->connections[conn->handle]; + virDomainPtr dom = NULL; + int i, id = -1; + for (i = 0 ; i < MAX_DOMAINS ; i++) { + if (con->domains[i].active && + memcmp(uuid, con->domains[i].uuid, 16) == 0) { + id = i; + break; + } + } + if (id >= 0) { + dom = virGetDomain(conn, con->domains[id].name, con->domains[id].uuid); + if (dom == NULL) { + testError(conn, NULL, VIR_ERR_NO_MEMORY, "Allocating domain"); + return(NULL); + } + dom->handle = id; + } + return dom; +} + +virDomainPtr testLookupDomainByName(virConnectPtr conn, + const char *name) +{ + testCon *con = &node->connections[conn->handle]; + virDomainPtr dom = NULL; + int i, id = -1; + for (i = 0 ; i < MAX_DOMAINS ; i++) { + if (con->domains[i].active && + strcmp(name, con->domains[i].name) == 0) { + id = i; + break; + } + } + if (id >= 0) { + dom = virGetDomain(conn, con->domains[id].name, con->domains[id].uuid); + if (dom == NULL) { + testError(conn, NULL, VIR_ERR_NO_MEMORY, "Allocating domain"); + return(NULL); + } + dom->handle = id; + } + return dom; +} + +int testListDomains (virConnectPtr conn, + int *ids, + int maxids) +{ + testCon *con = &node->connections[conn->handle]; + int n, i; + + for (i = 0, n = 0 ; i < MAX_DOMAINS && n < maxids ; i++) { + if (con->domains[i].active) { + ids[n++] = i; + } + } + return n; +} + +int testDestroyDomain (virDomainPtr domain) +{ + testCon *con = &node->connections[domain->conn->handle]; + con->domains[domain->handle].active = 0; + return 0; +} + +int testResumeDomain (virDomainPtr domain) +{ + testCon *con = &node->connections[domain->conn->handle]; + con->domains[domain->handle].info.state = VIR_DOMAIN_RUNNING; + return 0; +} + +int testPauseDomain (virDomainPtr domain) +{ + testCon *con = &node->connections[domain->conn->handle]; + con->domains[domain->handle].info.state = VIR_DOMAIN_PAUSED; + return 0; +} + +int testGetDomainInfo (virDomainPtr domain, + virDomainInfoPtr info) +{ + testCon *con = &node->connections[domain->conn->handle]; + struct timeval tv; + if (gettimeofday(&tv, NULL) < 0) { + testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot get timeofday"); + return -1; + } + + con->domains[domain->handle].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); + memcpy(info, &con->domains[domain->handle].info, sizeof(virDomainInfo)); + return 0; +} + +int testSetMaxMemory (virDomainPtr domain, + unsigned long memory) +{ + testCon *con = &node->connections[domain->conn->handle]; + con->domains[domain->handle].info.maxMem = memory; + return 0; +} diff --git a/src/test.h b/src/test.h new file mode 100644 index 0000000000..9281e27a25 --- /dev/null +++ b/src/test.h @@ -0,0 +1,52 @@ +/* + * test.h: A "mock" hypervisor for use by application unit tests + * + * Copyright (C) 2006 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Berrange + */ + +#ifndef __VIR_TEST_SIMPLE_INTERNAL_H__ +#define __VIR_TEST_SIMPLE_INTERNAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + void testRegister(void); + int testOpen(virConnectPtr conn, + const char *name, + int flags); + int testClose (virConnectPtr conn); + int testGetVersion(virConnectPtr conn, + unsigned long *hvVer); + int testNodeGetInfo(virConnectPtr conn, + virNodeInfoPtr info); + int testNumOfDomains(virConnectPtr conn); + int testListDomains(virConnectPtr conn, + int *ids, + int maxids); + virDomainPtr testLookupDomainByID(virConnectPtr conn, + int id); + virDomainPtr testLookupDomainByUUID(virConnectPtr conn, + const unsigned char *uuid); + virDomainPtr testLookupDomainByName(virConnectPtr conn, + const char *name); + int testDestroyDomain(virDomainPtr domain); + int testResumeDomain(virDomainPtr domain); + int testPauseDomain(virDomainPtr domain); + int testGetDomainInfo(virDomainPtr domain, + virDomainInfoPtr info); + int testGetDomainID(virDomainPtr domain); + const char*testGetDomainName(virDomainPtr domain); + int testSetMaxMemory(virDomainPtr domain, + unsigned long memory); + +#ifdef __cplusplus +} +#endif +#endif /* __VIR_TEST_INTERNAL_H__ */