qemuhotplugtest.c 27.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Copyright (C) 2011-2013 Red Hat, Inc.
 *
 * 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, see
 * <http://www.gnu.org/licenses/>.
 *
 */

#include <config.h>

22
#include "qemu/qemu_alias.h"
23 24
#include "qemu/qemu_conf.h"
#include "qemu/qemu_hotplug.h"
25
#define LIBVIRT_QEMU_HOTPLUGPRIV_H_ALLOW
26
#include "qemu/qemu_hotplugpriv.h"
27 28 29
#include "qemumonitortestutils.h"
#include "testutils.h"
#include "testutilsqemu.h"
30
#include "testutilsqemuschema.h"
31 32 33 34 35 36 37 38 39
#include "virerror.h"
#include "virstring.h"
#include "virthread.h"
#include "virfile.h"

#define VIR_FROM_THIS VIR_FROM_NONE

static virQEMUDriver driver;

40 41 42 43 44 45
enum {
    ATTACH,
    DETACH,
    UPDATE
};

46 47
#define QEMU_HOTPLUG_TEST_DOMAIN_ID 7

48 49 50 51 52
struct qemuHotplugTestData {
    const char *domain_filename;
    const char *device_filename;
    bool fail;
    const char *const *mon;
53 54 55
    int action;
    bool keep;
    virDomainObjPtr vm;
56
    bool deviceDeletedEvent;
57 58 59 60 61
};

static int
qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
                         virDomainObjPtr *vm,
62
                         const char *domxml)
63 64
{
    int ret = -1;
65
    qemuDomainObjPrivatePtr priv = NULL;
66
    const unsigned int parseFlags = 0;
67 68 69 70

    if (!(*vm = virDomainObjNew(xmlopt)))
        goto cleanup;

71 72 73 74 75
    priv = (*vm)->privateData;

    if (!(priv->qemuCaps = virQEMUCapsNew()))
        goto cleanup;

76
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_SCSI);
77
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE);
78
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_CCW);
79 80
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN);
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
81
    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_DISK_WWN);
82

83
    if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0)
P
Pavel Fedin 已提交
84 85 86 87 88
        goto cleanup;

    if (!((*vm)->def = virDomainDefParseString(domxml,
                                               driver.caps,
                                               driver.xmlopt,
89
                                               NULL,
90
                                               parseFlags)))
P
Pavel Fedin 已提交
91 92
        goto cleanup;

93 94
    if (qemuDomainAssignAddresses((*vm)->def, priv->qemuCaps,
                                  &driver, *vm, true) < 0) {
95
        goto cleanup;
96
    }
97 98 99

    if (qemuAssignDeviceAliases((*vm)->def, priv->qemuCaps) < 0)
        goto cleanup;
100

101 102
    (*vm)->def->id = QEMU_HOTPLUG_TEST_DOMAIN_ID;

103 104 105
    if (qemuDomainSetPrivatePaths(&driver, *vm) < 0)
        goto cleanup;

106
    ret = 0;
107
 cleanup:
108 109 110
    return ret;
}

111 112 113 114 115 116 117
static int
testQemuHotplugAttach(virDomainObjPtr vm,
                      virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
118 119 120 121
    case VIR_DOMAIN_DEVICE_DISK:
        /* conn in only used for storage pool and secrets lookup so as long
         * as we don't use any of them, passing NULL should be safe
         */
122
        ret = qemuDomainAttachDeviceDiskLive(&driver, vm, dev);
123
        break;
124
    case VIR_DOMAIN_DEVICE_CHR:
125
        ret = qemuDomainAttachChrDevice(&driver, vm, dev->data.chr);
126
        break;
127 128 129
    case VIR_DOMAIN_DEVICE_SHMEM:
        ret = qemuDomainAttachShmemDevice(&driver, vm, dev->data.shmem);
        break;
M
Michal Privoznik 已提交
130 131 132
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        ret = qemuDomainAttachWatchdog(&driver, vm, dev->data.watchdog);
        break;
133
    default:
134 135
        VIR_TEST_VERBOSE("device type '%s' cannot be attached\n",
                virDomainDeviceTypeToString(dev->type));
136 137 138 139 140 141 142 143
        break;
    }

    return ret;
}

static int
testQemuHotplugDetach(virDomainObjPtr vm,
144 145
                      virDomainDeviceDefPtr dev,
                      bool async)
146 147 148 149
{
    int ret = -1;

    switch (dev->type) {
150
    case VIR_DOMAIN_DEVICE_DISK:
151
    case VIR_DOMAIN_DEVICE_CHR:
152
    case VIR_DOMAIN_DEVICE_SHMEM:
M
Michal Privoznik 已提交
153
    case VIR_DOMAIN_DEVICE_WATCHDOG:
154
        ret = qemuDomainDetachDeviceLive(vm, dev, &driver, async);
M
Michal Privoznik 已提交
155
        break;
156
    default:
157 158
        VIR_TEST_VERBOSE("device type '%s' cannot be detached\n",
                virDomainDeviceTypeToString(dev->type));
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
        break;
    }

    return ret;
}

static int
testQemuHotplugUpdate(virDomainObjPtr vm,
                      virDomainDeviceDefPtr dev)
{
    int ret = -1;

    /* XXX Ideally, we would call qemuDomainUpdateDeviceLive here.  But that
     * would require us to provide virConnectPtr and virDomainPtr (they're used
     * in case of updating a disk device. So for now, we will proceed with
     * breaking the function into pieces. If we ever learn how to fake those
     * required object, we can replace this code then. */
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(&driver, vm, dev->data.graphics);
        break;
    default:
181 182
        VIR_TEST_VERBOSE("device type '%s' cannot be updated\n",
                virDomainDeviceTypeToString(dev->type));
183 184 185 186 187 188
        break;
    }

    return ret;
}

189 190 191
static int
testQemuHotplugCheckResult(virDomainObjPtr vm,
                           const char *expected,
192
                           const char *expectedFile,
193 194 195 196 197
                           bool fail)
{
    char *actual;
    int ret;

198 199
    actual = virDomainDefFormat(vm->def, driver.caps,
                                VIR_DOMAIN_DEF_FORMAT_SECURE);
200 201
    if (!actual)
        return -1;
202
    vm->def->id = QEMU_HOTPLUG_TEST_DOMAIN_ID;
203 204

    if (STREQ(expected, actual)) {
205 206
        if (fail)
            VIR_TEST_VERBOSE("domain XML should not match the expected result\n");
207 208 209
        ret = 0;
    } else {
        if (!fail)
210 211 212
            virTestDifferenceFull(stderr,
                                  expected, expectedFile,
                                  actual, NULL);
213 214 215 216 217 218 219
        ret = -1;
    }

    VIR_FREE(actual);
    return ret;
}

220 221 222 223 224 225 226
static int
testQemuHotplug(const void *data)
{
    int ret = -1;
    struct qemuHotplugTestData *test = (struct qemuHotplugTestData *) data;
    char *domain_filename = NULL;
    char *device_filename = NULL;
227 228
    char *result_filename = NULL;
    char *domain_xml = NULL;
229
    char *device_xml = NULL;
230
    char *result_xml = NULL;
231 232
    const char *const *tmp;
    bool fail = test->fail;
233
    bool keep = test->keep;
234
    unsigned int device_parse_flags = 0;
235 236 237 238 239 240
    virDomainObjPtr vm = NULL;
    virDomainDeviceDefPtr dev = NULL;
    virCapsPtr caps = NULL;
    qemuMonitorTestPtr test_mon = NULL;
    qemuDomainObjPrivatePtr priv = NULL;

241
    if (virAsprintf(&domain_filename, "%s/qemuhotplugtestdomains/qemuhotplug-%s.xml",
242
                    abs_srcdir, test->domain_filename) < 0 ||
243
        virAsprintf(&device_filename, "%s/qemuhotplugtestdevices/qemuhotplug-%s.xml",
244 245
                    abs_srcdir, test->device_filename) < 0 ||
        virAsprintf(&result_filename,
246
                    "%s/qemuhotplugtestdomains/qemuhotplug-%s+%s.xml",
247 248 249 250
                    abs_srcdir, test->domain_filename,
                    test->device_filename) < 0)
        goto cleanup;

251 252
    if (virTestLoadFile(domain_filename, &domain_xml) < 0 ||
        virTestLoadFile(device_filename, &device_xml) < 0)
253 254
        goto cleanup;

255
    if (test->action == ATTACH &&
256
        virTestLoadFile(result_filename, &result_xml) < 0)
257 258 259 260 261
        goto cleanup;

    if (!(caps = virQEMUDriverGetCapabilities(&driver, false)))
        goto cleanup;

262 263
    if (test->vm) {
        vm = test->vm;
264 265 266 267
        if (!vm->def) {
            VIR_TEST_VERBOSE("test skipped due to failure of dependent test\n");
            goto cleanup;
        }
268
    } else {
269
        if (qemuHotplugCreateObjects(driver.xmlopt, &vm, domain_xml) < 0)
270 271
            goto cleanup;
    }
272

273
    if (test->action == ATTACH)
274
        device_parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
275

276
    if (!(dev = virDomainDeviceDefParse(device_xml, vm->def,
277 278
                                        caps, driver.xmlopt,
                                        device_parse_flags)))
279 280 281 282
        goto cleanup;

    /* Now is the best time to feed the spoofed monitor with predefined
     * replies. */
283
    if (!(test_mon = qemuMonitorTestNew(driver.xmlopt, vm, &driver,
284
                                        NULL, NULL)))
285 286 287 288 289 290 291 292 293 294 295 296 297 298
        goto cleanup;

    tmp = test->mon;
    while (tmp && *tmp) {
        const char *command_name;
        const char *response;

        if (!(command_name = *tmp++) ||
            !(response = *tmp++))
            break;
        if (qemuMonitorTestAddItem(test_mon, command_name, response) < 0)
            goto cleanup;
    }

299
    priv = vm->privateData;
300 301 302 303 304 305 306
    priv->mon = qemuMonitorTestGetMonitor(test_mon);

    /* XXX We need to unlock the monitor here, as
     * qemuDomainObjEnterMonitorInternal (called from qemuDomainChangeGraphics)
     * tries to lock it again */
    virObjectUnlock(priv->mon);

307 308 309
    switch (test->action) {
    case ATTACH:
        ret = testQemuHotplugAttach(vm, dev);
310 311 312 313 314
        if (ret == 0) {
            /* vm->def stolen dev->data.* so we just need to free the dev
             * envelope */
            VIR_FREE(dev);
        }
315
        if (ret == 0 || fail)
316 317
            ret = testQemuHotplugCheckResult(vm, result_xml,
                                             result_filename, fail);
318
        break;
319 320

    case DETACH:
321
        ret = testQemuHotplugDetach(vm, dev, false);
322
        if (ret == 0 || fail)
323 324
            ret = testQemuHotplugCheckResult(vm, domain_xml,
                                             domain_filename, fail);
325
        break;
326 327 328

    case UPDATE:
        ret = testQemuHotplugUpdate(vm, dev);
329 330
    }

331
 cleanup:
332 333
    VIR_FREE(domain_filename);
    VIR_FREE(device_filename);
334 335
    VIR_FREE(result_filename);
    VIR_FREE(domain_xml);
336
    VIR_FREE(device_xml);
337
    VIR_FREE(result_xml);
338 339 340
    /* don't dispose test monitor with VM */
    if (priv)
        priv->mon = NULL;
341 342 343 344 345 346
    if (keep) {
        test->vm = vm;
    } else {
        virObjectUnref(vm);
        test->vm = NULL;
    }
347 348 349 350 351 352
    virDomainDeviceDefFree(dev);
    virObjectUnref(caps);
    qemuMonitorTestFree(test_mon);
    return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1;
}

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370

struct testQemuHotplugCpuData {
    char *file_xml_dom;
    char *file_xml_res_live;
    char *file_xml_res_conf;
    char *file_json_monitor;

    char *xml_dom;

    virDomainObjPtr vm;
    qemuMonitorTestPtr mon;
    bool modern;
};


static void
testQemuHotplugCpuDataFree(struct testQemuHotplugCpuData *data)
{
371 372
    qemuDomainObjPrivatePtr priv;

373 374 375 376 377 378 379 380 381 382
    if (!data)
        return;

    VIR_FREE(data->file_xml_dom);
    VIR_FREE(data->file_xml_res_live);
    VIR_FREE(data->file_xml_res_conf);
    VIR_FREE(data->file_json_monitor);

    VIR_FREE(data->xml_dom);

383 384 385 386 387 388 389
    if (data->vm) {
        priv = data->vm->privateData;
        priv->mon = NULL;

        virObjectUnref(data->vm);
    }

390
    qemuMonitorTestFree(data->mon);
391
    VIR_FREE(data);
392 393 394 395 396
}


static struct testQemuHotplugCpuData *
testQemuHotplugCpuPrepare(const char *test,
397 398
                          bool modern,
                          virHashTablePtr qmpschema)
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
{
    qemuDomainObjPrivatePtr priv = NULL;
    virCapsPtr caps = NULL;
    char *prefix = NULL;
    struct testQemuHotplugCpuData *data = NULL;

    if (virAsprintf(&prefix, "%s/qemuhotplugtestcpus/%s", abs_srcdir, test) < 0)
        return NULL;

    if (VIR_ALLOC(data) < 0)
        goto error;

    data->modern = modern;

    if (virAsprintf(&data->file_xml_dom, "%s-domain.xml", prefix) < 0 ||
        virAsprintf(&data->file_xml_res_live, "%s-result-live.xml", prefix) < 0 ||
        virAsprintf(&data->file_xml_res_conf, "%s-result-conf.xml", prefix) < 0 ||
        virAsprintf(&data->file_json_monitor, "%s-monitor.json", prefix) < 0)
        goto error;

    if (virTestLoadFile(data->file_xml_dom, &data->xml_dom) < 0)
        goto error;

422
    if (qemuHotplugCreateObjects(driver.xmlopt, &data->vm, data->xml_dom) < 0)
423 424 425 426 427 428 429
        goto error;

    if (!(caps = virQEMUDriverGetCapabilities(&driver, false)))
        goto error;

    /* create vm->newDef */
    data->vm->persistent = true;
430
    if (virDomainObjSetDefTransient(caps, driver.xmlopt, data->vm, NULL) < 0)
431 432 433 434 435 436 437 438
        goto error;

    priv = data->vm->privateData;

    if (data->modern)
        virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS);

    if (!(data->mon = qemuMonitorTestNewFromFileFull(data->file_json_monitor,
439
                                                     &driver, data->vm, qmpschema)))
440 441 442 443 444 445 446 447
        goto error;

    priv->mon = qemuMonitorTestGetMonitor(data->mon);
    virObjectUnlock(priv->mon);

    if (qemuDomainRefreshVcpuInfo(&driver, data->vm, 0, false) < 0)
        goto error;

448 449
    VIR_FREE(prefix);

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    return data;

 error:
    virObjectUnref(caps);
    testQemuHotplugCpuDataFree(data);
    VIR_FREE(prefix);
    return NULL;
}


static int
testQemuHotplugCpuFinalize(struct testQemuHotplugCpuData *data)
{
    int ret = -1;
    char *activeXML = NULL;
    char *configXML = NULL;

    if (data->file_xml_res_live) {
        if (!(activeXML = virDomainDefFormat(data->vm->def, driver.caps,
                                             VIR_DOMAIN_DEF_FORMAT_SECURE)))
            goto cleanup;

        if (virTestCompareToFile(activeXML, data->file_xml_res_live) < 0)
            goto cleanup;
    }

    if (data->file_xml_res_conf) {
        if (!(configXML = virDomainDefFormat(data->vm->newDef, driver.caps,
                                             VIR_DOMAIN_DEF_FORMAT_SECURE |
                                             VIR_DOMAIN_DEF_FORMAT_INACTIVE)))
            goto cleanup;

        if (virTestCompareToFile(configXML, data->file_xml_res_conf) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
     VIR_FREE(activeXML);
     VIR_FREE(configXML);
     return ret;
}


struct testQemuHotplugCpuParams {
    const char *test;
    int newcpus;
498 499
    const char *cpumap;
    bool state;
500 501
    bool modern;
    bool fail;
502
    virHashTablePtr schema;
503 504 505 506 507 508 509 510 511 512 513
};


static int
testQemuHotplugCpuGroup(const void *opaque)
{
    const struct testQemuHotplugCpuParams *params = opaque;
    struct testQemuHotplugCpuData *data = NULL;
    int ret = -1;
    int rc;

514 515
    if (!(data = testQemuHotplugCpuPrepare(params->test, params->modern,
                                           params->schema)))
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
        return -1;

    rc = qemuDomainSetVcpusInternal(&driver, data->vm, data->vm->def,
                                    data->vm->newDef, params->newcpus,
                                    params->modern);

    if (params->fail) {
        if (rc == 0)
            fprintf(stderr, "cpu test '%s' should have failed\n", params->test);
        else
            ret = 0;

        goto cleanup;
    } else {
        if (rc < 0)
            goto cleanup;
    }

    ret = testQemuHotplugCpuFinalize(data);

 cleanup:
    testQemuHotplugCpuDataFree(data);
    return ret;
}


542 543 544 545 546 547 548 549 550
static int
testQemuHotplugCpuIndividual(const void *opaque)
{
    const struct testQemuHotplugCpuParams *params = opaque;
    struct testQemuHotplugCpuData *data = NULL;
    virBitmapPtr map = NULL;
    int ret = -1;
    int rc;

551 552
    if (!(data = testQemuHotplugCpuPrepare(params->test, params->modern,
                                           params->schema)))
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
        return -1;

    if (virBitmapParse(params->cpumap, &map, 128) < 0)
        goto cleanup;

    rc = qemuDomainSetVcpuInternal(&driver, data->vm, data->vm->def,
                                   data->vm->newDef, map, params->state);

    if (params->fail) {
        if (rc == 0)
            fprintf(stderr, "cpu test '%s' should have failed\n", params->test);
        else
            ret = 0;

        goto cleanup;
    } else {
        if (rc < 0)
            goto cleanup;
    }

    ret = testQemuHotplugCpuFinalize(data);

 cleanup:
    virBitmapFree(map);
    testQemuHotplugCpuDataFree(data);
    return ret;
}



583 584 585
static int
mymain(void)
{
586
    VIR_AUTOPTR(virHashTable) qmpschema = NULL;
587
    int ret = 0;
588
    struct qemuHotplugTestData data = {0};
589
    struct testQemuHotplugCpuParams cpudata;
590

591
#if !WITH_YAJL
J
Ján Tomko 已提交
592
    fputs("libvirt not compiled with JSON support, skipping this test\n", stderr);
593 594 595 596
    return EXIT_AM_SKIP;
#endif

    if (virThreadInitialize() < 0 ||
597
        qemuTestDriverInit(&driver) < 0)
598 599 600 601 602 603
        return EXIT_FAILURE;

    virEventRegisterDefaultImpl();

    VIR_FREE(driver.config->spiceListen);
    VIR_FREE(driver.config->vncListen);
604 605 606
    /* some dummy values from 'config file' */
    if (VIR_STRDUP_QUIET(driver.config->spicePassword, "123456") < 0)
        return EXIT_FAILURE;
607

608
    if (!(driver.domainEventState = virObjectEventStateNew()))
609 610
        return EXIT_FAILURE;

611 612 613 614 615 616 617
    if (!(qmpschema = testQEMUSchemaLoad())) {
        VIR_TEST_VERBOSE("failed to load qapi schema\n");
        return EXIT_FAILURE;
    }

    cpudata.schema = qmpschema;

618 619 620 621 622 623
    driver.lockManager = virLockManagerPluginNew("nop", "qemu",
                                                 driver.config->configBaseDir,
                                                 0);
    if (!driver.lockManager)
        return EXIT_FAILURE;

624 625 626
    /* wait only 100ms for DEVICE_DELETED event */
    qemuDomainRemoveDeviceWaitTime = 100;

627
#define DO_TEST(file, ACTION, dev, fial, kep, ...) \
628 629 630 631 632 633 634 635 636 637 638
    do { \
        const char *my_mon[] = { __VA_ARGS__, NULL}; \
        const char *name = file " " #ACTION " " dev; \
        data.action = ACTION; \
        data.domain_filename = file; \
        data.device_filename = dev; \
        data.fail = fial; \
        data.mon = my_mon; \
        data.keep = kep; \
        if (virTestRun(name, testQemuHotplug, &data) < 0) \
            ret = -1; \
639
    } while (0)
640

641
#define DO_TEST_ATTACH(file, dev, fial, kep, ...) \
642
    DO_TEST(file, ATTACH, dev, fial, kep, __VA_ARGS__)
643

644
#define DO_TEST_DETACH(file, dev, fial, kep, ...) \
645
    DO_TEST(file, DETACH, dev, fial, kep, __VA_ARGS__)
646

647
#define DO_TEST_UPDATE(file, dev, fial, kep, ...) \
648
    DO_TEST(file, UPDATE, dev, fial, kep, __VA_ARGS__)
649

650 651

#define QMP_OK      "{\"return\": {}}"
652
#define HMP(msg)    "{\"return\": \"" msg "\"}"
653

654
#define QMP_DEVICE_DELETED(dev) \
655 656 657 658 659 660 661 662 663 664
    "{" \
    "    \"timestamp\": {" \
    "        \"seconds\": 1374137171," \
    "        \"microseconds\": 2659" \
    "    }," \
    "    \"event\": \"DEVICE_DELETED\"," \
    "    \"data\": {" \
    "        \"device\": \"" dev "\"," \
    "        \"path\": \"/machine/peripheral/" dev "\"" \
    "    }" \
665 666
    "}\r\n"

667 668
    DO_TEST_UPDATE("graphics-spice", "graphics-spice-nochange", false, false, NULL);
    DO_TEST_UPDATE("graphics-spice-timeout", "graphics-spice-timeout-nochange", false, false,
669
                   "set_password", QMP_OK, "expire_password", QMP_OK);
670
    DO_TEST_UPDATE("graphics-spice-timeout", "graphics-spice-timeout-password", false, false,
671
                   "set_password", QMP_OK, "expire_password", QMP_OK);
672
    DO_TEST_UPDATE("graphics-spice", "graphics-spice-listen", true, false, NULL);
673
    DO_TEST_UPDATE("graphics-spice-listen-network", "graphics-spice-listen-network-password", false, false,
674
                   "set_password", QMP_OK, "expire_password", QMP_OK);
675 676 677
    /* Strange huh? Currently, only graphics can be updated :-P */
    DO_TEST_UPDATE("disk-cdrom", "disk-cdrom-nochange", true, false, NULL);

678
    DO_TEST_ATTACH("console-compat-2-live", "console-virtio", false, true,
679
                   "chardev-add", "{\"return\": {\"pty\": \"/dev/pts/26\"}}",
680
                   "device_add", QMP_OK);
681

682
    DO_TEST_DETACH("console-compat-2-live", "console-virtio", false, false,
683
                   "device_del", QMP_DEVICE_DELETED("console1") QMP_OK,
684
                   "chardev-remove", QMP_OK);
685

686 687 688
    DO_TEST_ATTACH("base-live", "disk-virtio", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);
689
    DO_TEST_DETACH("base-live", "disk-virtio", true, true,
690 691
                   "device_del", QMP_OK,
                   "human-monitor-command", HMP(""));
692
    DO_TEST_DETACH("base-live", "disk-virtio", false, false,
693 694 695
                   "device_del", QMP_DEVICE_DELETED("virtio-disk4") QMP_OK,
                   "human-monitor-command", HMP(""));

696 697 698
    DO_TEST_ATTACH("base-live", "disk-usb", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);
699
    DO_TEST_DETACH("base-live", "disk-usb", true, true,
700 701
                   "device_del", QMP_OK,
                   "human-monitor-command", HMP(""));
702
    DO_TEST_DETACH("base-live", "disk-usb", false, false,
703 704 705
                   "device_del", QMP_DEVICE_DELETED("usb-disk16") QMP_OK,
                   "human-monitor-command", HMP(""));

706 707 708
    DO_TEST_ATTACH("base-live", "disk-scsi", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);
709
    DO_TEST_DETACH("base-live", "disk-scsi", true, true,
710 711
                   "device_del", QMP_OK,
                   "human-monitor-command", HMP(""));
712
    DO_TEST_DETACH("base-live", "disk-scsi", false, false,
713 714 715
                   "device_del", QMP_DEVICE_DELETED("scsi0-0-0-5") QMP_OK,
                   "human-monitor-command", HMP(""));

716 717 718 719 720 721 722 723 724
    DO_TEST_ATTACH("base-without-scsi-controller-live", "disk-scsi-2", false, true,
                   /* Four controllers added */
                   "device_add", QMP_OK,
                   "device_add", QMP_OK,
                   "device_add", QMP_OK,
                   "device_add", QMP_OK,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   /* Disk added */
                   "device_add", QMP_OK);
725
    DO_TEST_DETACH("base-with-scsi-controller-live", "disk-scsi-2", true, true,
726 727
                   "device_del", QMP_OK,
                   "human-monitor-command", HMP(""));
728
    DO_TEST_DETACH("base-with-scsi-controller-live", "disk-scsi-2", false, false,
729
                   "device_del", QMP_DEVICE_DELETED("scsi3-0-5-6") QMP_OK,
730 731
                   "human-monitor-command", HMP(""));

732
    DO_TEST_ATTACH("base-live", "qemu-agent", false, true,
733 734
                   "chardev-add", QMP_OK,
                   "device_add", QMP_OK);
735
    DO_TEST_DETACH("base-live", "qemu-agent-detach", false, false,
736
                   "device_del", QMP_DEVICE_DELETED("channel0") QMP_OK,
737 738
                   "chardev-remove", QMP_OK);

739 740 741 742
    DO_TEST_ATTACH("base-ccw-live", "ccw-virtio", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);
    DO_TEST_DETACH("base-ccw-live", "ccw-virtio", false, false,
743
                   "device_del", QMP_DEVICE_DELETED("virtio-disk4") QMP_OK,
744 745 746 747 748 749 750
                   "human-monitor-command", HMP(""));

    DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);

    DO_TEST_DETACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2", false, false,
751
                   "device_del", QMP_DEVICE_DELETED("virtio-disk0") QMP_OK,
752 753 754 755 756 757 758
                   "human-monitor-command", HMP(""));

    DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);

    DO_TEST_DETACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, false,
759
                   "device_del", QMP_DEVICE_DELETED("virtio-disk0") QMP_OK,
760 761 762 763 764 765 766 767
                   "human-monitor-command", HMP(""));

    /* Attach a second device, then detach the first one. Then attach the first one again. */
    DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, true,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);

    DO_TEST_DETACH("base-ccw-live-with-2-ccw-virtio", "ccw-virtio-1-explicit", false, true,
768
                   "device_del", QMP_DEVICE_DELETED("virtio-disk4") QMP_OK,
769 770 771 772 773 774
                   "human-monitor-command", HMP(""));

    DO_TEST_ATTACH("base-ccw-live-with-2-ccw-virtio", "ccw-virtio-1-reverse", false, false,
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);

775 776 777 778 779 780 781
    DO_TEST_ATTACH("base-live", "ivshmem-plain", false, true,
                   "object-add", QMP_OK,
                   "device_add", QMP_OK);
    DO_TEST_ATTACH("base-live", "ivshmem-doorbell", false, true,
                   "chardev-add", QMP_OK,
                   "device_add", QMP_OK);
    DO_TEST_DETACH("base-live+ivshmem-plain", "ivshmem-doorbell-detach", false, true,
782
                   "device_del", QMP_DEVICE_DELETED("shmem1") QMP_OK,
783 784
                   "chardev-remove", QMP_OK);
    DO_TEST_DETACH("base-live", "ivshmem-plain-detach", false, false,
785
                   "device_del", QMP_DEVICE_DELETED("shmem0") QMP_OK,
786
                   "object-del", QMP_OK);
787
    DO_TEST_ATTACH("base-live+disk-scsi-wwn",
M
Michal Privoznik 已提交
788
                   "disk-scsi-duplicate-wwn", false, false,
789 790
                   "human-monitor-command", HMP("OK\\r\\n"),
                   "device_add", QMP_OK);
791

M
Michal Privoznik 已提交
792
    DO_TEST_ATTACH("base-live", "watchdog", false, true,
M
Michal Privoznik 已提交
793 794
                   "watchdog-set-action", QMP_OK,
                   "device_add", QMP_OK);
M
Michal Privoznik 已提交
795
    DO_TEST_DETACH("base-live", "watchdog-full", false, false,
796
                   "device_del", QMP_DEVICE_DELETED("watchdog0") QMP_OK);
M
Michal Privoznik 已提交
797

798 799 800 801
    DO_TEST_ATTACH("base-live", "watchdog-user-alias", false, true,
                   "watchdog-set-action", QMP_OK,
                   "device_add", QMP_OK);
    DO_TEST_DETACH("base-live", "watchdog-user-alias-full", false, false,
802
                   "device_del", QMP_DEVICE_DELETED("ua-UserWatchdog") QMP_OK);
803

804 805 806 807 808 809
    DO_TEST_ATTACH("base-live", "guestfwd", false, true,
                   "chardev-add", QMP_OK,
                   "netdev_add", QMP_OK);
    DO_TEST_DETACH("base-live", "guestfwd", false, false,
                   "netdev_del", QMP_OK);

810 811 812 813 814 815 816 817 818
#define DO_TEST_CPU_GROUP(prefix, vcpus, modernhp, expectfail) \
    do { \
        cpudata.test = prefix; \
        cpudata.newcpus = vcpus; \
        cpudata.modern = modernhp; \
        cpudata.fail = expectfail; \
        if (virTestRun("hotplug vcpus group " prefix, \
                       testQemuHotplugCpuGroup, &cpudata) < 0) \
            ret = -1; \
819 820 821
    } while (0)

    DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false);
822
    DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false);
823 824 825 826
    DO_TEST_CPU_GROUP("ppc64-modern-bulk", 24, true, false);
    DO_TEST_CPU_GROUP("ppc64-modern-bulk", 15, true, true);
    DO_TEST_CPU_GROUP("ppc64-modern-bulk", 23, true, true);
    DO_TEST_CPU_GROUP("ppc64-modern-bulk", 25, true, true);
827

828 829 830 831 832 833 834 835 836 837
#define DO_TEST_CPU_INDIVIDUAL(prefix, mapstr, statefl, modernhp, expectfail) \
    do { \
        cpudata.test = prefix; \
        cpudata.cpumap = mapstr; \
        cpudata.state = statefl; \
        cpudata.modern = modernhp; \
        cpudata.fail = expectfail; \
        if (virTestRun("hotplug vcpus group " prefix, \
                       testQemuHotplugCpuIndividual, &cpudata) < 0) \
            ret = -1; \
838 839 840 841 842 843 844 845 846 847 848
    } while (0)

    DO_TEST_CPU_INDIVIDUAL("x86-modern-individual-add", "7", true, true, false);
    DO_TEST_CPU_INDIVIDUAL("x86-modern-individual-add", "6,7", true, true, true);
    DO_TEST_CPU_INDIVIDUAL("x86-modern-individual-add", "7", false, true, true);
    DO_TEST_CPU_INDIVIDUAL("x86-modern-individual-add", "7", true, false, true);

    DO_TEST_CPU_INDIVIDUAL("ppc64-modern-individual", "16-23", true, true, false);
    DO_TEST_CPU_INDIVIDUAL("ppc64-modern-individual", "16-22", true, true, true);
    DO_TEST_CPU_INDIVIDUAL("ppc64-modern-individual", "17", true, true, true);

849
    qemuTestDriverFree(&driver);
850
    virObjectUnref(data.vm);
851 852 853
    return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

854
VIR_TEST_MAIN(mymain)