[libvirt] [PATCH 0/6] tests: Add qemucapsprobe helper

Adding new *.replies files for qemucapabilitiestest or updating the files when libvirt adds an additional QMP command into the probing process is quite painful. The goal of the new qemucapsprobe command is to make this process as easy as tests/qemucapsprobe /path/to/qemu/binary >caps.replies Jiri Denemark (6): tests: Create a shared library with qemu driver tests: Decouple preload code from main() qemu: Make virQEMUCapsNewForBinary usable from tests qemu: Make qemuMonitorJSONIOProcessLine available for tests virjson: Make pretty format more compact tests: Add qemucapsprobe helper src/qemu/qemu_capabilities.c | 38 ++- src/qemu/qemu_capspriv.h | 8 + src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_json.h | 4 + src/util/virjson.c | 4 +- tests/Makefile.am | 23 ++ tests/qemucapabilitiestest.c | 5 + tests/qemucapsprobe.c | 82 +++++++ tests/qemucapsprobemock.c | 93 ++++++++ tests/testutils.h | 9 +- .../virnetdaemondata/output-data-admin-nomdns.json | 254 ++++++++++----------- .../output-data-admin-server-names.json | 254 ++++++++++----------- .../virnetdaemondata/output-data-anon-clients.json | 128 +++++------ tests/virnetdaemondata/output-data-client-ids.json | 128 +++++------ .../output-data-client-timestamp.json | 132 +++++------ .../output-data-initial-nomdns.json | 128 +++++------ tests/virnetdaemondata/output-data-initial.json | 130 +++++------ .../output-data-no-keepalive-required.json | 254 ++++++++++----------- 18 files changed, 960 insertions(+), 716 deletions(-) create mode 100644 tests/qemucapsprobe.c create mode 100644 tests/qemucapsprobemock.c -- 2.8.2

Currently all qemu driver tests are statically linked to qemu driver library, which makes it impossible to mock any API from the library. This patch creates a shared qemu driver library which can be used instead of the static one. NB we can't use libvirt_driver_qemu.so directly since it is linked with -module and it is supposed to be dlopened. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 6d8fa00..3a9ca76 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -51,6 +51,11 @@ MOCKLIBS_LDFLAGS = -module -avoid-version \ -rpath /evil/libtool/hack/to/force/shared/lib/creation \ $(MINGW_EXTRA_LDFLAGS) +QEMULIB_LDFLAGS = \ + -avoid-version \ + -rpath /evil/libtool/hack/to/force/shared/lib/creation \ + $(MINGW_EXTRA_LDFLAGS) + if WITH_DRIVER_MODULES INCLUDES += \ -DTEST_DRIVER_DIR=\"$(top_builddir)/src/.libs\" @@ -418,6 +423,7 @@ test_libraries = libshunload.la \ $(NULL) if WITH_QEMU test_libraries += libqemumonitortestutils.la \ + libqemutestdriver.la \ qemuxml2argvmock.la \ qemucaps2xmlmock.la \ $(NULL) @@ -546,6 +552,10 @@ if WITH_DTRACE_PROBES qemu_LDADDS += ../src/libvirt_qemu_probes.lo endif WITH_DTRACE_PROBES +libqemutestdriver_la_SOURCES = +libqemutestdriver_la_LDFLAGS = $(QEMULIB_LDFLAGS) +libqemutestdriver_la_LIBADD = $(qemu_LDADDS) + qemuxml2argvtest_SOURCES = \ qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h -- 2.8.2

On Wed, May 04, 2016 at 17:09:47 +0200, Jiri Denemark wrote:
Currently all qemu driver tests are statically linked to qemu driver library, which makes it impossible to mock any API from the library. This patch creates a shared qemu driver library which can be used instead of the static one.
NB we can't use libvirt_driver_qemu.so directly since it is linked with -module and it is supposed to be dlopened.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+)
ACK

The new VIRT_TEST_PRELOAD macro does not force the caller to create a special main function which would need to be called through virtTestMain(). Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/testutils.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/testutils.h b/tests/testutils.h index 0417a0b..123a4fb 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -110,8 +110,8 @@ int virtTestMain(int argc, return virtTestMain(argc, argv, func); \ } -# define VIRT_TEST_MAIN_PRELOAD(func, lib) \ - int main(int argc, char **argv) { \ +# define VIRT_TEST_PRELOAD(lib) \ + do { \ const char *preload = getenv("LD_PRELOAD"); \ if (preload == NULL || strstr(preload, lib) == NULL) { \ char *newenv; \ @@ -128,6 +128,11 @@ int virtTestMain(int argc, setenv("LD_PRELOAD", newenv, 1); \ execv(argv[0], argv); \ } \ + } while (0) + +# define VIRT_TEST_MAIN_PRELOAD(func, lib) \ + int main(int argc, char **argv) { \ + VIRT_TEST_PRELOAD(lib); \ return virtTestMain(argc, argv, func); \ } -- 2.8.2

On Wed, May 04, 2016 at 17:09:48 +0200, Jiri Denemark wrote:
The new VIRT_TEST_PRELOAD macro does not force the caller to create a special main function which would need to be called through virtTestMain().
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/testutils.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
ACK

virQEMUCapsNewForBinary unconditionally loads data from cache and probes using both QMP and -help parsing, which is suboptimal when we want to use it in tests. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 38 +++++++++++++++++++++++++++++++------- src/qemu/qemu_capspriv.h | 8 ++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 65c3d69..c2ba69d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3713,11 +3713,13 @@ virQEMUCapsLogProbeFailure(const char *binary) } -virQEMUCapsPtr virQEMUCapsNewForBinary(const char *binary, - const char *libDir, - const char *cacheDir, - uid_t runUid, - gid_t runGid) +virQEMUCapsPtr +virQEMUCapsNewForBinaryInternal(const char *binary, + const char *libDir, + const char *cacheDir, + uid_t runUid, + gid_t runGid, + bool qmpOnly) { virQEMUCapsPtr qemuCaps; struct stat sb; @@ -3749,7 +3751,9 @@ virQEMUCapsPtr virQEMUCapsNewForBinary(const char *binary, goto error; } - if ((rv = virQEMUCapsInitCached(qemuCaps, cacheDir)) < 0) + if (!cacheDir) + rv = 0; + else if ((rv = virQEMUCapsInitCached(qemuCaps, cacheDir)) < 0) goto error; if (rv == 0) { @@ -3758,13 +3762,22 @@ virQEMUCapsPtr virQEMUCapsNewForBinary(const char *binary, goto error; } + if (qmpOnly && !qemuCaps->usedQMP) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to probe QEMU binary with QMP: %s"), + qmperr ? qmperr : _("unknown error")); + virQEMUCapsLogProbeFailure(binary); + goto error; + } + if (!qemuCaps->usedQMP && virQEMUCapsInitHelp(qemuCaps, runUid, runGid, qmperr) < 0) { virQEMUCapsLogProbeFailure(binary); goto error; } - if (virQEMUCapsRememberCached(qemuCaps, cacheDir) < 0) + if (cacheDir && + virQEMUCapsRememberCached(qemuCaps, cacheDir) < 0) goto error; } @@ -3778,6 +3791,17 @@ virQEMUCapsPtr virQEMUCapsNewForBinary(const char *binary, return NULL; } +virQEMUCapsPtr +virQEMUCapsNewForBinary(const char *binary, + const char *libDir, + const char *cacheDir, + uid_t runUid, + gid_t runGid) +{ + return virQEMUCapsNewForBinaryInternal(binary, libDir, cacheDir, + runUid, runGid, false); +} + bool virQEMUCapsIsValid(virQEMUCapsPtr qemuCaps) { diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h index e4610bb..2a5d8d1 100644 --- a/src/qemu/qemu_capspriv.h +++ b/src/qemu/qemu_capspriv.h @@ -37,4 +37,12 @@ struct _virQEMUCapsCache { gid_t runGid; }; +virQEMUCapsPtr +virQEMUCapsNewForBinaryInternal(const char *binary, + const char *libDir, + const char *cacheDir, + uid_t runUid, + gid_t runGid, + bool qmpOnly); + #endif -- 2.8.2

On Wed, May 04, 2016 at 17:09:49 +0200, Jiri Denemark wrote:
virQEMUCapsNewForBinary unconditionally loads data from cache and probes using both QMP and -help parsing, which is suboptimal when we want to use it in tests.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 38 +++++++++++++++++++++++++++++++------- src/qemu/qemu_capspriv.h | 8 ++++++++ 2 files changed, 39 insertions(+), 7 deletions(-)
ACK

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_json.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 51fa790..ce2f908 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -180,7 +180,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon, return 0; } -static int +int qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon, const char *line, qemuMonitorMessagePtr msg) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index b7aff73..b207e3c 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -32,6 +32,10 @@ # include "cpu/cpu.h" # include "util/virgic.h" +int qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon, + const char *line, + qemuMonitorMessagePtr msg); + int qemuMonitorJSONIOProcess(qemuMonitorPtr mon, const char *data, size_t len, -- 2.8.2

On Wed, May 04, 2016 at 17:09:50 +0200, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_json.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-)
ACK

json_reformat uses two spaces for when indenting nested objects, let's do the same. The result of virJSONValueToString will be exactly the same as json_reformat would produce. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/util/virjson.c | 4 +- .../virnetdaemondata/output-data-admin-nomdns.json | 254 ++++++++++----------- .../output-data-admin-server-names.json | 254 ++++++++++----------- .../virnetdaemondata/output-data-anon-clients.json | 128 +++++------ tests/virnetdaemondata/output-data-client-ids.json | 128 +++++------ .../output-data-client-timestamp.json | 132 +++++------ .../output-data-initial-nomdns.json | 128 +++++------ tests/virnetdaemondata/output-data-initial.json | 130 +++++------ .../output-data-no-keepalive-required.json | 254 ++++++++++----------- 9 files changed, 706 insertions(+), 706 deletions(-) diff --git a/src/util/virjson.c b/src/util/virjson.c index ae6362b..1022cfc 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1756,7 +1756,7 @@ virJSONValueToString(virJSONValuePtr object, char *ret = NULL; yajl_size_t len; # ifndef WITH_YAJL2 - yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "}; + yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "}; # endif VIR_DEBUG("object=%p", object); @@ -1765,7 +1765,7 @@ virJSONValueToString(virJSONValuePtr object, g = yajl_gen_alloc(NULL); if (g) { yajl_gen_config(g, yajl_gen_beautify, pretty ? 1 : 0); - yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " "); + yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " "); yajl_gen_config(g, yajl_gen_validate_utf8, 1); } # else diff --git a/tests/virnetdaemondata/output-data-admin-nomdns.json b/tests/virnetdaemondata/output-data-admin-nomdns.json index ca3acd1..fc960f0 100644 --- a/tests/virnetdaemondata/output-data-admin-nomdns.json +++ b/tests/virnetdaemondata/output-data-admin-nomdns.json @@ -1,132 +1,132 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] }, - "testServer1": { - "min_workers": 2, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] + }, + "testServer1": { + "min_workers": 2, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-admin-server-names.json b/tests/virnetdaemondata/output-data-admin-server-names.json index ca3acd1..fc960f0 100644 --- a/tests/virnetdaemondata/output-data-admin-server-names.json +++ b/tests/virnetdaemondata/output-data-admin-server-names.json @@ -1,132 +1,132 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] }, - "testServer1": { - "min_workers": 2, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] + }, + "testServer1": { + "min_workers": 2, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-anon-clients.json b/tests/virnetdaemondata/output-data-anon-clients.json index 1a1909f..9f1c635 100644 --- a/tests/virnetdaemondata/output-data-anon-clients.json +++ b/tests/virnetdaemondata/output-data-anon-clients.json @@ -1,68 +1,68 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 10, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 10, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-client-ids.json b/tests/virnetdaemondata/output-data-client-ids.json index 7caa2cc..43c61cc 100644 --- a/tests/virnetdaemondata/output-data-client-ids.json +++ b/tests/virnetdaemondata/output-data-client-ids.json @@ -1,68 +1,68 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 10, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 5, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 2, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 3, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 10, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 5, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 2, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 3, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-client-timestamp.json b/tests/virnetdaemondata/output-data-client-timestamp.json index d069997..b706c14 100644 --- a/tests/virnetdaemondata/output-data-client-timestamp.json +++ b/tests/virnetdaemondata/output-data-client-timestamp.json @@ -1,70 +1,70 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 10, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "conn_time": 1234567890, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "conn_time": 1234567890, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 10, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "conn_time": 1234567890, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "conn_time": 1234567890, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-initial-nomdns.json b/tests/virnetdaemondata/output-data-initial-nomdns.json index da007f3..ca6b995 100644 --- a/tests/virnetdaemondata/output-data-initial-nomdns.json +++ b/tests/virnetdaemondata/output-data-initial-nomdns.json @@ -1,68 +1,68 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-initial.json b/tests/virnetdaemondata/output-data-initial.json index cdd02c2..a8df633 100644 --- a/tests/virnetdaemondata/output-data-initial.json +++ b/tests/virnetdaemondata/output-data-initial.json @@ -1,69 +1,69 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "mdnsGroupName": "libvirtTest", - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "mdnsGroupName": "libvirtTest", + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } diff --git a/tests/virnetdaemondata/output-data-no-keepalive-required.json b/tests/virnetdaemondata/output-data-no-keepalive-required.json index ca3acd1..fc960f0 100644 --- a/tests/virnetdaemondata/output-data-no-keepalive-required.json +++ b/tests/virnetdaemondata/output-data-no-keepalive-required.json @@ -1,132 +1,132 @@ { - "servers": { - "testServer0": { - "min_workers": 10, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] }, - "testServer1": { - "min_workers": 2, - "max_workers": 50, - "priority_workers": 5, - "max_clients": 100, - "max_anonymous_clients": 100, - "keepaliveInterval": 120, - "keepaliveCount": 5, - "next_client_id": 3, - "services": [ - { - "auth": 0, - "readonly": true, - "nrequests_client_max": 2, - "socks": [ - { - "fd": 100, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - }, - { - "auth": 2, - "readonly": false, - "nrequests_client_max": 5, - "socks": [ - { - "fd": 101, - "errfd": -1, - "pid": 0, - "isClient": false - } - ] - } - ], - "clients": [ - { - "id": 1, - "auth": 1, - "readonly": true, - "nrequests_max": 15, - "sock": { - "fd": 102, - "errfd": -1, - "pid": -1, - "isClient": true - } - }, - { - "id": 2, - "auth": 2, - "readonly": true, - "nrequests_max": 66, - "sock": { - "fd": 103, - "errfd": -1, - "pid": -1, - "isClient": true - } - } - ] + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] + }, + "testServer1": { + "min_workers": 2, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 100, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] } + } } -- 2.8.2

On Wed, May 04, 2016 at 17:09:51 +0200, Jiri Denemark wrote:
json_reformat uses two spaces for when indenting nested objects, let's do the same. The result of virJSONValueToString will be exactly the same as json_reformat would produce.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
I guess it's good to have an external tool doing the same formatting as libvirt. ACK

On Thu, May 05, 2016 at 09:11:54 +0200, Peter Krempa wrote:
On Wed, May 04, 2016 at 17:09:51 +0200, Jiri Denemark wrote:
json_reformat uses two spaces for when indenting nested objects, let's do the same. The result of virJSONValueToString will be exactly the same as json_reformat would produce.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
I guess it's good to have an external tool doing the same formatting as libvirt.
Yes, you can just update any json manually, filter it through json_reformat and our tests which produce json strings and compare them to the expected string will just be happy with it. I pushed this series, thanks for the review. Jirka

Adding new *.replies files for qemucapabilitiestest or updating the files when libvirt adds an additional QMP command into the probing process is quite painful. The goal of the new qemucapsprobe command is to make this process as easy as tests/qemucapsprobe /path/to/qemu/binary >caps.replies Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/Makefile.am | 13 +++++++ tests/qemucapabilitiestest.c | 5 +++ tests/qemucapsprobe.c | 82 ++++++++++++++++++++++++++++++++++++++ tests/qemucapsprobemock.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 tests/qemucapsprobe.c create mode 100644 tests/qemucapsprobemock.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 3a9ca76..cb72cdf 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -261,6 +261,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest \ qemumonitortest qemumonitorjsontest qemuhotplugtest \ qemuagenttest qemucapabilitiestest qemucaps2xmltest \ qemucommandutiltest +test_helpers += qemucapsprobe endif WITH_QEMU if WITH_LXC @@ -426,6 +427,7 @@ test_libraries += libqemumonitortestutils.la \ libqemutestdriver.la \ qemuxml2argvmock.la \ qemucaps2xmlmock.la \ + qemucapsprobemock.la \ $(NULL) endif WITH_QEMU @@ -603,6 +605,17 @@ qemucapabilitiestest_SOURCES = \ qemucapabilitiestest_LDADD = libqemumonitortestutils.la \ $(qemu_LDADDS) $(LDADDS) +qemucapsprobe_SOURCES = \ + qemucapsprobe.c +qemucapsprobe_LDADD = \ + libqemutestdriver.la $(LDADDS) + +qemucapsprobemock_la_SOURCES = \ + qemucapsprobemock.c +qemucapsprobemock_la_CFLAGS = $(AM_CFLAGS) +qemucapsprobemock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) +qemucapsprobemock_la_LIBADD = $(MOCKLIBS_LIBS) + qemucommandutiltest_SOURCES = \ qemucommandutiltest.c \ testutils.c testutils.h \ diff --git a/tests/qemucapabilitiestest.c b/tests/qemucapabilitiestest.c index ccf0b72..ac9f7a8 100644 --- a/tests/qemucapabilitiestest.c +++ b/tests/qemucapabilitiestest.c @@ -194,6 +194,11 @@ mymain(void) DO_TEST("caps_2.5.0-1"); DO_TEST("caps_2.6.0-1"); + /* + * Run "tests/qemucapsprobe /path/to/qemu/binary >foo.replies" + * to generate updated or new *.replies data files. + */ + qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/qemucapsprobe.c b/tests/qemucapsprobe.c new file mode 100644 index 0000000..9557055 --- /dev/null +++ b/tests/qemucapsprobe.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jiri Denemark <jdenemar@redhat.com> + */ + +#include <config.h> + +#include "testutils.h" +#include "internal.h" +#include "virthread.h" +#include "qemu/qemu_capabilities.h" +#define __QEMU_CAPSRIV_H_ALLOW__ 1 +#include "qemu/qemu_capspriv.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + + +static void +eventLoop(void *opaque ATTRIBUTE_UNUSED) +{ + while (1) { + if (virEventRunDefaultImpl() < 0) { + virErrorPtr err = virGetLastError(); + fprintf(stderr, "Failed to run event loop: %s\n", + err && err->message ? err->message : "Unknown error"); + } + } +} + + +int +main(int argc, char **argv) +{ + virThread thread; + virQEMUCapsPtr caps; + + VIRT_TEST_PRELOAD(abs_builddir "/.libs/qemucapsprobemock.so"); + + if (argc != 2) { + fprintf(stderr, "%s QEMU_binary\n", argv[0]); + return EXIT_FAILURE; + } + + if (virThreadInitialize() < 0 || + virInitialize() < 0) { + fprintf(stderr, "Failed to initialize libvirt"); + return EXIT_FAILURE; + } + + if (virEventRegisterDefaultImpl() < 0) { + virErrorPtr err = virGetLastError(); + fprintf(stderr, "Failed to register event implementation: %s\n", + err && err->message ? err->message: "Unknown error"); + return EXIT_FAILURE; + } + + if (virThreadCreate(&thread, false, eventLoop, NULL) < 0) + return EXIT_FAILURE; + + if (!(caps = virQEMUCapsNewForBinaryInternal(argv[1], "/tmp", NULL, + -1, -1, true))) + return EXIT_FAILURE; + + virObjectUnref(caps); + + return EXIT_SUCCESS; +} diff --git a/tests/qemucapsprobemock.c b/tests/qemucapsprobemock.c new file mode 100644 index 0000000..8ff4de9 --- /dev/null +++ b/tests/qemucapsprobemock.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jiri Denemark <jdenemar@redhat.com> + */ + +#include <config.h> +#include <stdio.h> +#include <dlfcn.h> + +#include "internal.h" +#include "viralloc.h" +#include "virjson.h" +#include "qemu/qemu_monitor.h" +#include "qemu/qemu_monitor_json.h" + +#define REAL_SYM(realFunc) \ + do { \ + if (!realFunc && !(realFunc = dlsym(RTLD_NEXT, __FUNCTION__))) { \ + fprintf(stderr, "Cannot find real '%s' symbol\n", \ + __FUNCTION__); \ + abort(); \ + } \ + } while (0) + + +static int (*realQemuMonitorSend)(qemuMonitorPtr mon, + qemuMonitorMessagePtr msg); + +int +qemuMonitorSend(qemuMonitorPtr mon, + qemuMonitorMessagePtr msg) +{ + REAL_SYM(realQemuMonitorSend); + + fprintf(stderr, "%s", msg->txBuffer); + + return realQemuMonitorSend(mon, msg); +} + + +static int (*realQemuMonitorJSONIOProcessLine)(qemuMonitorPtr mon, + const char *line, + qemuMonitorMessagePtr msg); + +int +qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon, + const char *line, + qemuMonitorMessagePtr msg) +{ + virJSONValuePtr value = NULL; + char *json = NULL; + int ret; + + REAL_SYM(realQemuMonitorJSONIOProcessLine); + + ret = realQemuMonitorJSONIOProcessLine(mon, line, msg); + + if (ret == 0 && + (value = virJSONValueFromString(line)) && + (json = virJSONValueToString(value, 1))) { + char *p; + bool skip = false; + + for (p = json; *p; p++) { + if (skip && *p == '\n') { + continue; + } else { + skip = *p == '\n'; + putchar(*p); + } + } + putchar('\n'); + } + + VIR_FREE(json); + virJSONValueFree(value); + return ret; +} -- 2.8.2

On Wed, May 04, 2016 at 17:09:52 +0200, Jiri Denemark wrote:
Adding new *.replies files for qemucapabilitiestest or updating the files when libvirt adds an additional QMP command into the probing process is quite painful. The goal of the new qemucapsprobe command is to make this process as easy as
tests/qemucapsprobe /path/to/qemu/binary >caps.replies
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
ACK
participants (2)
-
Jiri Denemark
-
Peter Krempa