test.c 42.4 KB
Newer Older
1 2 3
/*
 * test.c: A "mock" hypervisor for use by application unit tests
 *
4 5
 * Copyright (C) 2006-2007 Red Hat, Inc.
 * Copyright (C) 2006 Daniel P. Berrange
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
20 21 22 23
 *
 * Daniel Berrange <berrange@redhat.com>
 */

24
#ifdef WITH_TEST
25 26 27
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
28 29 30
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
31
#include <libxml/uri.h>
32 33
#include <fcntl.h>
#include <unistd.h>
34 35 36

#include "internal.h"
#include "test.h"
37
#include "xml.h"
38

39 40 41 42 43 44 45 46
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);
47
char *testGetCapabilities (virConnectPtr conn);
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
int testNumOfDomains(virConnectPtr conn);
int testListDomains(virConnectPtr conn,
                    int *ids,
                    int maxids);
char *testGetOSType(virDomainPtr dom);
virDomainPtr
testDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
                      unsigned int flags ATTRIBUTE_UNUSED);
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 testShutdownDomain (virDomainPtr domain);
int testRebootDomain (virDomainPtr domain,
                      virDomainRestart action);
int testGetDomainInfo(virDomainPtr domain,
                      virDomainInfoPtr info);
unsigned long testGetMaxMemory(virDomainPtr domain);
int testSetMaxMemory(virDomainPtr domain,
                     unsigned long memory);
int testSetMemory(virDomainPtr domain,
                  unsigned long memory);
int testSetVcpus(virDomainPtr domain,
                 unsigned int nrCpus);
char * testDomainDumpXML(virDomainPtr domain, int flags);

int testNumOfDefinedDomains(virConnectPtr conn);
int testListDefinedDomains(virConnectPtr conn,
81
                           char **const names,
82 83 84 85 86 87 88 89 90
                           int maxnames);

virDomainPtr testDomainDefineXML(virConnectPtr conn,
                                 const char *xml);

int testDomainCreate(virDomainPtr dom);

int testDomainUndefine(virDomainPtr dom);

91
static virDriver testDriver = {
92 93 94 95 96 97 98
    VIR_DRV_TEST,
    "Test",
    LIBVIR_VERSION_NUMBER,
    testOpen, /* open */
    testClose, /* close */
    NULL, /* type */
    testGetVersion, /* version */
99
    NULL, /* getMaxVcpus */
100
    testNodeGetInfo, /* nodeGetInfo */
101
    testGetCapabilities, /* getCapabilities */
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    testListDomains, /* listDomains */
    testNumOfDomains, /* numOfDomains */
    testDomainCreateLinux, /* domainCreateLinux */
    testLookupDomainByID, /* domainLookupByID */
    testLookupDomainByUUID, /* domainLookupByUUID */
    testLookupDomainByName, /* domainLookupByName */
    testPauseDomain, /* domainSuspend */
    testResumeDomain, /* domainResume */
    testShutdownDomain, /* domainShutdown */
    testRebootDomain, /* domainReboot */
    testDestroyDomain, /* domainDestroy */
    testGetOSType, /* domainGetOSType */
    testGetMaxMemory, /* domainGetMaxMemory */
    testSetMaxMemory, /* domainSetMaxMemory */
    testSetMemory, /* domainSetMemory */
    testGetDomainInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL, /* domainRestore */
    NULL, /* domainCoreDump */
    testSetVcpus, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
124
    NULL, /* domainGetMaxVcpus */
125 126 127 128 129 130 131 132
    testDomainDumpXML, /* domainDumpXML */
    testListDefinedDomains, /* listDefinedDomains */
    testNumOfDefinedDomains, /* numOfDefinedDomains */
    testDomainCreate, /* domainCreate */
    testDomainDefineXML, /* domainDefineXML */
    testDomainUndefine, /* domainUndefine */
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
133 134
    NULL, /* domainGetAutostart */
    NULL, /* domainSetAutostart */
135 136
};

137 138 139 140 141 142
/* Per-connection private data. */
struct _testPrivate {
    int handle;
};
typedef struct _testPrivate *testPrivatePtr;

143
typedef struct _testDev {
144 145
    char name[20];
    virDeviceMode mode;
146 147 148 149 150
} testDev;

#define MAX_DEVICES 10

typedef struct _testDom {
151
    int active;
152
    int id;
153
    char name[20];
154
    unsigned char uuid[VIR_UUID_BUFLEN];
155 156 157 158 159 160 161 162 163
    virDomainKernel kernel;
    virDomainInfo info;
    unsigned int maxVCPUs;
    virDomainRestart onRestart; /* What to do at end of current shutdown procedure */
    virDomainRestart onReboot;
    virDomainRestart onPoweroff;
    virDomainRestart onCrash;
    int numDevices;
    testDev devices[MAX_DEVICES];
164 165 166 167 168
} testDom;

#define MAX_DOMAINS 20

typedef struct _testCon {
169 170 171 172
    int active;
    virNodeInfo nodeInfo;
    int numDomains;
    testDom domains[MAX_DOMAINS];
173 174 175 176 177
} testCon;

#define MAX_CONNECTIONS 5

typedef struct _testNode {
178 179
    int numConnections;
    testCon connections[MAX_CONNECTIONS];
180 181 182 183 184 185 186 187
} 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;
188
static int nextDomID = 1;
189

190 191 192
#define TEST_MODEL "i686"
#define TEST_MODEL_WORDSIZE "32"

193
static const virNodeInfo defaultNodeInfo = {
194
    TEST_MODEL,
195 196 197 198 199 200 201
    1024*1024*3, /* 3 GB */
    16,
    1400,
    2,
    2,
    2,
    2,
202 203 204 205
};

static void
testError(virConnectPtr con,
206 207 208
          virDomainPtr dom,
          virErrorNumber error,
          const char *info)
209
{
210
    const char *errmsg;
211

212 213
    if (error == VIR_ERR_OK)
        return;
214

215
    errmsg = __virErrorMsg(error, info);
216
    __virRaiseError(con, dom, NULL, VIR_FROM_TEST, error, VIR_ERR_ERROR,
217
                    errmsg, info, NULL, 0, 0, errmsg, info, 0);
218 219
}

220
static int testRestartStringToFlag(const char *str) {
221 222 223 224 225 226 227 228 229 230 231
    if (!strcmp(str, "restart")) {
        return VIR_DOMAIN_RESTART;
    } else if (!strcmp(str, "destroy")) {
        return VIR_DOMAIN_DESTROY;
    } else if (!strcmp(str, "preserve")) {
        return VIR_DOMAIN_PRESERVE;
    } else if (!strcmp(str, "rename-restart")) {
        return VIR_DOMAIN_RENAME_RESTART;
    } else {
        return (0);
    }
232 233 234
}

static const char *testRestartFlagToString(int flag) {
235 236 237 238 239 240 241 242 243 244 245
    switch (flag) {
    case VIR_DOMAIN_RESTART:
        return "restart";
    case VIR_DOMAIN_DESTROY:
        return "destroy";
    case VIR_DOMAIN_PRESERVE:
        return "preserve";
    case VIR_DOMAIN_RENAME_RESTART:
        return "rename-restart";
    }
    return (NULL);
246
}
247 248 249 250 251 252

/**
 * testRegister:
 *
 * Registers the test driver
 */
253 254
int
testRegister(void)
255
{
256
    return virRegisterDriver(&testDriver);
257 258
}

259
static int testLoadDomain(virConnectPtr conn,
260 261 262 263 264
                          int domid,
                          xmlDocPtr xml) {
    xmlNodePtr root = NULL;
    xmlXPathContextPtr ctxt = NULL;
    char *name = NULL;
265
    unsigned char rawuuid[VIR_UUID_BUFLEN];
266 267 268 269 270 271
    char *dst_uuid;
    testCon *con;
    struct timeval tv;
    unsigned long memory = 0;
    unsigned long maxMem = 0;
    int nrVirtCpu;
272 273 274
    char *str;
    int handle = -1, i, ret;
    long l;
275 276 277
    virDomainRestart onReboot = VIR_DOMAIN_RESTART;
    virDomainRestart onPoweroff = VIR_DOMAIN_DESTROY;
    virDomainRestart onCrash = VIR_DOMAIN_RENAME_RESTART;
278
    testPrivatePtr priv;
279 280 281 282

    if (gettimeofday(&tv, NULL) < 0) {
        testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"));
        return (-1);
283 284
    }

285 286 287 288
    root = xmlDocGetRootElement(xml);
    if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
        testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain"));
        goto error;
289
    }
290 291 292 293 294 295 296

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, _("creating xpath context"));
        goto error;
    }

297 298
    name = virXPathString("string(/domain/name[1])", ctxt);
    if (name == NULL) {
299 300 301
        testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, _("domain name"));
        goto error;
    }
302

303 304
    str = virXPathString("string(/domain/uuid[1])", ctxt);
    if (str == NULL) {
305 306 307 308
        testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain uuid"));
        goto error;
    }
    dst_uuid = (char *) &rawuuid[0];
309
    if (!(virParseUUID((char **)&dst_uuid, str))) {
310 311
        testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain uuid"));
        goto error;
312
    }
313
    free(str);
314

315 316 317

    ret = virXPathLong("string(/domain/memory[1])", ctxt, &l);
    if (ret != 0) {
318 319
        testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain memory"));
        goto error;
320
    }
321
    maxMem = l;
322

323 324
    ret = virXPathLong("string(/domain/currentMemory[1])", ctxt, &l);
    if (ret == -1) {
325
        memory = maxMem;
326 327 328
    } else if (ret == -2) {
	testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain current memory"));
	goto error;
329
    } else {
330
        memory = l;
331 332
    }

333 334
    ret = virXPathLong("string(/domain/vcpu[1])", ctxt, &l);
    if (ret == -1) {
335
        nrVirtCpu = 1;
336 337 338
    } else if (ret == -2) {
	testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain vcpus"));
	goto error;
339
    } else {
340
        nrVirtCpu = l;
341 342
    }

343 344 345
    str = virXPathString("string(/domain/on_reboot[1])", ctxt);
    if (str != NULL) {
        if (!(onReboot = testRestartStringToFlag(str))) {
346
            testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain reboot behaviour"));
347
	    free(str);
348 349
            goto error;
        }
350
	free(str);
351 352
    }

353 354 355
    str = virXPathString("string(/domain/on_poweroff[1])", ctxt);
    if (str != NULL) {
        if (!(onReboot = testRestartStringToFlag(str))) {
356
            testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain poweroff behaviour"));
357
	    free(str);
358 359
            goto error;
        }
360
	free(str);
361 362
    }

363 364 365
    str = virXPathString("string(/domain/on_crash[1])", ctxt);
    if (str != NULL) {
        if (!(onReboot = testRestartStringToFlag(str))) {
366
            testError(conn, NULL, VIR_ERR_XML_ERROR, _("domain crash behaviour"));
367
	    free(str);
368 369
            goto error;
        }
370
	free(str);
371
    }
372

373 374
    priv = (testPrivatePtr) conn->privateData;
    con = &node->connections[priv->handle];
375

376 377 378 379 380 381 382 383 384 385
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (!con->domains[i].active) {
            handle = i;
            break;
        }
    }
    if (handle < 0)
        return (-1);

    con->domains[handle].active = 1;
386
    con->domains[handle].id = domid;
387
    strncpy(con->domains[handle].name, name, sizeof(con->domains[handle].name));
388
    free(name);
389 390 391 392 393
    name = NULL;

    if (memory > maxMem)
        memory = maxMem;

394
    memmove(con->domains[handle].uuid, rawuuid, VIR_UUID_BUFLEN);
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
    con->domains[handle].info.maxMem = maxMem;
    con->domains[handle].info.memory = memory;
    con->domains[handle].info.state = domid < 0 ? VIR_DOMAIN_SHUTOFF : VIR_DOMAIN_RUNNING;
    con->domains[handle].info.nrVirtCpu = nrVirtCpu;
    con->domains[handle].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
    con->domains[handle].maxVCPUs = nrVirtCpu;

    con->domains[handle].onReboot = onReboot;
    con->domains[handle].onPoweroff = onPoweroff;
    con->domains[handle].onCrash = onCrash;

    return (0);

 error:
    if (name)
        free(name);
    return (-1);
412 413 414
}

static int testLoadDomainFromDoc(virConnectPtr conn,
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
                                 int domid,
                                 const char *doc) {
    int ret;
    xmlDocPtr xml;
    if (!(xml = xmlReadDoc(BAD_CAST doc, "domain.xml", NULL,
                           XML_PARSE_NOENT | XML_PARSE_NONET |
                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
        return (-1);
    }

    ret = testLoadDomain(conn, domid, xml);

    xmlFreeDoc(xml);

    return (ret);
431 432 433
}

static int testLoadDomainFromFile(virConnectPtr conn,
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
                                  int domid,
                                  const char *file) {
    int ret, fd;
    xmlDocPtr xml;

    if ((fd = open(file, O_RDONLY)) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("load domain definition file"));
        return (-1);
    }

    if (!(xml = xmlReadFd(fd, file, NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
        close(fd);
        return (-1);
    }
451 452
    close(fd);

453
    ret = testLoadDomain(conn, domid, xml);
454

455
    xmlFreeDoc(xml);
456

457
    return (ret);
458 459 460 461
}


static int testOpenDefault(virConnectPtr conn,
462 463 464
                           int connid) {
    int u;
    struct timeval tv;
465
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
466 467 468

    if (gettimeofday(&tv, NULL) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"));
469
        return VIR_DRV_OPEN_ERROR;
470 471
    }

472
    priv->handle = connid;
473 474 475 476 477
    node->connections[connid].active = 1;
    memmove(&node->connections[connid].nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));

    node->connections[connid].numDomains = 1;
    node->connections[connid].domains[0].active = 1;
478
    node->connections[connid].domains[0].id = nextDomID++;
479 480 481 482
    node->connections[connid].domains[0].onReboot = VIR_DOMAIN_RESTART;
    node->connections[connid].domains[0].onCrash = VIR_DOMAIN_RESTART;
    node->connections[connid].domains[0].onPoweroff = VIR_DOMAIN_DESTROY;
    strcpy(node->connections[connid].domains[0].name, "test");
483
    for (u = 0 ; u < VIR_UUID_BUFLEN ; u++) {
484 485 486 487 488 489 490 491
        node->connections[connid].domains[0].uuid[u] = (u * 75)%255;
    }
    node->connections[connid].domains[0].info.maxMem = 8192 * 1024;
    node->connections[connid].domains[0].info.memory = 2048 * 1024;
    node->connections[connid].domains[0].info.state = VIR_DOMAIN_RUNNING;
    node->connections[connid].domains[0].info.nrVirtCpu = 2;
    node->connections[connid].domains[0].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
    return (0);
492 493 494 495
}


static char *testBuildFilename(const char *relativeTo,
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
                               const char *filename) {
    char *offset;
    int baseLen;
    if (!filename || filename[0] == '\0')
        return (NULL);
    if (filename[0] == '/')
        return strdup(filename);

    offset = rindex(relativeTo, '/');
    if ((baseLen = (offset-relativeTo+1))) {
        char *absFile = malloc(baseLen + strlen(filename) + 1);
        strncpy(absFile, relativeTo, baseLen);
        absFile[baseLen] = '\0';
        strcat(absFile, filename);
        return absFile;
    } else {
        return strdup(filename);
    }
514 515 516
}

static int testOpenFromFile(virConnectPtr conn,
517 518
                            int connid,
                            const char *file) {
519 520 521
    int fd, i, ret;
    long l;
    char *str;
522 523
    xmlDocPtr xml;
    xmlNodePtr root = NULL;
524
    xmlNodePtr *domains;
525 526
    xmlXPathContextPtr ctxt = NULL;
    virNodeInfoPtr nodeInfo;
527
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
528 529 530

    if ((fd = open(file, O_RDONLY)) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("loading host definition file"));
531
        return VIR_DRV_OPEN_ERROR;
532 533
    }

534 535 536 537 538
    if (!(xml = xmlReadFd(fd, file, NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("host"));
        goto error;
539
    }
540 541
    close(fd);
    fd = -1;
542

543 544 545 546
    root = xmlDocGetRootElement(xml);
    if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "node"))) {
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node"));
        goto error;
547 548
    }

549 550 551 552
    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("creating xpath context"));
        goto error;
553
    }
554

555
    priv->handle = connid;
556 557 558 559 560
    node->connections[connid].active = 1;
    node->connections[connid].numDomains = 0;
    memmove(&node->connections[connid].nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));

    nodeInfo = &node->connections[connid].nodeInfo;
561 562 563 564
    ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->nodes = l;
    } else if (ret == -2) {
565
	testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu numa nodes"));
566
	goto error;
567
    }
568

569 570 571 572
    ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->sockets = l;
    } else if (ret == -2) {
573
	testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu sockets"));
574
	goto error;
575
    }
576

577 578 579 580
    ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->cores = l;
    } else if (ret == -2) {
581
	testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu cores"));
582
	goto error;
583 584
    }

585 586 587 588
    ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->threads = l;
    } else if (ret == -2) {
589
	testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu threads"));
590
	goto error;
591
    }
592

593
    nodeInfo->cpus = nodeInfo->cores * nodeInfo->threads * nodeInfo->sockets * nodeInfo->nodes;
594 595 596 597 598 599
    ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
    if (ret == 0) {
        if (l < nodeInfo->cpus) {
	    nodeInfo->cpus = l;
	}
    } else if (ret == -2) {
600
	testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node active cpu"));
601 602 603 604 605 606
	goto error;
    }
    ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->mhz = l;
    } else if (ret == -2) {
607
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node cpu mhz"));
608 609 610 611 612 613
	goto error;
    }

    str = virXPathString("string(/node/cpu/model[1])", ctxt);
    if (str != NULL) {
        strncpy(nodeInfo->model, str, sizeof(nodeInfo->model)-1);
614
        nodeInfo->model[sizeof(nodeInfo->model)-1] = '\0';
615
        free(str);
616 617
    }

618 619 620 621
    ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
    if (ret == 0) {
        nodeInfo->memory = l;
    } else if (ret == -2) {
622
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node memory"));
623
	goto error;
624
    }
625

626 627
    ret = virXPathNodeSet("/node/domain", ctxt, &domains);
    if (ret < 0) {
628 629
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("node domain list"));
        goto error;
630
    }
631

632 633
    for (i = 0 ; i < ret ; i++) {
        xmlChar *domFile = xmlGetProp(domains[i], BAD_CAST "file");
634 635 636 637 638 639 640 641 642 643 644 645 646
        char *absFile = testBuildFilename(file, (const char *)domFile);
        int domid = nextDomID++;
        free(domFile);
        if (!absFile) {
            testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("resolving domain filename"));
            goto error;
        }
        if (testLoadDomainFromFile(conn, domid, absFile) != 0) {
            free(absFile);
            goto error;
        }
        free(absFile);
        node->connections[connid].numDomains++;
647
    }
648 649
    if (domains != NULL)
        free(domains);
650

651
    xmlFreeDoc(xml);
652

653
    return (0);
654 655

 error:
656 657 658 659 660 661
    if (node->connections[connid].active) {
        for (i = 0 ; i <node->connections[connid].numDomains ; i++) {
            node->connections[connid].domains[i].active = 0;
        }
        node->connections[connid].numDomains = 0;
        node->connections[connid].active = 0;
662
    }
663 664 665 666
    if (xml)
        xmlFreeDoc(xml);
    if (fd != -1)
        close(fd);
667
    return VIR_DRV_OPEN_ERROR;
668 669 670
}

static int getNextConnection(void) {
671 672 673 674 675 676 677 678 679 680 681 682 683 684
    int i;
    if (node == NULL) {
        node = calloc(1, sizeof(testNode));
        nextDomID = 1;
        if (!node) {
            testError(NULL, NULL, VIR_ERR_NO_MEMORY, _("allocating node"));
            return (-1);
        }
    }

    for (i = 0 ; i < MAX_CONNECTIONS ; i++) {
        if (!node->connections[i].active) {
            return (i);
        }
685
    }
686 687
    return (-1);
}
688

689 690 691
static int getDomainIndex(virDomainPtr domain) {
    int i;
    testCon *con;
692 693 694
    testPrivatePtr priv = (testPrivatePtr) domain->conn->privateData;

    con = &node->connections[priv->handle];
695
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
696 697
        if (domain->id >= 0) {
            if (domain->id == con->domains[i].id)
698 699 700 701 702
                return (i);
        } else {
            if (!strcmp(domain->name, con->domains[i].name))
                return (i);
        }
703
    }
704
    return (-1);
705
}
706 707 708

int testOpen(virConnectPtr conn,
             const char *name,
709
             int flags ATTRIBUTE_UNUSED)
710
{
711 712
    xmlURIPtr uri;
    int ret, connid;
713
    testPrivatePtr priv;
714

715 716
    if (!name)
        return VIR_DRV_OPEN_DECLINED;
717

718 719
    uri = xmlParseURI(name);
    if (uri == NULL) {
720
        testError(NULL, NULL, VIR_ERR_NO_SUPPORT, name);
721
        return VIR_DRV_OPEN_DECLINED;
722
    }
723

724
    if (!uri->scheme || strcmp(uri->scheme, "test") != 0) {
725
        xmlFreeURI(uri);
726
        return VIR_DRV_OPEN_DECLINED;
727
    }
728

729 730 731 732
    /* From this point on, the connection is for us. */
    if (!uri->path
        || uri->path[0] == '\0'
        || (uri->path[0] == '/' && uri->path[1] == '\0')) {
733
        testError (NULL, NULL, VIR_ERR_INVALID_ARG,
734 735 736
                   _("testOpen: supply a path or use test:///default"));
        return VIR_DRV_OPEN_ERROR;
    }
737

738 739
    if ((connid = getNextConnection()) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("too many connections"));
740
        return VIR_DRV_OPEN_ERROR;
741 742
    }

743 744 745
    /* Allocate per-connection private data. */
    priv = conn->privateData = malloc (sizeof (struct _testPrivate));
    if (!priv) {
746
        testError(NULL, NULL, VIR_ERR_NO_MEMORY, _("allocating private data"));
747 748 749 750
        return VIR_DRV_OPEN_ERROR;
    }
    priv->handle = -1;

751
    if (strcmp(uri->path, "/default") == 0) {
752 753 754 755 756 757 758 759 760 761
        ret = testOpenDefault(conn,
                              connid);
    } else {
        ret = testOpenFromFile(conn,
                               connid,
                               uri->path);
    }

    xmlFreeURI(uri);

762 763
    if (ret < 0) free (conn->privateData);

764
    return (ret);
765 766 767 768
}

int testClose(virConnectPtr conn)
{
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    testPrivatePtr priv;

    if (!conn) {
        testError (NULL, NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
        return -1;
    }

    priv = (testPrivatePtr) conn->privateData;
    if (!priv) {
        testError (NULL, NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
        return -1;
    }

    if (priv->handle >= 0) {
        testCon *con = &node->connections[priv->handle];
        con->active = 0;
        memset (con, 0, sizeof *con); // RWMJ - why?
    }

    free (priv);
    return 0;
790 791
}

792
int testGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
793 794
                   unsigned long *hvVer)
{
795 796
    *hvVer = 2;
    return (0);
797 798
}

799
int testNodeGetInfo(virConnectPtr conn,
800 801
                    virNodeInfoPtr info)
{
802 803
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
804 805
    memcpy(info, &con->nodeInfo, sizeof(virNodeInfo));
    return (0);
806 807
}

808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
char *
testGetCapabilities (virConnectPtr conn)
{
    static char caps[] = "\
<capabilities>\n\
  <host>\n\
    <cpu>\n\
      <arch>" TEST_MODEL "</arch>\n\
      <features>\n\
        <pae/>\n\
        <nonpae/>\n\
      </features>\n\
    </cpu>\n\
  </host>\n\
\n\
  <guest>\n\
    <os_type>linux</os_type>\n\
    <arch name=\"" TEST_MODEL "\">\n\
      <wordsize>" TEST_MODEL_WORDSIZE "</wordsize>\n\
      <domain type=\"test\"/>\n\
    </arch>\n\
    <features>\n\
      <pae/>\n\
      <nonpae/>\n\
    </features>\n\
  </guest>\n\
</capabilities>\n\
";

    char *caps_copy = strdup (caps);
    if (!caps_copy) {
        testError(conn, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__);
        return NULL;
    }
    return caps_copy;
}

845 846
int testNumOfDomains(virConnectPtr conn)
{
847
    int numActive = 0, i;
848 849
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
850 851 852 853 854 855 856
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (!con->domains[i].active ||
            con->domains[i].info.state == VIR_DOMAIN_SHUTOFF)
            continue;
        numActive++;
    }
    return (numActive);
857 858
}

859 860
virDomainPtr
testDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
861
                      unsigned int flags ATTRIBUTE_UNUSED)
862
{
863 864 865
    testCon *con;
    int domid, handle = -1, i;
    virDomainPtr dom;
866
    testPrivatePtr priv;
867

868 869 870 871 872 873 874 875 876 877 878 879
    if (!VIR_IS_CONNECT(conn)) {
        testError(conn, NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
        return (NULL);
    }
    if (xmlDesc == NULL) {
        testError(conn, NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return (NULL);
    }
    if (conn->flags & VIR_CONNECT_RO) {
        testError(conn, NULL, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (NULL);
    }
880 881

    priv = (testPrivatePtr) conn->privateData;
882
  
883
    con = &node->connections[priv->handle];
884 885 886 887 888 889 890 891 892 893

    if (con->numDomains == MAX_DOMAINS) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("too many domains"));
        return (NULL);
    }

    domid = nextDomID++;
    if (testLoadDomainFromDoc(conn, domid, xmlDesc) < 0)
        return (NULL);
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
894
        if (con->domains[i].id == domid) {
895 896 897 898 899 900 901 902 903 904 905
            handle = i;
            break;
        }
    }
    dom = virGetDomain(conn, con->domains[handle].name, con->domains[handle].uuid);
    if (dom == NULL) {
        testError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"));
        return (NULL);
    }
    con->numDomains++;
    return (dom);
906 907 908
}


909 910 911
virDomainPtr testLookupDomainByID(virConnectPtr conn,
                                  int id)
{
912 913
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
914 915 916 917 918
    virDomainPtr dom;
    int i, idx = -1;

    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (con->domains[i].active &&
919
            con->domains[i].id == id) {
920 921 922 923 924 925 926 927 928 929 930 931 932 933
            idx = i;
            break;
        }
    }

    if (idx < 0) {
        return(NULL);
    }

    dom = virGetDomain(conn, con->domains[idx].name, con->domains[idx].uuid);
    if (dom == NULL) {
        testError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"));
        return(NULL);
    }
934
    dom->id = id;
935
    return (dom);
936 937 938 939 940
}

virDomainPtr testLookupDomainByUUID(virConnectPtr conn,
                                    const unsigned char *uuid)
{
941 942
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
943 944 945 946
    virDomainPtr dom = NULL;
    int i, idx = -1;
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (con->domains[i].active &&
947
            memcmp(uuid, con->domains[i].uuid, VIR_UUID_BUFLEN) == 0) {
948 949 950
            idx = i;
            break;
        }
951
    }
952 953 954 955 956 957
    if (idx >= 0) {
        dom = virGetDomain(conn, con->domains[idx].name, con->domains[idx].uuid);
        if (dom == NULL) {
            testError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"));
            return(NULL);
        }
958
        dom->id = con->domains[idx].id;
959 960
    }
    return (dom);
961 962 963 964 965
}

virDomainPtr testLookupDomainByName(virConnectPtr conn,
                                    const char *name)
{
966 967
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
968 969 970 971 972 973 974 975
    virDomainPtr dom = NULL;
    int i, idx = -1;
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (con->domains[i].active &&
            strcmp(name, con->domains[i].name) == 0) {
            idx = i;
            break;
        }
976
    }
977 978 979 980 981 982
    if (idx >= 0) {
        dom = virGetDomain(conn, con->domains[idx].name, con->domains[idx].uuid);
        if (dom == NULL) {
            testError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"));
            return(NULL);
        }
983
        dom->id = con->domains[idx].id;
984 985
    }
    return (dom);
986 987 988 989 990 991
}

int testListDomains (virConnectPtr conn,
                     int *ids,
                     int maxids)
{
992 993
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
994 995 996 997 998
    int n, i;

    for (i = 0, n = 0 ; i < MAX_DOMAINS && n < maxids ; i++) {
        if (con->domains[i].active &&
            con->domains[i].info.state != VIR_DOMAIN_SHUTOFF) {
999
            ids[n++] = con->domains[i].id;
1000
        }
1001
    }
1002
    return (n);
1003 1004 1005 1006
}

int testDestroyDomain (virDomainPtr domain)
{
1007 1008
    testCon *con;
    int domidx;
1009 1010
    testPrivatePtr priv;

1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }

1022 1023 1024
    priv = (testPrivatePtr) domain->conn->privateData;

    con = &node->connections[priv->handle];
1025 1026
    con->domains[domidx].active = 0;
    return (0);
1027 1028 1029 1030
}

int testResumeDomain (virDomainPtr domain)
{
1031 1032
    testCon *con;
    int domidx;
1033 1034
    testPrivatePtr priv;

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1045

1046 1047 1048
    priv = (testPrivatePtr) domain->conn->privateData;

    con = &node->connections[priv->handle];
1049 1050
    con->domains[domidx].info.state = VIR_DOMAIN_RUNNING;
    return (0);
1051 1052 1053 1054
}

int testPauseDomain (virDomainPtr domain)
{
1055 1056
    testCon *con;\
    int domidx;
1057 1058
    testPrivatePtr priv;

1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1069

1070 1071 1072
    priv = (testPrivatePtr) domain->conn->privateData;

    con = &node->connections[priv->handle];
1073 1074
    con->domains[domidx].info.state = VIR_DOMAIN_PAUSED;
    return (0);
1075 1076
}

1077 1078 1079 1080 1081 1082
/* We don't do an immediate shutdown. We basically pretend that
   out shutdown sequence takes 'n' seconds to complete. SO, here
   we just set state to shutdown, and subsquent calls to getDomainInfo
   will check to see if shutdown ought to be marked complete. */
int testShutdownDomain (virDomainPtr domain)
{
1083 1084 1085
    testCon *con;
    int domidx;
    struct timeval tv;
1086 1087
    testPrivatePtr priv;

1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1098

1099 1100 1101
    priv = (testPrivatePtr) domain->conn->privateData;

    con = &node->connections[priv->handle];
1102

1103 1104 1105 1106
    if (gettimeofday(&tv, NULL) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"));
        return (-1);
    }
1107

1108
    con->domains[domidx].info.state = VIR_DOMAIN_SHUTOFF;
1109 1110
    domain->id = -1;
    con->domains[domidx].id = -1;
1111 1112

    return (0);
1113 1114 1115 1116 1117
}

/* Similar behaviour as shutdown */
int testRebootDomain (virDomainPtr domain, virDomainRestart action)
{
1118 1119 1120
    testCon *con;
    int domidx;
    struct timeval tv;
1121 1122
    testPrivatePtr priv;

1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1133

1134 1135
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1136

1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
    if (gettimeofday(&tv, NULL) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"));
        return (-1);
    }

    if (!action)
        action = VIR_DOMAIN_RESTART;

    con->domains[domidx].info.state = VIR_DOMAIN_SHUTDOWN;
    switch (action) {
    case VIR_DOMAIN_DESTROY:
        con->domains[domidx].info.state = VIR_DOMAIN_SHUTOFF;
        break;

    case VIR_DOMAIN_RESTART:
        con->domains[domidx].info.state = VIR_DOMAIN_RUNNING;
        break;

    case VIR_DOMAIN_PRESERVE:
        con->domains[domidx].info.state = VIR_DOMAIN_SHUTOFF;
        break;

    case VIR_DOMAIN_RENAME_RESTART:
        con->domains[domidx].info.state = VIR_DOMAIN_RUNNING;
        break;
1162

1163 1164 1165 1166
    default:
        con->domains[domidx].info.state = VIR_DOMAIN_SHUTOFF;
        break;
    }
1167 1168
    domain->id = -1;
    con->domains[domidx].id = -1;
1169

1170
    return (0);
1171 1172
}

1173 1174 1175
int testGetDomainInfo (virDomainPtr domain,
                       virDomainInfoPtr info)
{
1176 1177 1178
    struct timeval tv;
    testCon *con;
    int domidx;
1179 1180
    testPrivatePtr priv;

1181 1182 1183 1184 1185 1186 1187
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }

1188 1189
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203

    if (gettimeofday(&tv, NULL) < 0) {
        testError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"));
        return (-1);
    }

    if (con->domains[domidx].info.state == VIR_DOMAIN_SHUTOFF) {
        con->domains[domidx].info.cpuTime = 0;
        con->domains[domidx].info.memory = 0;
    } else {
        con->domains[domidx].info.cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
    }
    memcpy(info, &con->domains[domidx].info, sizeof(virDomainInfo));
    return (0);
1204 1205
}

1206
char *testGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1207
    return strdup("linux");
1208 1209
}

1210
unsigned long testGetMaxMemory(virDomainPtr domain) {
1211 1212
    testCon *con;
    int domidx;
1213 1214
    testPrivatePtr priv;

1215 1216 1217 1218 1219 1220 1221
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }

1222 1223
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1224
    return con->domains[domidx].info.maxMem;
1225 1226
}

1227 1228
int testSetMaxMemory(virDomainPtr domain,
                     unsigned long memory)
1229
{
1230 1231
    testCon *con;
    int domidx;
1232 1233
    testPrivatePtr priv;

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1244

1245 1246
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1247 1248 1249
    /* XXX validate not over host memory wrt to other domains */
    con->domains[domidx].info.maxMem = memory;
    return (0);
1250 1251
}

1252 1253
int testSetMemory(virDomainPtr domain,
                  unsigned long memory)
1254
{
1255 1256
    testCon *con;
    int domidx;
1257 1258
    testPrivatePtr priv;

1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1269

1270 1271
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1272

1273 1274 1275 1276
    if (memory > con->domains[domidx].info.maxMem) {
        testError(domain->conn, domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return (-1);
    }
1277

1278 1279
    con->domains[domidx].info.memory = memory;
    return (0);
1280 1281 1282
}

int testSetVcpus(virDomainPtr domain,
1283 1284 1285
                 unsigned int nrCpus) {
    testCon *con;
    int domidx;
1286 1287
    testPrivatePtr priv;

1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        testError(domain->conn, domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return (-1);
    }
1298

1299 1300
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1301

1302 1303 1304 1305 1306
    /* We allow more cpus in guest than host */
    if (nrCpus > 32) {
        testError(domain->conn, domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return (-1);
    }
1307

1308 1309
    con->domains[domidx].info.nrVirtCpu = nrCpus;
    return (0);
1310 1311 1312 1313
}

char * testDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
{
1314 1315 1316 1317 1318
    virBufferPtr buf;
    char *xml;
    unsigned char *uuid;
    testCon *con;
    int domidx;
1319 1320
    testPrivatePtr priv;

1321 1322 1323 1324 1325 1326 1327
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (NULL);
    }

1328 1329
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1330 1331 1332 1333 1334

    if (!(buf = virBufferNew(4000))) {
        return (NULL);
    }

1335
    virBufferVSprintf(buf, "<domain type='test' id='%d'>\n", domain->id);
1336 1337 1338 1339 1340 1341 1342 1343 1344
    virBufferVSprintf(buf, "  <name>%s</name>\n", domain->name);
    uuid = domain->uuid;
    virBufferVSprintf(buf,
                      "  <uuid>%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</uuid>\n",
                      uuid[0], uuid[1], uuid[2], uuid[3],
                      uuid[4], uuid[5], uuid[6], uuid[7],
                      uuid[8], uuid[9], uuid[10], uuid[11],
                      uuid[12], uuid[13], uuid[14], uuid[15]);

1345
    virBufferVSprintf(buf, "  <memory>%lu</memory>\n", con->domains[domidx].info.maxMem);
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
    virBufferVSprintf(buf, "  <vcpu>%d</vcpu>\n", con->domains[domidx].info.nrVirtCpu);
    virBufferVSprintf(buf, "  <on_reboot>%s</on_reboot>\n", testRestartFlagToString(con->domains[domidx].onReboot));
    virBufferVSprintf(buf, "  <on_poweroff>%s</on_poweroff>\n", testRestartFlagToString(con->domains[domidx].onPoweroff));
    virBufferVSprintf(buf, "  <on_crash>%s</on_crash>\n", testRestartFlagToString(con->domains[domidx].onCrash));

    virBufferAdd(buf, "</domain>\n", -1);

    xml = buf->content;
    free(buf);

    return (xml);
1357
}
1358 1359 1360 1361


int testNumOfDefinedDomains(virConnectPtr conn) {
    int numInactive = 0, i;
1362 1363
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
    for (i = 0 ; i < MAX_DOMAINS ; i++) {
        if (!con->domains[i].active ||
            con->domains[i].info.state != VIR_DOMAIN_SHUTOFF)
            continue;
        numInactive++;
    }
    return (numInactive);
}

int testListDefinedDomains(virConnectPtr conn,
1374
                           char **const names,
1375
                           int maxnames) {
1376 1377
    testPrivatePtr priv = (testPrivatePtr) conn->privateData;
    testCon *con = &node->connections[priv->handle];
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
    int n = 0, i;

    for (i = 0, n = 0 ; i < MAX_DOMAINS && n < maxnames ; i++) {
        if (con->domains[i].active &&
            con->domains[i].info.state == VIR_DOMAIN_SHUTOFF) {
            names[n++] = strdup(con->domains[i].name);
        }
    }
    return (n);
}

virDomainPtr testDomainDefineXML(virConnectPtr conn,
                                 const char *doc) {
    int ret;
    xmlDocPtr xml;
    int domid;

    if (!(xml = xmlReadDoc(BAD_CAST doc, "domain.xml", NULL,
                           XML_PARSE_NOENT | XML_PARSE_NONET |
                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
        testError(NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
        return (NULL);
    }

    domid = nextDomID++;
    ret = testLoadDomain(conn, domid, xml);

    xmlFreeDoc(xml);

    if (ret < 0)
        return (NULL);

    return testLookupDomainByID(conn, domid);
}

int testDomainCreate(virDomainPtr domain) {
    testCon *con;
    int domidx;
1416 1417
    testPrivatePtr priv;

1418 1419 1420 1421 1422 1423 1424
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }

1425 1426
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1427 1428 1429 1430 1431 1432 1433

    if (con->domains[domidx].info.state != VIR_DOMAIN_SHUTOFF) {
        testError(domain->conn, domain, VIR_ERR_INTERNAL_ERROR,
                  _("Domain is already running"));
        return (-1);
    }

1434
    domain->id = con->domains[domidx].id = nextDomID++;
1435 1436 1437 1438 1439 1440 1441 1442
    con->domains[domidx].info.state = VIR_DOMAIN_RUNNING;

    return (0);
}

int testDomainUndefine(virDomainPtr domain) {
    testCon *con;
    int domidx;
1443 1444
    testPrivatePtr priv;

1445 1446 1447 1448 1449 1450 1451
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        ((domidx = getDomainIndex(domain)) < 0)) {
        testError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
                  __FUNCTION__);
        return (-1);
    }

1452 1453
    priv = (testPrivatePtr) domain->conn->privateData;
    con = &node->connections[priv->handle];
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464

    if (con->domains[domidx].info.state != VIR_DOMAIN_SHUTOFF) {
        testError(domain->conn, domain, VIR_ERR_INTERNAL_ERROR,
                  _("Domain is still running"));
        return (-1);
    }

    con->domains[domidx].active = 0;

    return (0);
}
1465
#endif /* WITH_TEST */
1466

1467 1468 1469 1470 1471
/*
 * vim: set tabstop=4:
 * vim: set shiftwidth=4:
 * vim: set expandtab:
 */
1472 1473 1474 1475 1476 1477 1478 1479
/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */