[libvirt] [PATCH v2 00/11] tests: qemu: Add cpu hotplug testing

This is a repost of https://www.redhat.com/archives/libvir-list/2016-December/msg00420.html after a recent rebase conflict. Add some useful monitor infrastructure to simplify testing and add testing for the cpu hotplug code. The code has some complex logic which was not covered by current test suite. Peter Krempa (11): qemu: monitor: More strict checking of 'query-cpus' if hotplug is supported util: json: Add helper to reformat JSON strings tests: qemu: Document qemuMonitorTestNewFromFile qemu: Prepare for reuse of qemuDomainSetVcpusLive qemu: Move cpu hotplug code into qemu_hotplug.c tests: qemumonitor: Propagate better error messages tests: qemu: monitor: Add helpers to test full command syntax tests: qemu: Add helper to load full monitor conversation from file tests: hotplug: Add test infrastructure for testing qemu CPU hotplug code tests: hotplug: Add test data for legacy cpu hotplug tests: hotplug: Test CPU hotplug with ppc64 data src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 328 ------------ src/qemu/qemu_hotplug.c | 339 ++++++++++++ src/qemu/qemu_hotplug.h | 7 + src/qemu/qemu_monitor.c | 6 +- src/qemu/qemu_monitor_json.c | 6 +- src/qemu/qemu_monitor_json.h | 3 +- src/util/virjson.c | 29 + src/util/virjson.h | 2 + tests/qemuagenttest.c | 3 +- tests/qemuhotplugtest.c | 194 +++++++ tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml | 20 + tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json | 593 +++++++++++++++++++++ .../qemuhotplugtestcpus/ppc64-bulk-result-conf.xml | 64 +++ .../qemuhotplugtestcpus/ppc64-bulk-result-live.xml | 72 +++ .../qemuhotplugtestcpus/x86-modern-bulk-domain.xml | 21 + .../x86-modern-bulk-monitor.json | 471 ++++++++++++++++ .../x86-modern-bulk-result-conf.xml | 40 ++ .../x86-modern-bulk-result-live.xml | 48 ++ tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml | 21 + .../qemuhotplugtestcpus/x86-old-bulk-monitor.json | 193 +++++++ .../x86-old-bulk-result-conf.xml | 30 ++ .../x86-old-bulk-result-live.xml | 38 ++ tests/qemumonitorjsontest.c | 2 +- tests/qemumonitortestutils.c | 322 ++++++++++- tests/qemumonitortestutils.h | 12 +- 26 files changed, 2516 insertions(+), 349 deletions(-) create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml -- 2.11.0

In cases where CPU hotplug is supported by qemu force the monitor to reject invalid or broken responses to 'query-cpus'. It's expected that the command returns usable data in such case. --- src/qemu/qemu_monitor.c | 6 +++--- src/qemu/qemu_monitor_json.c | 6 +++++- src/qemu/qemu_monitor_json.h | 3 ++- tests/qemumonitorjsontest.c | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 1610ae3f4..b7be5e7f4 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1921,12 +1921,12 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon, goto cleanup; if (mon->json) - rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries); + rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries, hotplug); else rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries); if (rc < 0) { - if (rc == -2) { + if (!hotplug && rc == -2) { VIR_STEAL_PTR(*vcpus, info); ret = 0; } @@ -1974,7 +1974,7 @@ qemuMonitorGetCpuHalted(qemuMonitorPtr mon, QEMU_CHECK_MONITOR_NULL(mon); if (mon->json) - rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries); + rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries, false); else rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e767437c0..20d3e2c16 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1394,7 +1394,8 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data, int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, struct qemuMonitorQueryCpusEntry **entries, - size_t *nentries) + size_t *nentries, + bool force) { int ret = -1; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL); @@ -1407,6 +1408,9 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) goto cleanup; + if (force && qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + if (!(data = virJSONValueObjectGetArray(reply, "return"))) { ret = -2; goto cleanup; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 18b508d9c..79688c82f 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -60,7 +60,8 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon); int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, struct qemuMonitorQueryCpusEntry **entries, - size_t *nentries); + size_t *nentries, + bool force); int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon, virDomainVirtType *virtType); int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 535fb63de..5b2d6bb34 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1407,7 +1407,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data) goto cleanup; if (qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), - &cpudata, &ncpudata) < 0) + &cpudata, &ncpudata, true) < 0) goto cleanup; if (ncpudata != 4) { -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:11AM +0100, Peter Krempa wrote:
In cases where CPU hotplug is supported by qemu force the monitor to reject invalid or broken responses to 'query-cpus'. It's expected that the command returns usable data in such case. --- src/qemu/qemu_monitor.c | 6 +++--- src/qemu/qemu_monitor_json.c | 6 +++++- src/qemu/qemu_monitor_json.h | 3 ++- tests/qemumonitorjsontest.c | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-)
ACK Pavel

For use in test cases it will be helpful to allow reformatting JSON strings. Add a wrapper on top of the parser and formatter to achieve this. --- src/libvirt_private.syms | 1 + src/util/virjson.c | 29 +++++++++++++++++++++++++++++ src/util/virjson.h | 2 ++ 3 files changed, 32 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4d16620b4..59ed85dcc 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1791,6 +1791,7 @@ virISCSIScanTargets; # util/virjson.h +virJSONStringReformat; virJSONValueArrayAppend; virJSONValueArrayForeachSteal; virJSONValueArrayGet; diff --git a/src/util/virjson.c b/src/util/virjson.c index 3804e7e97..c907b5ded 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1918,3 +1918,32 @@ virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED, return NULL; } #endif + + +/** + * virJSONStringReformat: + * @jsonstr: string to reformat + * @pretty: use the pretty formatter + * + * Reformats a JSON string by passing it to the parser and then to the + * formatter. If @pretty is true the JSON is formatted for human eye + * compatibility. + * + * Returns the reformatted JSON string on success; NULL and a libvirt error on + * failure. + */ +char * +virJSONStringReformat(const char *jsonstr, + bool pretty) +{ + virJSONValuePtr json; + char *ret; + + if (!(json = virJSONValueFromString(jsonstr))) + return NULL; + + ret = virJSONValueToString(json, pretty); + + virJSONValueFree(json); + return ret; +} diff --git a/src/util/virjson.h b/src/util/virjson.h index 122de96c5..5e32cb9a4 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -181,4 +181,6 @@ int virJSONValueObjectForeachKeyValue(virJSONValuePtr object, virJSONValuePtr virJSONValueCopy(const virJSONValue *in); +char *virJSONStringReformat(const char *jsonstr, bool pretty); + #endif /* __VIR_JSON_H_ */ -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:12AM +0100, Peter Krempa wrote:
For use in test cases it will be helpful to allow reformatting JSON strings. Add a wrapper on top of the parser and formatter to achieve this. --- src/libvirt_private.syms | 1 + src/util/virjson.c | 29 +++++++++++++++++++++++++++++ src/util/virjson.h | 2 ++ 3 files changed, 32 insertions(+)
ACK Pavel

--- tests/qemumonitortestutils.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index f8f23c3d7..3722b0729 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1037,6 +1037,19 @@ qemuMonitorTestNew(bool json, } +/** + * qemuMonitorTestNewFromFile: + * @fileName: File name to load monitor replies from + * @xmlopt: XML parser configuration object + * @simple: see below + * + * Create a JSON test monitor simulator object and fill it with replies + * specified in @fileName. The file contains JSON reply objects separated by + * empty lines. If @simple is true a generic QMP greeting is automatically + * added as the first reply, otherwise the first entry in the file is used. + * + * Returns the monitor object on success; NULL on error. + */ qemuMonitorTestPtr qemuMonitorTestNewFromFile(const char *fileName, virDomainXMLOptionPtr xmlopt, -- 2.11.0

Extract the call to qemuDomainSelectHotplugVcpuEntities outside of qemuDomainSetVcpusLive and decide whether to hotplug or unplug the entities specified by the cpumap using a boolean flag. This will allow to use qemuDomainSetVcpusLive in cases where we prepare the list of vcpus to enable or disable by other means. --- src/qemu/qemu_driver.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 42f988965..dee5d6c60 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4784,6 +4784,7 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, * * @def: domain definition * @nvcpus: target vcpu count + * @enable: set to true if vcpus should be enabled * * Tries to find which vcpu entities need to be enabled or disabled to reach * @nvcpus. This function works in order of the legacy hotplug but is able to @@ -4793,7 +4794,8 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, */ static virBitmapPtr qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, - unsigned int nvcpus) + unsigned int nvcpus, + bool *enable) { virBitmapPtr ret = NULL; virDomainVcpuDefPtr vcpu; @@ -4806,6 +4808,8 @@ qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, return NULL; if (nvcpus > curvcpus) { + *enable = true; + for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { vcpu = virDomainDefGetVcpu(def, i); vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); @@ -4828,6 +4832,8 @@ qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, ignore_value(virBitmapSetBit(ret, i)); } } else { + *enable = false; + for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { vcpu = virDomainDefGetVcpu(def, i); vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); @@ -4873,22 +4879,19 @@ static int qemuDomainSetVcpusLive(virQEMUDriverPtr driver, virQEMUDriverConfigPtr cfg, virDomainObjPtr vm, - unsigned int nvcpus) + virBitmapPtr vcpumap, + bool enable) { qemuDomainObjPrivatePtr priv = vm->privateData; qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; - virBitmapPtr vcpumap = NULL; ssize_t nextvcpu = -1; int rc = 0; int ret = -1; - if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus))) - goto cleanup; - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) goto cleanup; - if (nvcpus > virDomainDefGetVcpus(vm->def)) { + if (enable) { while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) break; @@ -4915,7 +4918,6 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver, cleanup: qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); - virBitmapFree(vcpumap); return ret; } @@ -5001,6 +5003,8 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, bool hotpluggable) { virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virBitmapPtr vcpumap = NULL; + bool enable; int ret = -1; if (def && nvcpus > virDomainDefGetVcpusMax(def)) { @@ -5019,8 +5023,14 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, goto cleanup; } - if (def && qemuDomainSetVcpusLive(driver, cfg, vm, nvcpus) < 0) - goto cleanup; + if (def) { + if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, + &enable))) + goto cleanup; + + if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) + goto cleanup; + } if (persistentDef) { qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); @@ -5032,6 +5042,7 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, ret = 0; cleanup: + virBitmapFree(vcpumap); virObjectUnref(cfg); return ret; } -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:14AM +0100, Peter Krempa wrote:
Extract the call to qemuDomainSelectHotplugVcpuEntities outside of qemuDomainSetVcpusLive and decide whether to hotplug or unplug the entities specified by the cpumap using a boolean flag.
This will allow to use qemuDomainSetVcpusLive in cases where we prepare the list of vcpus to enable or disable by other means. --- src/qemu/qemu_driver.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
ACK Pavel

Move all the worker code into the appropriate file. This will also allow testing of cpu hotplug. --- src/qemu/qemu_driver.c | 339 ------------------------------------------------ src/qemu/qemu_hotplug.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 7 + 3 files changed, 346 insertions(+), 339 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dee5d6c60..ba39b4156 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4616,76 +4616,6 @@ static void qemuProcessEventHandler(void *data, void *opaque) static int -qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver, - virDomainObjPtr vm, - unsigned int vcpu) -{ - virJSONValuePtr vcpuprops = NULL; - virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu); - qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); - unsigned int nvcpus = vcpupriv->vcpus; - bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm); - int ret = -1; - int rc; - int oldvcpus = virDomainDefGetVcpus(vm->def); - size_t i; - - if (newhotplug) { - if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0) - goto cleanup; - - if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo))) - goto cleanup; - } - - qemuDomainObjEnterMonitor(driver, vm); - - if (newhotplug) { - rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops); - vcpuprops = NULL; - } else { - rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true); - } - - if (qemuDomainObjExitMonitor(driver, vm) < 0) - goto cleanup; - - virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0); - - if (rc < 0) - goto cleanup; - - /* start outputting of the new XML element to allow keeping unpluggability */ - if (newhotplug) - vm->def->individualvcpus = true; - - if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0) - goto cleanup; - - /* validation requires us to set the expected state prior to calling it */ - for (i = vcpu; i < vcpu + nvcpus; i++) { - vcpuinfo = virDomainDefGetVcpu(vm->def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); - - vcpuinfo->online = true; - - if (vcpupriv->tid > 0 && - qemuProcessSetupVcpu(vm, i) < 0) - goto cleanup; - } - - if (qemuDomainValidateVcpuInfo(vm) < 0) - goto cleanup; - - ret = 0; - - cleanup: - virJSONValueFree(vcpuprops); - return ret; -} - - -static int qemuDomainSetVcpusAgent(virDomainObjPtr vm, unsigned int nvcpus) { @@ -4779,275 +4709,6 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, } -/** - * qemuDomainSelectHotplugVcpuEntities: - * - * @def: domain definition - * @nvcpus: target vcpu count - * @enable: set to true if vcpus should be enabled - * - * Tries to find which vcpu entities need to be enabled or disabled to reach - * @nvcpus. This function works in order of the legacy hotplug but is able to - * skip over entries that are added out of order. - * - * Returns the bitmap of vcpus to modify on success, NULL on error. - */ -static virBitmapPtr -qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, - unsigned int nvcpus, - bool *enable) -{ - virBitmapPtr ret = NULL; - virDomainVcpuDefPtr vcpu; - qemuDomainVcpuPrivatePtr vcpupriv; - unsigned int maxvcpus = virDomainDefGetVcpusMax(def); - unsigned int curvcpus = virDomainDefGetVcpus(def); - ssize_t i; - - if (!(ret = virBitmapNew(maxvcpus))) - return NULL; - - if (nvcpus > curvcpus) { - *enable = true; - - for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { - vcpu = virDomainDefGetVcpu(def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); - - if (vcpu->online) - continue; - - if (vcpupriv->vcpus == 0) - continue; - - curvcpus += vcpupriv->vcpus; - - if (curvcpus > nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("target vm vcpu granularity does not allow the " - "desired vcpu count")); - goto error; - } - - ignore_value(virBitmapSetBit(ret, i)); - } - } else { - *enable = false; - - for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { - vcpu = virDomainDefGetVcpu(def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); - - if (!vcpu->online) - continue; - - if (vcpupriv->vcpus == 0) - continue; - - if (!vcpupriv->alias) - continue; - - curvcpus -= vcpupriv->vcpus; - - if (curvcpus < nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("target vm vcpu granularity does not allow the " - "desired vcpu count")); - goto error; - } - - ignore_value(virBitmapSetBit(ret, i)); - } - } - - if (curvcpus != nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("failed to find appropriate hotpluggable vcpus to " - "reach the desired target vcpu count")); - goto error; - } - - return ret; - - error: - virBitmapFree(ret); - return NULL; -} - - -static int -qemuDomainSetVcpusLive(virQEMUDriverPtr driver, - virQEMUDriverConfigPtr cfg, - virDomainObjPtr vm, - virBitmapPtr vcpumap, - bool enable) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; - ssize_t nextvcpu = -1; - int rc = 0; - int ret = -1; - - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) - goto cleanup; - - if (enable) { - while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { - if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) - break; - } - } else { - for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) { - if (!virBitmapIsBitSet(vcpumap, nextvcpu)) - continue; - - if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0) - break; - } - } - - qemuDomainVcpuPersistOrder(vm->def); - - if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) - goto cleanup; - - if (rc < 0) - goto cleanup; - - ret = 0; - - cleanup: - qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); - - return ret; -} - - -/** - * qemuDomainSetVcpusConfig: - * @def: config/offline definition of a domain - * @nvcpus: target vcpu count - * - * Properly handle cold(un)plug of vcpus: - * - plug in inactive vcpus/uplug active rather than rewriting state - * - fix hotpluggable state - */ -static void -qemuDomainSetVcpusConfig(virDomainDefPtr def, - unsigned int nvcpus, - bool hotpluggable) -{ - virDomainVcpuDefPtr vcpu; - size_t curvcpus = virDomainDefGetVcpus(def); - size_t maxvcpus = virDomainDefGetVcpusMax(def); - size_t i; - - /* ordering information may become invalid, thus clear it */ - virDomainDefVcpuOrderClear(def); - - if (curvcpus == nvcpus) - return; - - if (curvcpus < nvcpus) { - for (i = 0; i < maxvcpus; i++) { - vcpu = virDomainDefGetVcpu(def, i); - - if (!vcpu) - continue; - - if (vcpu->online) { - /* non-hotpluggable vcpus need to be clustered at the beggining, - * thus we need to force vcpus to be hotpluggable when we find - * vcpus that are hotpluggable and online prior to the ones - * we are going to add */ - if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) - hotpluggable = true; - - continue; - } - - vcpu->online = true; - if (hotpluggable) { - vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; - def->individualvcpus = true; - } else { - vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO; - } - - if (++curvcpus == nvcpus) - break; - } - } else { - for (i = maxvcpus; i != 0; i--) { - vcpu = virDomainDefGetVcpu(def, i - 1); - - if (!vcpu || !vcpu->online) - continue; - - vcpu->online = false; - vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; - - if (--curvcpus == nvcpus) - break; - } - } -} - - -static int -qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainDefPtr def, - virDomainDefPtr persistentDef, - unsigned int nvcpus, - bool hotpluggable) -{ - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); - virBitmapPtr vcpumap = NULL; - bool enable; - int ret = -1; - - if (def && nvcpus > virDomainDefGetVcpusMax(def)) { - virReportError(VIR_ERR_INVALID_ARG, - _("requested vcpus is greater than max allowable" - " vcpus for the live domain: %u > %u"), - nvcpus, virDomainDefGetVcpusMax(def)); - goto cleanup; - } - - if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) { - virReportError(VIR_ERR_INVALID_ARG, - _("requested vcpus is greater than max allowable" - " vcpus for the persistent domain: %u > %u"), - nvcpus, virDomainDefGetVcpusMax(persistentDef)); - goto cleanup; - } - - if (def) { - if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, - &enable))) - goto cleanup; - - if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) - goto cleanup; - } - - if (persistentDef) { - qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); - - if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0) - goto cleanup; - } - - ret = 0; - - cleanup: - virBitmapFree(vcpumap); - virObjectUnref(cfg); - return ret; -} - - static int qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index f2e98469e..5b0a3f515 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5346,3 +5346,342 @@ qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver, return qemuDomainRemoveVcpu(driver, vm, vcpu); } + + +static int +qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver, + virDomainObjPtr vm, + unsigned int vcpu) +{ + virJSONValuePtr vcpuprops = NULL; + virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu); + qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); + unsigned int nvcpus = vcpupriv->vcpus; + bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm); + int ret = -1; + int rc; + int oldvcpus = virDomainDefGetVcpus(vm->def); + size_t i; + + if (newhotplug) { + if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0) + goto cleanup; + + if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo))) + goto cleanup; + } + + qemuDomainObjEnterMonitor(driver, vm); + + if (newhotplug) { + rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops); + vcpuprops = NULL; + } else { + rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true); + } + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + goto cleanup; + + virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0); + + if (rc < 0) + goto cleanup; + + /* start outputting of the new XML element to allow keeping unpluggability */ + if (newhotplug) + vm->def->individualvcpus = true; + + if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0) + goto cleanup; + + /* validation requires us to set the expected state prior to calling it */ + for (i = vcpu; i < vcpu + nvcpus; i++) { + vcpuinfo = virDomainDefGetVcpu(vm->def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); + + vcpuinfo->online = true; + + if (vcpupriv->tid > 0 && + qemuProcessSetupVcpu(vm, i) < 0) + goto cleanup; + } + + if (qemuDomainValidateVcpuInfo(vm) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(vcpuprops); + return ret; +} + + +/** + * qemuDomainSelectHotplugVcpuEntities: + * + * @def: domain definition + * @nvcpus: target vcpu count + * @enable: set to true if vcpus should be enabled + * + * Tries to find which vcpu entities need to be enabled or disabled to reach + * @nvcpus. This function works in order of the legacy hotplug but is able to + * skip over entries that are added out of order. + * + * Returns the bitmap of vcpus to modify on success, NULL on error. + */ +static virBitmapPtr +qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, + unsigned int nvcpus, + bool *enable) +{ + virBitmapPtr ret = NULL; + virDomainVcpuDefPtr vcpu; + qemuDomainVcpuPrivatePtr vcpupriv; + unsigned int maxvcpus = virDomainDefGetVcpusMax(def); + unsigned int curvcpus = virDomainDefGetVcpus(def); + ssize_t i; + + if (!(ret = virBitmapNew(maxvcpus))) + return NULL; + + if (nvcpus > curvcpus) { + *enable = true; + + for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { + vcpu = virDomainDefGetVcpu(def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); + + if (vcpu->online) + continue; + + if (vcpupriv->vcpus == 0) + continue; + + curvcpus += vcpupriv->vcpus; + + if (curvcpus > nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("target vm vcpu granularity does not allow the " + "desired vcpu count")); + goto error; + } + + ignore_value(virBitmapSetBit(ret, i)); + } + } else { + *enable = false; + + for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { + vcpu = virDomainDefGetVcpu(def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); + + if (!vcpu->online) + continue; + + if (vcpupriv->vcpus == 0) + continue; + + if (!vcpupriv->alias) + continue; + + curvcpus -= vcpupriv->vcpus; + + if (curvcpus < nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("target vm vcpu granularity does not allow the " + "desired vcpu count")); + goto error; + } + + ignore_value(virBitmapSetBit(ret, i)); + } + } + + if (curvcpus != nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("failed to find appropriate hotpluggable vcpus to " + "reach the desired target vcpu count")); + goto error; + } + + return ret; + + error: + virBitmapFree(ret); + return NULL; +} + + +static int +qemuDomainSetVcpusLive(virQEMUDriverPtr driver, + virQEMUDriverConfigPtr cfg, + virDomainObjPtr vm, + virBitmapPtr vcpumap, + bool enable) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; + ssize_t nextvcpu = -1; + int rc = 0; + int ret = -1; + + if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) + goto cleanup; + + if (enable) { + while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { + if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) + break; + } + } else { + for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) { + if (!virBitmapIsBitSet(vcpumap, nextvcpu)) + continue; + + if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0) + break; + } + } + + qemuDomainVcpuPersistOrder(vm->def); + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) + goto cleanup; + + if (rc < 0) + goto cleanup; + + ret = 0; + + cleanup: + qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); + + return ret; +} + + +/** + * qemuDomainSetVcpusConfig: + * @def: config/offline definition of a domain + * @nvcpus: target vcpu count + * + * Properly handle cold(un)plug of vcpus: + * - plug in inactive vcpus/uplug active rather than rewriting state + * - fix hotpluggable state + */ +static void +qemuDomainSetVcpusConfig(virDomainDefPtr def, + unsigned int nvcpus, + bool hotpluggable) +{ + virDomainVcpuDefPtr vcpu; + size_t curvcpus = virDomainDefGetVcpus(def); + size_t maxvcpus = virDomainDefGetVcpusMax(def); + size_t i; + + /* ordering information may become invalid, thus clear it */ + virDomainDefVcpuOrderClear(def); + + if (curvcpus == nvcpus) + return; + + if (curvcpus < nvcpus) { + for (i = 0; i < maxvcpus; i++) { + vcpu = virDomainDefGetVcpu(def, i); + + if (!vcpu) + continue; + + if (vcpu->online) { + /* non-hotpluggable vcpus need to be clustered at the beggining, + * thus we need to force vcpus to be hotpluggable when we find + * vcpus that are hotpluggable and online prior to the ones + * we are going to add */ + if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) + hotpluggable = true; + + continue; + } + + vcpu->online = true; + if (hotpluggable) { + vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; + def->individualvcpus = true; + } else { + vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO; + } + + if (++curvcpus == nvcpus) + break; + } + } else { + for (i = maxvcpus; i != 0; i--) { + vcpu = virDomainDefGetVcpu(def, i - 1); + + if (!vcpu || !vcpu->online) + continue; + + vcpu->online = false; + vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; + + if (--curvcpus == nvcpus) + break; + } + } +} + + +int +qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr def, + virDomainDefPtr persistentDef, + unsigned int nvcpus, + bool hotpluggable) +{ + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virBitmapPtr vcpumap = NULL; + bool enable; + int ret = -1; + + if (def && nvcpus > virDomainDefGetVcpusMax(def)) { + virReportError(VIR_ERR_INVALID_ARG, + _("requested vcpus is greater than max allowable" + " vcpus for the live domain: %u > %u"), + nvcpus, virDomainDefGetVcpusMax(def)); + goto cleanup; + } + + if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) { + virReportError(VIR_ERR_INVALID_ARG, + _("requested vcpus is greater than max allowable" + " vcpus for the persistent domain: %u > %u"), + nvcpus, virDomainDefGetVcpusMax(persistentDef)); + goto cleanup; + } + + if (def) { + if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, + &enable))) + goto cleanup; + + if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) + goto cleanup; + } + + if (persistentDef) { + qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); + + if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virBitmapFree(vcpumap); + virObjectUnref(cfg); + return ret; +} diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 85ec72470..13242eec9 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -136,4 +136,11 @@ bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm, const char *devAlias, qemuDomainUnpluggingDeviceStatus status); +int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr def, + virDomainDefPtr persistentDef, + unsigned int nvcpus, + bool hotpluggable); + #endif /* __QEMU_HOTPLUG_H__ */ -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:15AM +0100, Peter Krempa wrote:
Move all the worker code into the appropriate file. This will also allow testing of cpu hotplug. --- src/qemu/qemu_driver.c | 339 ------------------------------------------------ src/qemu/qemu_hotplug.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 7 + 3 files changed, 346 insertions(+), 339 deletions(-)
ACK Pavel

--- tests/qemuagenttest.c | 3 +- tests/qemumonitortestutils.c | 101 +++++++++++++++++++++++++++++++++++++------ tests/qemumonitortestutils.h | 4 +- 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 5dfa58eb0..3be745e7c 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -375,7 +375,8 @@ qemuAgentShutdownTestMonitorHandler(qemuMonitorTestPtr test, } if (STRNEQ(cmdname, "guest-shutdown")) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-shutdown", + cmdname); goto cleanup; } diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 3722b0729..fb4f51c54 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -118,17 +118,89 @@ qemuMonitorTestAddResponse(qemuMonitorTestPtr test, } -int -qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test) +static int +qemuMonitorTestAddErrorResponse(qemuMonitorTestPtr test, + const char *usermsg) { - if (test->agent || test->json) { - return qemuMonitorTestAddResponse(test, - "{ \"error\": " - " { \"desc\": \"Unexpected command\", " - " \"class\": \"UnexpectedCommand\" } }"); + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *escapemsg = NULL; + char *jsonmsg = NULL; + const char *monmsg = NULL; + char *tmp; + int ret = -1; + + if (!usermsg) + usermsg = "unexpected command"; + + if (test->json || test->agent) { + virBufferEscape(&buf, '\\', "\"", "%s", usermsg); + if (virBufferCheckError(&buf) < 0) + goto error; + escapemsg = virBufferContentAndReset(&buf); + + /* replace newline/carriage return with space */ + tmp = escapemsg; + while (*tmp) { + if (*tmp == '\r' || *tmp == '\n') + *tmp = ' '; + + tmp++; + } + + /* format the JSON error message */ + if (virAsprintf(&jsonmsg, "{ \"error\": " + " { \"desc\": \"%s\", " + " \"class\": \"UnexpectedCommand\" } }", + escapemsg) < 0) + goto error; + + monmsg = jsonmsg; } else { - return qemuMonitorTestAddResponse(test, "unexpected command"); + monmsg = usermsg; } + + ret = qemuMonitorTestAddResponse(test, monmsg); + + error: + VIR_FREE(escapemsg); + VIR_FREE(jsonmsg); + return ret; +} + + +static int +qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test, + const char *command) +{ + char *msg; + int ret; + + if (virAsprintf(&msg, "unexpected command: '%s'", command) < 0) + return -1; + + ret = qemuMonitorTestAddErrorResponse(test, msg); + + VIR_FREE(msg); + return ret; +} + + +int +qemuMonitorTestAddInvalidCommandResponse(qemuMonitorTestPtr test, + const char *expectedcommand, + const char *actualcommand) +{ + char *msg; + int ret; + + if (virAsprintf(&msg, "expected command '%s' got '%s'", + expectedcommand, actualcommand) < 0) + return -1; + + ret = qemuMonitorTestAddErrorResponse(test, msg); + + VIR_FREE(msg); + return ret; } @@ -181,7 +253,7 @@ qemuMonitorTestProcessCommand(qemuMonitorTestPtr test, VIR_DEBUG("Processing string from monitor handler: '%s", cmdstr); if (test->nitems == 0) { - return qemuMonitorTestAddUnexpectedErrorResponse(test); + return qemuMonitorTestAddUnexpectedErrorResponse(test, cmdstr); } else { qemuMonitorTestItemPtr item = test->items[0]; ret = (item->cb)(test, item, cmdstr); @@ -499,7 +571,8 @@ qemuMonitorTestProcessCommandDefault(qemuMonitorTestPtr test, } if (data->command_name && STRNEQ(data->command_name, cmdname)) - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); else ret = qemuMonitorTestAddResponse(test, data->response); @@ -553,7 +626,7 @@ qemuMonitorTestProcessGuestAgentSync(qemuMonitorTestPtr test, } if (STRNEQ(cmdname, "guest-sync")) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-sync", cmdname); goto cleanup; } @@ -619,7 +692,8 @@ qemuMonitorTestProcessCommandWithArgs(qemuMonitorTestPtr test, if (data->command_name && STRNEQ(data->command_name, cmdname)) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); goto cleanup; } @@ -745,7 +819,8 @@ qemuMonitorTestProcessCommandWithArgStr(qemuMonitorTestPtr test, } if (STRNEQ(data->command_name, cmdname)) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); goto cleanup; } diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 3890cd46f..87c11af47 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -42,7 +42,9 @@ int qemuMonitorTestAddHandler(qemuMonitorTestPtr test, int qemuMonitorTestAddResponse(qemuMonitorTestPtr test, const char *response); -int qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test); +int qemuMonitorTestAddInvalidCommandResponse(qemuMonitorTestPtr test, + const char *expectedcommand, + const char *actualcommand); void *qemuMonitorTestItemGetPrivateData(qemuMonitorTestItemPtr item); -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:16AM +0100, Peter Krempa wrote:
--- tests/qemuagenttest.c | 3 +- tests/qemumonitortestutils.c | 101 +++++++++++++++++++++++++++++++++++++------ tests/qemumonitortestutils.h | 4 +- 3 files changed, 93 insertions(+), 15 deletions(-)
ACK Pavel

Add test monitor infrastructure that will test the commands verbatim rather than trying to do any smart handling. --- tests/qemumonitortestutils.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 5 +++ 2 files changed, 94 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index fb4f51c54..50042f960 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -508,6 +508,7 @@ struct _qemuMonitorTestCommandArgs { struct qemuMonitorTestHandlerData { char *command_name; + char *cmderr; char *response; size_t nargs; qemuMonitorTestCommandArgsPtr args; @@ -529,6 +530,7 @@ qemuMonitorTestHandlerDataFree(void *opaque) } VIR_FREE(data->command_name); + VIR_FREE(data->cmderr); VIR_FREE(data->response); VIR_FREE(data->args); VIR_FREE(data->expectArgs); @@ -606,6 +608,93 @@ qemuMonitorTestAddItem(qemuMonitorTestPtr test, static int +qemuMonitorTestProcessCommandVerbatim(qemuMonitorTestPtr test, + qemuMonitorTestItemPtr item, + const char *cmdstr) +{ + struct qemuMonitorTestHandlerData *data = item->opaque; + char *reformatted = NULL; + char *errmsg = NULL; + int ret = -1; + + /* JSON strings will be reformatted to simplify checking */ + if (test->json || test->agent) { + if (!(reformatted = virJSONStringReformat(cmdstr, false))) + return -1; + + cmdstr = reformatted; + } + + if (STREQ(data->command_name, cmdstr)) { + ret = qemuMonitorTestAddResponse(test, data->response); + } else { + if (data->cmderr) { + if (virAsprintf(&errmsg, "%s: %s", data->cmderr, cmdstr) < 0) + goto cleanup; + + ret = qemuMonitorTestAddErrorResponse(test, errmsg); + } else { + ret = qemuMonitorTestAddInvalidCommandResponse(test, + data->command_name, + cmdstr); + } + } + + cleanup: + VIR_FREE(errmsg); + VIR_FREE(reformatted); + return ret; +} + + +/** + * qemuMonitorTestAddItemVerbatim: + * @test: monitor test object + * @command: full expected command syntax + * @cmderr: possible explanation of expected command (may be NULL) + * @response: full reply of @command + * + * Adds a test command for the simulated monitor. The full syntax is checked + * as specified in @command. For JSON monitor tests formatting/whitespace is + * ignored. If the command on the monitor is not as expected an error containing + * @cmderr is returned. Otherwise @response is put as-is on the monitor. + * + * Returns 0 when command was succesfully added, -1 on error. + */ +int +qemuMonitorTestAddItemVerbatim(qemuMonitorTestPtr test, + const char *command, + const char *cmderr, + const char *response) +{ + struct qemuMonitorTestHandlerData *data; + + if (VIR_ALLOC(data) < 0) + return -1; + + if (VIR_STRDUP(data->response, response) < 0 || + VIR_STRDUP(data->cmderr, cmderr) < 0) + goto error; + + if (test->json || test->agent) + data->command_name = virJSONStringReformat(command, false); + else + ignore_value(VIR_STRDUP(data->command_name, command)); + + if (!data->command_name) + goto error; + + return qemuMonitorTestAddHandler(test, + qemuMonitorTestProcessCommandVerbatim, + data, qemuMonitorTestHandlerDataFree); + + error: + qemuMonitorTestHandlerDataFree(data); + return -1; +} + + +static int qemuMonitorTestProcessGuestAgentSync(qemuMonitorTestPtr test, qemuMonitorTestItemPtr item ATTRIBUTE_UNUSED, const char *cmdstr) diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 87c11af47..147996a08 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -54,6 +54,11 @@ int qemuMonitorTestAddItem(qemuMonitorTestPtr test, const char *command_name, const char *response); +int qemuMonitorTestAddItemVerbatim(qemuMonitorTestPtr test, + const char *command, + const char *cmderr, + const char *response); + int qemuMonitorTestAddAgentSyncResponse(qemuMonitorTestPtr test); int qemuMonitorTestAddItemParams(qemuMonitorTestPtr test, -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:17AM +0100, Peter Krempa wrote:
Add test monitor infrastructure that will test the commands verbatim rather than trying to do any smart handling. --- tests/qemumonitortestutils.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 5 +++ 2 files changed, 94 insertions(+)
diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index fb4f51c54..50042f960 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -508,6 +508,7 @@ struct _qemuMonitorTestCommandArgs {
struct qemuMonitorTestHandlerData { char *command_name; + char *cmderr; char *response; size_t nargs; qemuMonitorTestCommandArgsPtr args; @@ -529,6 +530,7 @@ qemuMonitorTestHandlerDataFree(void *opaque) }
VIR_FREE(data->command_name); + VIR_FREE(data->cmderr); VIR_FREE(data->response); VIR_FREE(data->args); VIR_FREE(data->expectArgs); @@ -606,6 +608,93 @@ qemuMonitorTestAddItem(qemuMonitorTestPtr test,
static int +qemuMonitorTestProcessCommandVerbatim(qemuMonitorTestPtr test, + qemuMonitorTestItemPtr item, + const char *cmdstr) +{ + struct qemuMonitorTestHandlerData *data = item->opaque; + char *reformatted = NULL; + char *errmsg = NULL; + int ret = -1; + + /* JSON strings will be reformatted to simplify checking */ + if (test->json || test->agent) { + if (!(reformatted = virJSONStringReformat(cmdstr, false))) + return -1; + + cmdstr = reformatted; + } + + if (STREQ(data->command_name, cmdstr)) { + ret = qemuMonitorTestAddResponse(test, data->response); + } else { + if (data->cmderr) { + if (virAsprintf(&errmsg, "%s: %s", data->cmderr, cmdstr) < 0) + goto cleanup; + + ret = qemuMonitorTestAddErrorResponse(test, errmsg); + } else { + ret = qemuMonitorTestAddInvalidCommandResponse(test, + data->command_name, + cmdstr); + } + } + + cleanup: + VIR_FREE(errmsg); + VIR_FREE(reformatted); + return ret; +} + + +/** + * qemuMonitorTestAddItemVerbatim: + * @test: monitor test object + * @command: full expected command syntax + * @cmderr: possible explanation of expected command (may be NULL) + * @response: full reply of @command + * + * Adds a test command for the simulated monitor. The full syntax is checked + * as specified in @command. For JSON monitor tests formatting/whitespace is + * ignored. If the command on the monitor is not as expected an error containing + * @cmderr is returned. Otherwise @response is put as-is on the monitor. + * + * Returns 0 when command was succesfully added, -1 on error.
s/succesfully/successfully/ ACK Pavel

Similar to the existing qemuMonitorTestNewFromFile the *Full version will allow to check both commands and supply responses for a better monitor testing. --- tests/qemumonitortestutils.c | 119 +++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 3 ++ 2 files changed, 122 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 50042f960..80136dc14 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1278,6 +1278,125 @@ qemuMonitorTestNewFromFile(const char *fileName, } +static int +qemuMonitorTestFullAddItem(qemuMonitorTestPtr test, + const char *filename, + const char *command, + const char *response, + size_t line) +{ + char *cmderr; + int ret; + + if (virAsprintf(&cmderr, "wrong expected command in %s:%zu: ", + filename, line) < 0) + return -1; + + ret = qemuMonitorTestAddItemVerbatim(test, command, cmderr, response); + + VIR_FREE(cmderr); + return ret; +} + + +/** + * qemuMonitorTestNewFromFileFull: + * @fileName: File name to load monitor replies from + * @driver: qemu driver object + * @vm: domain object (may be null if it's not needed by the test) + * + * Create a JSON test monitor simulator object and fill it with expected command + * sequence and replies specified in @fileName. + * + * The file contains a sequence of JSON commands and reply objects separated by + * empty lines. A command is followed by a reply. The QMP greeting is added + * automatically. + * + * Returns the monitor object on success; NULL on error. + */ +qemuMonitorTestPtr +qemuMonitorTestNewFromFileFull(const char *fileName, + virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuMonitorTestPtr ret = NULL; + char *jsonstr = NULL; + char *tmp; + size_t line = 0; + + char *command = NULL; + char *response = NULL; + size_t commandln = 0; + char *cmderr = NULL; + + if (virTestLoadFile(fileName, &jsonstr) < 0) + return NULL; + + if (!(ret = qemuMonitorTestNew(true, driver->xmlopt, vm, driver, NULL))) + goto cleanup; + + tmp = jsonstr; + command = tmp; + while ((tmp = strchr(tmp, '\n'))) { + bool eof = !tmp[1]; + line++; + + if (*(tmp + 1) != '\n') { + *tmp = ' '; + tmp++; + } else { + /* Cut off a single reply. */ + *(tmp + 1) = '\0'; + + if (response) { + if (qemuMonitorTestFullAddItem(ret, fileName, command, + response, commandln) < 0) + goto error; + command = NULL; + response = NULL; + } + + if (!eof) { + /* Move the @tmp and @singleReply. */ + tmp += 2; + + if (!command) { + commandln = line; + command = tmp; + } else { + response = tmp; + } + } + } + + if (eof) + break; + } + + if (command) { + if (!response) { + virReportError(VIR_ERR_INTERNAL_ERROR, "missing response for command " + "on line '%zu' in '%s'", commandln, fileName); + goto error; + } + + if (qemuMonitorTestFullAddItem(ret, fileName, command, + response, commandln) < 0) + goto error; + } + + cleanup: + VIR_FREE(cmderr); + VIR_FREE(jsonstr); + return ret; + + error: + qemuMonitorTestFree(ret); + ret = NULL; + goto cleanup; +} + + qemuMonitorTestPtr qemuMonitorTestNewAgent(virDomainXMLOptionPtr xmlopt) { diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 147996a08..8b19b37e7 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -85,6 +85,9 @@ qemuMonitorTestPtr qemuMonitorTestNew(bool json, qemuMonitorTestPtr qemuMonitorTestNewFromFile(const char *fileName, virDomainXMLOptionPtr xmlopt, bool simple); +qemuMonitorTestPtr qemuMonitorTestNewFromFileFull(const char *fileName, + virQEMUDriverPtr driver, + virDomainObjPtr vm); qemuMonitorTestPtr qemuMonitorTestNewAgent(virDomainXMLOptionPtr xmlopt); -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:18AM +0100, Peter Krempa wrote:
Similar to the existing qemuMonitorTestNewFromFile the *Full version will allow to check both commands and supply responses for a better monitor testing. --- tests/qemumonitortestutils.c | 119 +++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 3 ++ 2 files changed, 122 insertions(+)
diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 50042f960..80136dc14 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1278,6 +1278,125 @@ qemuMonitorTestNewFromFile(const char *fileName, }
+static int +qemuMonitorTestFullAddItem(qemuMonitorTestPtr test, + const char *filename, + const char *command, + const char *response, + size_t line) +{ + char *cmderr; + int ret; + + if (virAsprintf(&cmderr, "wrong expected command in %s:%zu: ", + filename, line) < 0) + return -1; + + ret = qemuMonitorTestAddItemVerbatim(test, command, cmderr, response); + + VIR_FREE(cmderr); + return ret; +} + + +/** + * qemuMonitorTestNewFromFileFull: + * @fileName: File name to load monitor replies from + * @driver: qemu driver object + * @vm: domain object (may be null if it's not needed by the test) + * + * Create a JSON test monitor simulator object and fill it with expected command + * sequence and replies specified in @fileName. + * + * The file contains a sequence of JSON commands and reply objects separated by + * empty lines. A command is followed by a reply. The QMP greeting is added + * automatically. + * + * Returns the monitor object on success; NULL on error. + */ +qemuMonitorTestPtr +qemuMonitorTestNewFromFileFull(const char *fileName, + virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuMonitorTestPtr ret = NULL; + char *jsonstr = NULL; + char *tmp; + size_t line = 0; + + char *command = NULL; + char *response = NULL; + size_t commandln = 0; + char *cmderr = NULL;
The *cmderr* is not used anywhere so remove it. ACK Pavel

The cpu hotplug operation is rather complex so the testing code needs to provide quite lot of data and monitor conversations to successfully test it. The code mainly tests the selection of cpus according to the target count request. --- tests/qemuhotplugtest.c | 189 +++++++++ .../qemuhotplugtestcpus/x86-modern-bulk-domain.xml | 21 + .../x86-modern-bulk-monitor.json | 471 +++++++++++++++++++++ .../x86-modern-bulk-result-conf.xml | 40 ++ .../x86-modern-bulk-result-live.xml | 48 +++ 5 files changed, 769 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0a845394..32aaf5718 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -347,11 +347,187 @@ testQemuHotplug(const void *data) return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1; } + +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) +{ + 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); + + virObjectUnref(data->vm); + qemuMonitorTestFree(data->mon); +} + + +static struct testQemuHotplugCpuData * +testQemuHotplugCpuPrepare(const char *test, + bool modern) +{ + 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; + + if (qemuHotplugCreateObjects(driver.xmlopt, &data->vm, data->xml_dom, true, + "cpu-hotplug-test-domain") < 0) + goto error; + + if (!(caps = virQEMUDriverGetCapabilities(&driver, false))) + goto error; + + /* create vm->newDef */ + data->vm->persistent = true; + if (virDomainObjSetDefTransient(caps, driver.xmlopt, data->vm) < 0) + 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, + &driver, data->vm))) + goto error; + + priv->mon = qemuMonitorTestGetMonitor(data->mon); + priv->monJSON = true; + virObjectUnlock(priv->mon); + + if (qemuDomainRefreshVcpuInfo(&driver, data->vm, 0, false) < 0) + goto error; + + 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; + bool modern; + bool fail; +}; + + +static int +testQemuHotplugCpuGroup(const void *opaque) +{ + const struct testQemuHotplugCpuParams *params = opaque; + struct testQemuHotplugCpuData *data = NULL; + int ret = -1; + int rc; + + if (!(data = testQemuHotplugCpuPrepare(params->test, params->modern))) + 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; +} + + static int mymain(void) { int ret = 0; struct qemuHotplugTestData data = {0}; + struct testQemuHotplugCpuParams cpudata; #if !WITH_YAJL fputs("libvirt not compiled with yajl, skipping this test\n", stderr); @@ -584,6 +760,19 @@ mymain(void) "device_del", QMP_OK, "object-del", QMP_OK); +#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; \ + } while (0) + + DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); + qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml new file mode 100644 index 000000000..1c2a5b131 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml @@ -0,0 +1,21 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='5'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="4" cores="2" threads="1"/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json b/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json new file mode 100644 index 000000000..4dcb6a2cf --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json @@ -0,0 +1,471 @@ +{"execute":"query-hotpluggable-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-2"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + } + ], + "id": "libvirt-22" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "qemu64-x86_64-cpu", + "id": "vcpu5", + "socket-id": 1, + "core-id": 0, + "thread-id": 1 + }, + "id": "libvirt-3" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-4"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu5", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + } + ], + "id": "libvirt-22" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "qemu64-x86_64-cpu", + "id": "vcpu6", + "socket-id": 1, + "core-id": 1, + "thread-id": 0 + }, + "id": "libvirt-6" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-7"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu6", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu5", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-8"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + }, + { + "arch": "x86", + "current": false, + "CPU": 6, + "qom_path": "/machine/peripheral/vcpu6", + "pc": -2130415978, + "halted": true, + "thread_id": 518298 + } + ], + "id": "libvirt-22" +} diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml new file mode 100644 index 000000000..5c1d18b8f --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml @@ -0,0 +1,40 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no'/> + <vcpu id='1' enabled='yes' hotpluggable='no'/> + <vcpu id='2' enabled='yes' hotpluggable='no'/> + <vcpu id='3' enabled='yes' hotpluggable='no'/> + <vcpu id='4' enabled='yes' hotpluggable='no'/> + <vcpu id='5' enabled='yes' hotpluggable='yes'/> + <vcpu id='6' enabled='yes' hotpluggable='yes'/> + <vcpu id='7' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml new file mode 100644 index 000000000..50fd9eab6 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml @@ -0,0 +1,48 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='1' enabled='yes' hotpluggable='no' order='2'/> + <vcpu id='2' enabled='yes' hotpluggable='no' order='3'/> + <vcpu id='3' enabled='yes' hotpluggable='no' order='4'/> + <vcpu id='4' enabled='yes' hotpluggable='no' order='5'/> + <vcpu id='5' enabled='yes' hotpluggable='yes' order='6'/> + <vcpu id='6' enabled='yes' hotpluggable='yes' order='7'/> + <vcpu id='7' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:19AM +0100, Peter Krempa wrote:
The cpu hotplug operation is rather complex so the testing code needs to provide quite lot of data and monitor conversations to successfully test it. The code mainly tests the selection of cpus according to the target count request. --- tests/qemuhotplugtest.c | 189 +++++++++ .../qemuhotplugtestcpus/x86-modern-bulk-domain.xml | 21 + .../x86-modern-bulk-monitor.json | 471 +++++++++++++++++++++ .../x86-modern-bulk-result-conf.xml | 40 ++ .../x86-modern-bulk-result-live.xml | 48 +++ 5 files changed, 769 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0a845394..32aaf5718 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -347,11 +347,187 @@ testQemuHotplug(const void *data) return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1; }
+ +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) +{ + 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); + + virObjectUnref(data->vm); + qemuMonitorTestFree(data->mon); +} + + +static struct testQemuHotplugCpuData * +testQemuHotplugCpuPrepare(const char *test, + bool modern) +{ + 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; + + if (qemuHotplugCreateObjects(driver.xmlopt, &data->vm, data->xml_dom, true, + "cpu-hotplug-test-domain") < 0) + goto error; + + if (!(caps = virQEMUDriverGetCapabilities(&driver, false))) + goto error; + + /* create vm->newDef */ + data->vm->persistent = true; + if (virDomainObjSetDefTransient(caps, driver.xmlopt, data->vm) < 0) + 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, + &driver, data->vm))) + goto error; + + priv->mon = qemuMonitorTestGetMonitor(data->mon); + priv->monJSON = true; + virObjectUnlock(priv->mon); + + if (qemuDomainRefreshVcpuInfo(&driver, data->vm, 0, false) < 0) + goto error; + + 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; + bool modern; + bool fail; +}; + + +static int +testQemuHotplugCpuGroup(const void *opaque) +{ + const struct testQemuHotplugCpuParams *params = opaque; + struct testQemuHotplugCpuData *data = NULL; + int ret = -1; + int rc; + + if (!(data = testQemuHotplugCpuPrepare(params->test, params->modern))) + 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);
I would put apostrophes around %s. ACK Pavel

Test that the old approach generates correct commands. --- tests/qemuhotplugtest.c | 1 + tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml | 21 +++ .../qemuhotplugtestcpus/x86-old-bulk-monitor.json | 193 +++++++++++++++++++++ .../x86-old-bulk-result-conf.xml | 30 ++++ .../x86-old-bulk-result-live.xml | 38 ++++ 5 files changed, 283 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 32aaf5718..f0817eb86 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -772,6 +772,7 @@ mymain(void) } while (0) DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); + DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false); qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml new file mode 100644 index 000000000..1c2a5b131 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml @@ -0,0 +1,21 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='5'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="4" cores="2" threads="1"/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json b/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json new file mode 100644 index 000000000..6caf8cc18 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json @@ -0,0 +1,193 @@ +{"execute":"query-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + } + ], + "id": "libvirt-22" +} + +{"execute":"cpu-add","arguments":{"id":5},"id":"libvirt-2"} + +{"return": {}} + +{"execute":"query-cpus","id":"libvirt-3"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + } + ], + "id": "libvirt-22" +} + +{"execute":"cpu-add","arguments":{"id":6},"id":"libvirt-4"} + +{"return": {}} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + }, + { + "arch": "x86", + "current": false, + "CPU": 6, + "qom_path": "/machine/peripheral/vcpu6", + "pc": -2130415978, + "halted": true, + "thread_id": 518298 + } + ], + "id": "libvirt-22" +} diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml new file mode 100644 index 000000000..1ccbf2b51 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml new file mode 100644 index 000000000..5286267e7 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml @@ -0,0 +1,38 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:20AM +0100, Peter Krempa wrote:
Test that the old approach generates correct commands. --- tests/qemuhotplugtest.c | 1 + tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml | 21 +++ .../qemuhotplugtestcpus/x86-old-bulk-monitor.json | 193 +++++++++++++++++++++ .../x86-old-bulk-result-conf.xml | 30 ++++ .../x86-old-bulk-result-live.xml | 38 ++++ 5 files changed, 283 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml
ACK Pavel

Add a positive test and few negative tests. --- tests/qemuhotplugtest.c | 4 + tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml | 20 + tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json | 593 +++++++++++++++++++++ .../qemuhotplugtestcpus/ppc64-bulk-result-conf.xml | 64 +++ .../qemuhotplugtestcpus/ppc64-bulk-result-live.xml | 72 +++ 5 files changed, 753 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0817eb86..44a5e69ae 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -773,6 +773,10 @@ mymain(void) DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 24, true, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 15, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 23, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 25, true, true); qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml new file mode 100644 index 000000000..eb04e42b6 --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml @@ -0,0 +1,20 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='8'>32</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="1" cores="4" threads="8"/> + </cpu> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json b/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json new file mode 100644 index 000000000..c139426b7 --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json @@ -0,0 +1,593 @@ +{"execute":"query-hotpluggable-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-2"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018422360608, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + } + ], + "id": "libvirt-12" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "host-spapr-cpu-core", + "id": "vcpu8", + "core-id": 8 + }, + "id": "libvirt-3" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-4"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu1", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + }, + { + "arch": "ppc", + "current": false, + "CPU": 8, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[0]", + "halted": false, + "thread_id": 22131 + }, + { + "arch": "ppc", + "current": false, + "CPU": 9, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[1]", + "halted": false, + "thread_id": 22132 + }, + { + "arch": "ppc", + "current": false, + "CPU": 10, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[2]", + "halted": false, + "thread_id": 22133 + }, + { + "arch": "ppc", + "current": false, + "CPU": 11, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[3]", + "halted": false, + "thread_id": 22134 + }, + { + "arch": "ppc", + "current": false, + "CPU": 12, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[4]", + "halted": false, + "thread_id": 22135 + }, + { + "arch": "ppc", + "current": false, + "CPU": 13, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[5]", + "halted": false, + "thread_id": 22136 + }, + { + "arch": "ppc", + "current": false, + "CPU": 14, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[6]", + "halted": false, + "thread_id": 22137 + }, + { + "arch": "ppc", + "current": false, + "CPU": 15, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[7]", + "halted": false, + "thread_id": 22138 + } + ], + "id": "libvirt-14" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "host-spapr-cpu-core", + "id": "vcpu16", + "core-id": 16 + }, + "id": "libvirt-6" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-7"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu2", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu1", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-8"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018422360576, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018422360596, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018422360596, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + }, + { + "arch": "ppc", + "current": false, + "CPU": 8, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[0]", + "halted": false, + "thread_id": 22131 + }, + { + "arch": "ppc", + "current": false, + "CPU": 9, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[1]", + "halted": false, + "thread_id": 22132 + }, + { + "arch": "ppc", + "current": false, + "CPU": 10, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[2]", + "halted": false, + "thread_id": 22133 + }, + { + "arch": "ppc", + "current": false, + "CPU": 11, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[3]", + "halted": false, + "thread_id": 22134 + }, + { + "arch": "ppc", + "current": false, + "CPU": 12, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[4]", + "halted": false, + "thread_id": 22135 + }, + { + "arch": "ppc", + "current": false, + "CPU": 13, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[5]", + "halted": false, + "thread_id": 22136 + }, + { + "arch": "ppc", + "current": false, + "CPU": 14, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[6]", + "halted": false, + "thread_id": 22137 + }, + { + "arch": "ppc", + "current": false, + "CPU": 15, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[7]", + "halted": false, + "thread_id": 22138 + }, + { + "arch": "ppc", + "current": false, + "CPU": 16, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[0]", + "halted": false, + "thread_id": 22223 + }, + { + "arch": "ppc", + "current": false, + "CPU": 17, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[1]", + "halted": false, + "thread_id": 22224 + }, + { + "arch": "ppc", + "current": false, + "CPU": 18, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[2]", + "halted": false, + "thread_id": 22225 + }, + { + "arch": "ppc", + "current": false, + "CPU": 19, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[3]", + "halted": false, + "thread_id": 22226 + }, + { + "arch": "ppc", + "current": false, + "CPU": 20, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[4]", + "halted": false, + "thread_id": 22227 + }, + { + "arch": "ppc", + "current": false, + "CPU": 21, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[5]", + "halted": false, + "thread_id": 22228 + }, + { + "arch": "ppc", + "current": false, + "CPU": 22, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[6]", + "halted": false, + "thread_id": 22229 + }, + { + "arch": "ppc", + "current": false, + "CPU": 23, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[7]", + "halted": false, + "thread_id": 22230 + } + ], + "id": "libvirt-17" +} diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml new file mode 100644 index 000000000..bd792eaae --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml @@ -0,0 +1,64 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='24'>32</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no'/> + <vcpu id='1' enabled='yes' hotpluggable='no'/> + <vcpu id='2' enabled='yes' hotpluggable='no'/> + <vcpu id='3' enabled='yes' hotpluggable='no'/> + <vcpu id='4' enabled='yes' hotpluggable='no'/> + <vcpu id='5' enabled='yes' hotpluggable='no'/> + <vcpu id='6' enabled='yes' hotpluggable='no'/> + <vcpu id='7' enabled='yes' hotpluggable='no'/> + <vcpu id='8' enabled='yes' hotpluggable='yes'/> + <vcpu id='9' enabled='yes' hotpluggable='yes'/> + <vcpu id='10' enabled='yes' hotpluggable='yes'/> + <vcpu id='11' enabled='yes' hotpluggable='yes'/> + <vcpu id='12' enabled='yes' hotpluggable='yes'/> + <vcpu id='13' enabled='yes' hotpluggable='yes'/> + <vcpu id='14' enabled='yes' hotpluggable='yes'/> + <vcpu id='15' enabled='yes' hotpluggable='yes'/> + <vcpu id='16' enabled='yes' hotpluggable='yes'/> + <vcpu id='17' enabled='yes' hotpluggable='yes'/> + <vcpu id='18' enabled='yes' hotpluggable='yes'/> + <vcpu id='19' enabled='yes' hotpluggable='yes'/> + <vcpu id='20' enabled='yes' hotpluggable='yes'/> + <vcpu id='21' enabled='yes' hotpluggable='yes'/> + <vcpu id='22' enabled='yes' hotpluggable='yes'/> + <vcpu id='23' enabled='yes' hotpluggable='yes'/> + <vcpu id='24' enabled='no' hotpluggable='yes'/> + <vcpu id='25' enabled='no' hotpluggable='yes'/> + <vcpu id='26' enabled='no' hotpluggable='yes'/> + <vcpu id='27' enabled='no' hotpluggable='yes'/> + <vcpu id='28' enabled='no' hotpluggable='yes'/> + <vcpu id='29' enabled='no' hotpluggable='yes'/> + <vcpu id='30' enabled='no' hotpluggable='yes'/> + <vcpu id='31' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='1' cores='4' threads='8'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml new file mode 100644 index 000000000..da40fec89 --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml @@ -0,0 +1,72 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='24'>32</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='1' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='2' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='3' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='4' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='5' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='6' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='7' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='8' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='9' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='10' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='11' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='12' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='13' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='14' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='15' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='16' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='17' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='18' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='19' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='20' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='21' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='22' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='23' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='24' enabled='no' hotpluggable='yes'/> + <vcpu id='25' enabled='no' hotpluggable='yes'/> + <vcpu id='26' enabled='no' hotpluggable='yes'/> + <vcpu id='27' enabled='no' hotpluggable='yes'/> + <vcpu id='28' enabled='no' hotpluggable='yes'/> + <vcpu id='29' enabled='no' hotpluggable='yes'/> + <vcpu id='30' enabled='no' hotpluggable='yes'/> + <vcpu id='31' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='1' cores='4' threads='8'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.11.0

On Wed, Jan 11, 2017 at 10:48:21AM +0100, Peter Krempa wrote:
Add a positive test and few negative tests. --- tests/qemuhotplugtest.c | 4 + tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml | 20 + tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json | 593 +++++++++++++++++++++ .../qemuhotplugtestcpus/ppc64-bulk-result-conf.xml | 64 +++ .../qemuhotplugtestcpus/ppc64-bulk-result-live.xml | 72 +++ 5 files changed, 753 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0817eb86..44a5e69ae 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -773,6 +773,10 @@ mymain(void)
DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 24, true, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 15, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 23, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 25, true, true);
Even though there is only modern cpu hotplug on ppc64 I would put the modern into the test name just to make it clear that it tests modern cpu hotplug. ACK Pavel
participants (2)
-
Pavel Hrdina
-
Peter Krempa