All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h
@ 2018-07-27 15:13 Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 01/23] libqtest: Document calling conventions Markus Armbruster
                   ` (22 more replies)
  0 siblings, 23 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

This is a reboot of "[PATCH 0/9] tests: Clean up around qmp() and
hmp()" I sent about a year ago.  Back then, Eric folded it into his
"Clean up around qmp() and hmp()" series, which stalled after v4.

My reboot tries to avoid that fate by reducing mission creep.  There
are plenty of good ideas in Eric's series we should mine some day, but
today is not that day.

v2:
* PATCH 01: Comments tweaked, ripple effect on PATCH 05+13
* PATCH 05: Commit message improved [Thomas]
* PATCH 06: Style fix [Philippe]
* PATCH 16+17: Silence a warning
* PATCH 21-23: New

Eric Blake (1):
  libqtest: Document calling conventions

Markus Armbruster (22):
  libqtest: Rename functions to send QMP messages
  libqtest: Clean up how we read device_del messages
  libqtest: Clean up how we read the QMP greeting
  qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail()
  qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail()
  libqtest: Simplify qmp_fd_vsend() a bit
  test-qobject-input-visitor: Avoid format string ambiguity
  qobject: qobject_from_jsonv() is dangerous, hide it away
  tests: Pass literal format strings directly to qmp_FOO()
  tests: Clean up string interpolation into QMP input (simple cases)
  cpu-plug-test: Don't pass integers as strings to device_add
  tests: Clean up string interpolation around qtest_qmp_device_add()
  migration-test: Make wait_command() return the "return" member
  tests: New helper qtest_qmp_receive_success()
  migration-test: Make wait_command() cope with '%'
  migration-test: Clean up string interpolation into QMP, part 1
  migration-test: Clean up string interpolation into QMP, part 2
  migration-test: Clean up string interpolation into QMP, part 3
  libqtest: Enable compile-time format string checking
  libqtest: Remove qtest_qmp_discard_response() & friends
  libqtest: Replace qtest_startf() by qtest_initf()
  libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency

 include/qapi/qmp/qjson.h           |  12 +-
 qobject/qjson.c                    |  89 ++++++++++----
 tests/ahci-test.c                  |  24 ++--
 tests/boot-order-test.c            |  12 +-
 tests/boot-serial-test.c           |  10 +-
 tests/cdrom-test.c                 |   6 +-
 tests/check-qjson.c                |  15 +--
 tests/cpu-plug-test.c              |   7 +-
 tests/drive_del-test.c             |   4 +-
 tests/e1000e-test.c                |   6 +-
 tests/endianness-test.c            |  24 ++--
 tests/fdc-test.c                   |   9 +-
 tests/ide-test.c                   |   6 +-
 tests/ipmi-bt-test.c               |   2 +-
 tests/ivshmem-test.c               |   8 +-
 tests/libqos/ahci.c                |   4 +-
 tests/libqos/pci-pc.c              |   9 +-
 tests/libqos/pci.c                 |   7 --
 tests/libqos/pci.h                 |   2 -
 tests/libqos/usb.c                 |  10 +-
 tests/libqos/usb.h                 |   2 +-
 tests/libqtest.c                   | 189 ++++++++++++++---------------
 tests/libqtest.h                   | 124 ++++++++++---------
 tests/m25p80-test.c                |   6 +-
 tests/m48t59-test.c                |   2 +-
 tests/machine-none-test.c          |   2 +-
 tests/migration-test.c             | 180 ++++++++++++---------------
 tests/numa-test.c                  |   4 +-
 tests/pnv-xscom-test.c             |   8 +-
 tests/prom-env-test.c              |  10 +-
 tests/qmp-test.c                   |  20 +--
 tests/sdhci-test.c                 |   6 +-
 tests/tco-test.c                   |   6 +-
 tests/test-filter-mirror.c         |   5 +-
 tests/test-filter-redirector.c     |   9 +-
 tests/test-qga.c                   | 150 ++++++++++-------------
 tests/test-qobject-input-visitor.c |  19 +--
 tests/tpm-util.c                   |  41 ++-----
 tests/usb-hcd-ehci-test.c          |   2 +-
 tests/usb-hcd-ohci-test.c          |   2 +-
 tests/usb-hcd-uhci-test.c          |   4 +-
 tests/usb-hcd-xhci-test.c          |  10 +-
 tests/vhost-user-test.c            |   6 +-
 tests/virtio-balloon-test.c        |   4 +-
 tests/virtio-blk-test.c            |  32 ++---
 tests/virtio-console-test.c        |  12 +-
 tests/virtio-net-test.c            |   3 +-
 tests/virtio-rng-test.c            |   3 +-
 tests/virtio-scsi-test.c           |   2 +-
 tests/virtio-serial-test.c         |   6 +-
 tests/vmgenid-test.c               |   6 +-
 51 files changed, 554 insertions(+), 587 deletions(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 01/23] libqtest: Document calling conventions
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages Markus Armbruster
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

From: Eric Blake <eblake@redhat.com>

We have two flavors of vararg usage in qtest: qtest_hmp() etc. work
like sprintf(), and qtest_qmp() etc. work like qobject_from_jsonf().
Spell that out in the comments.

Also add GCC_FMT_ATTR() to qtest_hmp() etc. so that the compiler can
flag incorrect use.

We have some cleanup work to do before we can do the same for
qtest_qmp() etc.  This would get us the same better-than-nothing
checking we already have for qobject_from_jsonf(): common incorrect
uses of supported conversion specifications will be flagged
(e.g. passing a double for %d), but use of unsupported ones won't.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Rebased, comment wording tweaked, commit message rewritten]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/libqtest.h | 41 ++++++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/tests/libqtest.h b/tests/libqtest.h
index ac52872cbe..aa2b2cd7c1 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -76,7 +76,9 @@ void qtest_quit(QTestState *s);
 /**
  * qtest_qmp_discard_response:
  * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
@@ -85,7 +87,9 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
 /**
  * qtest_qmp:
  * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and returns the response.
  */
@@ -94,7 +98,9 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
 /**
  * qtest_async_qmp:
  * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
@@ -103,7 +109,9 @@ void qtest_async_qmp(QTestState *s, const char *fmt, ...);
 /**
  * qtest_qmpv_discard_response:
  * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
  * Sends a QMP message to QEMU and consumes the response.
@@ -113,7 +121,9 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
 /**
  * qtest_qmpv:
  * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
  * Sends a QMP message to QEMU and returns the response.
@@ -123,7 +133,9 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
 /**
  * qtest_async_qmpv:
  * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU
+ * @fmt: QMP message to send to QEMU, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
@@ -172,7 +184,7 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 /**
  * qtest_hmpv:
  * @s: #QTestState instance to operate on.
- * @fmt: HMP command to send to QEMU
+ * @fmt: HMP command to send to QEMU, formats arguments like vsprintf().
  * @ap: HMP command arguments
  *
  * Send HMP command to QEMU via QMP's human-monitor-command.
@@ -180,7 +192,8 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
  *
  * Returns: the command's output.  The caller should g_free() it.
  */
-char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap);
+char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
 
 /**
  * qtest_get_irq:
@@ -561,7 +574,9 @@ static inline void qtest_end(void)
 
 /**
  * qmp:
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and returns the response.
  */
@@ -569,7 +584,9 @@ QDict *qmp(const char *fmt, ...);
 
 /**
  * qmp_async:
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
@@ -577,7 +594,9 @@ void qmp_async(const char *fmt, ...);
 
 /**
  * qmp_discard_response:
- * @fmt...: QMP message to send to qemu
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 01/23] libqtest: Document calling conventions Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:24   ` Eric Blake
  2018-07-27 16:35   ` Thomas Huth
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages Markus Armbruster
                   ` (20 subsequent siblings)
  22 siblings, 2 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

The functions to receive messages are called qtest_qmp_receive() and
qmp_receive(), qmp_fd_receive().  The ones to send messages are called
qtest_async_qmp(), qtest_async_qmpv(), qmp_async(), qmp_fd_send(),
qmp_fd_sendv().  Inconsistent.  Rename the *_async* ones to
qmp_send(), qtest_qmp_send(), qtest_qmp_vsend().  Rename
qmp_fd_sendv() to qmp_fd_vsend().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 tests/ahci-test.c   | 10 +++++-----
 tests/libqos/ahci.c |  4 ++--
 tests/libqtest.c    | 20 ++++++++++----------
 tests/libqtest.h    | 14 +++++++-------
 tests/qmp-test.c    | 18 +++++++++---------
 5 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 1a7b761304..7e3491b5bd 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1389,7 +1389,7 @@ static void test_flush_migrate(void)
 
     /* Complete the command */
     s = "{'execute':'cont' }";
-    qmp_async(s);
+    qmp_send(s);
     qmp_eventwait("RESUME");
     ahci_command_wait(dst, cmd);
     ahci_command_verify(dst, cmd);
@@ -1592,8 +1592,8 @@ static void test_atapi_tray(void)
     atapi_wait_tray(false);
 
     /* Remove media */
-    qmp_async("{'execute': 'blockdev-open-tray', "
-               "'arguments': {'id': 'cd0'}}");
+    qmp_send("{'execute': 'blockdev-open-tray',"
+             " 'arguments': {'id': 'cd0'}}");
     atapi_wait_tray(true);
     rsp = qmp_receive();
     qobject_unref(rsp);
@@ -1619,8 +1619,8 @@ static void test_atapi_tray(void)
                                          "'node-name': 'node0' }}");
 
     /* Again, the event shows up first */
-    qmp_async("{'execute': 'blockdev-close-tray', "
-               "'arguments': {'id': 'cd0'}}");
+    qmp_send("{'execute': 'blockdev-close-tray',"
+             " 'arguments': {'id': 'cd0'}}");
     atapi_wait_tray(false);
     rsp = qmp_receive();
     qobject_unref(rsp);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 42d3f76933..63fbc9e3c9 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -674,7 +674,7 @@ void ahci_exec(AHCIQState *ahci, uint8_t port,
         g_assert_cmpint(rc, ==, 0);
     }
     if (opts->error) {
-        qtest_async_qmp(ahci->parent->qts, "{'execute':'cont' }");
+        qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }");
         qtest_qmp_eventwait(ahci->parent->qts, "RESUME");
     }
 
@@ -712,7 +712,7 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port,
 void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd)
 {
     /* Complete the command */
-    qtest_async_qmp(ahci->parent->qts, "{'execute':'cont' }");
+    qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }");
     qtest_qmp_eventwait(ahci->parent->qts, "RESUME");
     ahci_command_wait(ahci, cmd);
     ahci_command_verify(ahci, cmd);
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 098af6aec4..9cb4096639 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -484,7 +484,7 @@ QDict *qtest_qmp_receive(QTestState *s)
  * in the case that they choose to discard all replies up until
  * a particular EVENT is received.
  */
-void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
+void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
 {
     va_list ap_copy;
     QObject *qobj;
@@ -529,21 +529,21 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
     }
 }
 
-void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
+void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
 {
-    qmp_fd_sendv(s->qmp_fd, fmt, ap);
+    qmp_fd_vsend(s->qmp_fd, fmt, ap);
 }
 
 QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
 {
-    qmp_fd_sendv(fd, fmt, ap);
+    qmp_fd_vsend(fd, fmt, ap);
 
     return qmp_fd_receive(fd);
 }
 
 QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
 {
-    qtest_async_qmpv(s, fmt, ap);
+    qtest_qmp_vsend(s, fmt, ap);
 
     /* Receive reply */
     return qtest_qmp_receive(s);
@@ -565,7 +565,7 @@ void qmp_fd_send(int fd, const char *fmt, ...)
     va_list ap;
 
     va_start(ap, fmt);
-    qmp_fd_sendv(fd, fmt, ap);
+    qmp_fd_vsend(fd, fmt, ap);
     va_end(ap);
 }
 
@@ -580,12 +580,12 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
     return response;
 }
 
-void qtest_async_qmp(QTestState *s, const char *fmt, ...)
+void qtest_qmp_send(QTestState *s, const char *fmt, ...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    qtest_async_qmpv(s, fmt, ap);
+    qtest_qmp_vsend(s, fmt, ap);
     va_end(ap);
 }
 
@@ -968,12 +968,12 @@ QDict *qmp(const char *fmt, ...)
     return response;
 }
 
-void qmp_async(const char *fmt, ...)
+void qmp_send(const char *fmt, ...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    qtest_async_qmpv(global_qtest, fmt, ap);
+    qtest_qmp_vsend(global_qtest, fmt, ap);
     va_end(ap);
 }
 
diff --git a/tests/libqtest.h b/tests/libqtest.h
index aa2b2cd7c1..ced95f490a 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -96,7 +96,7 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
 QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
 
 /**
- * qtest_async_qmp:
+ * qtest_qmp_send:
  * @s: #QTestState instance to operate on.
  * @fmt...: QMP message to send to qemu, formatted like
  * qobject_from_jsonf().
@@ -104,7 +104,7 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qtest_async_qmp(QTestState *s, const char *fmt, ...);
+void qtest_qmp_send(QTestState *s, const char *fmt, ...);
 
 /**
  * qtest_qmpv_discard_response:
@@ -131,7 +131,7 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
 QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
 
 /**
- * qtest_async_qmpv:
+ * qtest_qmp_vsend:
  * @s: #QTestState instance to operate on.
  * @fmt: QMP message to send to QEMU, formatted like
  * qobject_from_jsonf().
@@ -140,7 +140,7 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap);
+void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap);
 
 /**
  * qtest_receive:
@@ -583,14 +583,14 @@ static inline void qtest_end(void)
 QDict *qmp(const char *fmt, ...);
 
 /**
- * qmp_async:
+ * qmp_send:
  * @fmt...: QMP message to send to qemu, formatted like
  * qobject_from_jsonf().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qmp_async(const char *fmt, ...);
+void qmp_send(const char *fmt, ...);
 
 /**
  * qmp_discard_response:
@@ -959,7 +959,7 @@ static inline int64_t clock_set(int64_t val)
 }
 
 QDict *qmp_fd_receive(int fd);
-void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
+void qmp_fd_vsend(int fd, const char *fmt, va_list ap);
 void qmp_fd_send(int fd, const char *fmt, ...);
 QDict *qmp_fdv(int fd, const char *fmt, va_list ap);
 QDict *qmp_fd(int fd, const char *fmt, ...);
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index b9774084f8..5eb15daebc 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -159,12 +159,12 @@ static void cleanup_blocking_cmd(void)
 
 static void send_cmd_that_blocks(QTestState *s, const char *id)
 {
-    qtest_async_qmp(s, "{ 'execute': 'blockdev-add',  'id': %s,"
-                    " 'arguments': {"
-                    " 'driver': 'blkdebug', 'node-name': %s,"
-                    " 'config': %s,"
-                    " 'image': { 'driver': 'null-co' } } }",
-                    id, id, fifo_name);
+    qtest_qmp_send(s, "{ 'execute': 'blockdev-add',  'id': %s,"
+                   " 'arguments': {"
+                   " 'driver': 'blkdebug', 'node-name': %s,"
+                   " 'config': %s,"
+                   " 'image': { 'driver': 'null-co' } } }",
+                   id, id, fifo_name);
 }
 
 static void unblock_blocked_cmd(void)
@@ -176,7 +176,7 @@ static void unblock_blocked_cmd(void)
 
 static void send_oob_cmd_that_fails(QTestState *s, const char *id)
 {
-    qtest_async_qmp(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
+    qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
 }
 
 static void recv_cmd_id(QTestState *s, const char *id)
@@ -235,7 +235,7 @@ static void test_qmp_oob(void)
     /* OOB command overtakes slow in-band command */
     setup_blocking_cmd();
     send_cmd_that_blocks(qts, "ib-blocks-1");
-    qtest_async_qmp(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
+    qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
     send_oob_cmd_that_fails(qts, "oob-1");
     recv_cmd_id(qts, "oob-1");
     unblock_blocked_cmd();
@@ -244,7 +244,7 @@ static void test_qmp_oob(void)
 
     /* Even malformed in-band command fails in-band */
     send_cmd_that_blocks(qts, "blocks-2");
-    qtest_async_qmp(qts, "{ 'id': 'err-2' }");
+    qtest_qmp_send(qts, "{ 'id': 'err-2' }");
     unblock_blocked_cmd();
     recv_cmd_id(qts, "blocks-2");
     recv_cmd_id(qts, "err-2");
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 01/23] libqtest: Document calling conventions Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:24   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting Markus Armbruster
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qtest_qmp_device_del() still uses the qmp("") hack to receive a
message, even though we have qmp_receive() since commit 66e0c7b187e.
Put it to use.

Bonus: gets rid of empty format strings.  A step towards compile-time
format string checking without triggering -Wformat-zero-length.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 tests/libqtest.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index 9cb4096639..071d7eb7b1 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1090,7 +1090,7 @@ void qtest_qmp_device_del(const char *id)
     g_assert(response1);
     g_assert(!qdict_haskey(response1, "error"));
 
-    response2 = qmp("");
+    response2 = qmp_receive();
     g_assert(response2);
     g_assert(!qdict_haskey(response2, "error"));
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (2 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:25   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail() Markus Armbruster
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qtest_init() still uses the qtest_qmp_discard_response(s, "") hack to
receive the greeting, even though we have qtest_qmp_receive() since
commit 66e0c7b187e.  Put it to use.

Bonus: gets rid of an empty format string.  A step towards
compile-time format string checking without triggering
-Wformat-zero-length.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 tests/libqtest.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index 071d7eb7b1..c2c08a890c 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -249,9 +249,11 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
 QTestState *qtest_init(const char *extra_args)
 {
     QTestState *s = qtest_init_without_qmp_handshake(false, extra_args);
+    QDict *greeting;
 
     /* Read the QMP greeting and then do the handshake */
-    qtest_qmp_discard_response(s, "");
+    greeting = qtest_qmp_receive(s);
+    qobject_unref(greeting);
     qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }");
 
     return s;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (3 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:28   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail() Markus Armbruster
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

Commit ab45015a968 "qobject: Let qobject_from_jsonf() fail instead of
abort" fails to accomplish its stated aim: the function can still
abort due to its use of &error_abort.

Its rationale for letting it fail is that all remaining users cope
fine with failure.  Well, they're just fine with aborting, too; it's
what they do on failure.

Simply reverting the broken commit would bring back the unfortunate
asymmetry between qobject_from_jsonf() and qobject_from_jsonv(): one
aborts, the other returns null.  So also rename it to
qobject_from_jsonf_nofail().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 include/qapi/qmp/qjson.h |  6 ++++--
 qobject/qjson.c          |  8 +++++++-
 tests/check-qjson.c      | 15 ++++++++-------
 tests/libqtest.h         | 18 +++++++++---------
 4 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h
index 43b2ce2f33..dc509d51ae 100644
--- a/include/qapi/qmp/qjson.h
+++ b/include/qapi/qmp/qjson.h
@@ -15,11 +15,13 @@
 #define QJSON_H
 
 QObject *qobject_from_json(const char *string, Error **errp);
-QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2);
 QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
     GCC_FMT_ATTR(1, 0);
 
-QDict *qdict_from_jsonf_nofail(const char *string, ...) GCC_FMT_ATTR(1, 2);
+QObject *qobject_from_jsonf_nofail(const char *string, ...)
+    GCC_FMT_ATTR(1, 2);
+QDict *qdict_from_jsonf_nofail(const char *string, ...)
+    GCC_FMT_ATTR(1, 2);
 
 QString *qobject_to_json(const QObject *obj);
 QString *qobject_to_json_pretty(const QObject *obj);
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 2f6a590e44..4a9dcff343 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -59,7 +59,12 @@ QObject *qobject_from_json(const char *string, Error **errp)
     return qobject_from_jsonv(string, NULL, errp);
 }
 
-QObject *qobject_from_jsonf(const char *string, ...)
+/*
+ * Parse @string as JSON value with %-escapes interpolated.
+ * Abort on error.  Do not use with untrusted @string.
+ * Return the resulting QObject.  It is never null.
+ */
+QObject *qobject_from_jsonf_nofail(const char *string, ...)
 {
     QObject *obj;
     va_list ap;
@@ -68,6 +73,7 @@ QObject *qobject_from_jsonf(const char *string, ...)
     obj = qobject_from_jsonv(string, &ap, &error_abort);
     va_end(ap);
 
+    assert(obj);
     return obj;
 }
 
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index da582df3e9..eaf5d20663 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -865,7 +865,8 @@ static void vararg_string(void)
         QString *str;
 
         str = qobject_to(QString,
-                         qobject_from_jsonf("%s", test_cases[i].decoded));
+                         qobject_from_jsonf_nofail("%s",
+                                                   test_cases[i].decoded));
         g_assert(str);
         g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
 
@@ -998,17 +999,17 @@ static void vararg_number(void)
     double valuef = 2.323423423;
     int64_t val;
 
-    qnum = qobject_to(QNum, qobject_from_jsonf("%d", value));
+    qnum = qobject_to(QNum, qobject_from_jsonf_nofail("%d", value));
     g_assert(qnum_get_try_int(qnum, &val));
     g_assert_cmpint(val, ==, value);
     qobject_unref(qnum);
 
-    qnum = qobject_to(QNum, qobject_from_jsonf("%lld", value_ll));
+    qnum = qobject_to(QNum, qobject_from_jsonf_nofail("%lld", value_ll));
     g_assert(qnum_get_try_int(qnum, &val));
     g_assert_cmpint(val, ==, value_ll);
     qobject_unref(qnum);
 
-    qnum = qobject_to(QNum, qobject_from_jsonf("%f", valuef));
+    qnum = qobject_to(QNum, qobject_from_jsonf_nofail("%f", valuef));
     g_assert(qnum_get_double(qnum) == valuef);
     qobject_unref(qnum);
 }
@@ -1042,13 +1043,13 @@ static void keyword_literal(void)
 
     qobject_unref(qbool);
 
-    qbool = qobject_to(QBool, qobject_from_jsonf("%i", false));
+    qbool = qobject_to(QBool, qobject_from_jsonf_nofail("%i", false));
     g_assert(qbool);
     g_assert(qbool_get_bool(qbool) == false);
     qobject_unref(qbool);
 
     /* Test that non-zero values other than 1 get collapsed to true */
-    qbool = qobject_to(QBool, qobject_from_jsonf("%i", 2));
+    qbool = qobject_to(QBool, qobject_from_jsonf_nofail("%i", 2));
     g_assert(qbool);
     g_assert(qbool_get_bool(qbool) == true);
     qobject_unref(qbool);
@@ -1298,7 +1299,7 @@ static void simple_varargs(void)
     embedded_obj = qobject_from_json("[32, 42]", &error_abort);
     g_assert(embedded_obj != NULL);
 
-    obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
+    obj = qobject_from_jsonf_nofail("[%d, 2, %p]", 1, embedded_obj);
     g_assert(qlit_equal_qobject(&decoded, obj));
 
     qobject_unref(obj);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ced95f490a..a67e5e34eb 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -77,7 +77,7 @@ void qtest_quit(QTestState *s);
  * qtest_qmp_discard_response:
  * @s: #QTestState instance to operate on.
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and consumes the response.
@@ -88,7 +88,7 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
  * qtest_qmp:
  * @s: #QTestState instance to operate on.
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and returns the response.
@@ -99,7 +99,7 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
  * qtest_qmp_send:
  * @s: #QTestState instance to operate on.
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
@@ -110,7 +110,7 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...);
  * qtest_qmpv_discard_response:
  * @s: #QTestState instance to operate on.
  * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
@@ -122,7 +122,7 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
  * qtest_qmpv:
  * @s: #QTestState instance to operate on.
  * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
@@ -134,7 +134,7 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
  * qtest_qmp_vsend:
  * @s: #QTestState instance to operate on.
  * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  * @ap: QMP message arguments
  *
@@ -575,7 +575,7 @@ static inline void qtest_end(void)
 /**
  * qmp:
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and returns the response.
@@ -585,7 +585,7 @@ QDict *qmp(const char *fmt, ...);
 /**
  * qmp_send:
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
@@ -595,7 +595,7 @@ void qmp_send(const char *fmt, ...);
 /**
  * qmp_discard_response:
  * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf().
+ * qobject_from_jsonf_nofail().
  * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Sends a QMP message to QEMU and consumes the response.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (4 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:30   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit Markus Armbruster
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

Every printf()-like function sooner or later needs its vprintf()-like
buddy.  The next commit will need qobject_from_jsonf_nofail()'s buddy,
and qdict_from_jsonf_nofail()'s buddy will be used later in this
series.  Add both.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/qapi/qmp/qjson.h |  4 ++++
 qobject/qjson.c          | 44 +++++++++++++++++++++++++++++++++-------
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h
index dc509d51ae..dce78583dc 100644
--- a/include/qapi/qmp/qjson.h
+++ b/include/qapi/qmp/qjson.h
@@ -18,8 +18,12 @@ QObject *qobject_from_json(const char *string, Error **errp);
 QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
     GCC_FMT_ATTR(1, 0);
 
+QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
+    GCC_FMT_ATTR(1, 0);
 QObject *qobject_from_jsonf_nofail(const char *string, ...)
     GCC_FMT_ATTR(1, 2);
+QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
+    GCC_FMT_ATTR(1, 0);
 QDict *qdict_from_jsonf_nofail(const char *string, ...)
     GCC_FMT_ATTR(1, 2);
 
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 4a9dcff343..2e450231ff 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -59,6 +59,25 @@ QObject *qobject_from_json(const char *string, Error **errp)
     return qobject_from_jsonv(string, NULL, errp);
 }
 
+/*
+ * Parse @string as JSON value with %-escapes interpolated.
+ * Abort on error.  Do not use with untrusted @string.
+ * Return the resulting QObject.  It is never null.
+ */
+QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
+{
+    va_list ap_copy;
+    QObject *obj;
+
+    /* va_copy() is needed when va_list is an array type */
+    va_copy(ap_copy, ap);
+    obj = qobject_from_jsonv(string, &ap_copy, &error_abort);
+    va_end(ap_copy);
+
+    assert(obj);
+    return obj;
+}
+
 /*
  * Parse @string as JSON value with %-escapes interpolated.
  * Abort on error.  Do not use with untrusted @string.
@@ -70,13 +89,26 @@ QObject *qobject_from_jsonf_nofail(const char *string, ...)
     va_list ap;
 
     va_start(ap, string);
-    obj = qobject_from_jsonv(string, &ap, &error_abort);
+    obj = qobject_from_vjsonf_nofail(string, ap);
     va_end(ap);
 
-    assert(obj);
     return obj;
 }
 
+/*
+ * Parse @string as JSON object with %-escapes interpolated.
+ * Abort on error.  Do not use with untrusted @string.
+ * Return the resulting QDict.  It is never null.
+ */
+QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
+{
+    QDict *qdict;
+
+    qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap));
+    assert(qdict);
+    return qdict;
+}
+
 /*
  * Parse @string as JSON object with %-escapes interpolated.
  * Abort on error.  Do not use with untrusted @string.
@@ -84,15 +116,13 @@ QObject *qobject_from_jsonf_nofail(const char *string, ...)
  */
 QDict *qdict_from_jsonf_nofail(const char *string, ...)
 {
-    QDict *obj;
+    QDict *qdict;
     va_list ap;
 
     va_start(ap, string);
-    obj = qobject_to(QDict, qobject_from_jsonv(string, &ap, &error_abort));
+    qdict = qdict_from_vjsonf_nofail(string, ap);
     va_end(ap);
-
-    assert(obj);
-    return obj;
+    return qdict;
 }
 
 typedef struct ToJsonIterState
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (5 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:31   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity Markus Armbruster
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 tests/libqtest.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index c2c08a890c..3bfb062fcb 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -488,24 +488,20 @@ QDict *qtest_qmp_receive(QTestState *s)
  */
 void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
 {
-    va_list ap_copy;
     QObject *qobj;
 
-    /* qobject_from_jsonv() silently eats leading 0xff as invalid
-     * JSON, but we want to test sending them over the wire to force
-     * resyncs */
+    /*
+     * qobject_from_vjsonf_nofail() chokes on leading 0xff as invalid
+     * JSON, but tests/test-qga.c needs to send that to test QGA
+     * synchronization
+     */
     if (*fmt == '\377') {
         socket_send(fd, fmt, 1);
         fmt++;
     }
 
-    /* Going through qobject ensures we escape strings properly.
-     * This seemingly unnecessary copy is required in case va_list
-     * is an array type.
-     */
-    va_copy(ap_copy, ap);
-    qobj = qobject_from_jsonv(fmt, &ap_copy, &error_abort);
-    va_end(ap_copy);
+    /* Going through qobject ensures we escape strings properly */
+    qobj = qobject_from_vjsonf_nofail(fmt, ap);
 
     /* No need to send anything for an empty QObject.  */
     if (qobj) {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (6 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:33   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away Markus Armbruster
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

When visitor_input_test_init_internal()'s argument @ap is null, then
@json_string is interpreted literally, else it's gets %-escapes
interpolated.  This is awkward.

One caller always passes null @ap, and the others never do.  Lift the
building of the QObject into the callers, where it can be done without
such ambiguity.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/test-qobject-input-visitor.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index 0f4d234c3f..caa90b3d7e 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -47,15 +47,13 @@ static void visitor_input_teardown(TestInputVisitorData *data,
 /* The various test_init functions are provided instead of a test setup
    function so that the JSON string used by the tests are kept in the test
    functions (and not in main()). */
-static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data,
-                                                 bool keyval,
-                                                 const char *json_string,
-                                                 va_list *ap)
+
+static Visitor *test_init_internal(TestInputVisitorData *data, bool keyval,
+                                   QObject *obj)
 {
     visitor_input_teardown(data, NULL);
 
-    data->obj = qobject_from_jsonv(json_string, ap, &error_abort);
-    g_assert(data->obj);
+    data->obj = obj;
 
     if (keyval) {
         data->qiv = qobject_input_visitor_new_keyval(data->obj);
@@ -75,7 +73,8 @@ Visitor *visitor_input_test_init_full(TestInputVisitorData *data,
     va_list ap;
 
     va_start(ap, json_string);
-    v = visitor_input_test_init_internal(data, keyval, json_string, &ap);
+    v = test_init_internal(data, keyval,
+                           qobject_from_vjsonf_nofail(json_string, ap));
     va_end(ap);
     return v;
 }
@@ -88,7 +87,8 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
     va_list ap;
 
     va_start(ap, json_string);
-    v = visitor_input_test_init_internal(data, false, json_string, &ap);
+    v = test_init_internal(data, false,
+                           qobject_from_vjsonf_nofail(json_string, ap));
     va_end(ap);
     return v;
 }
@@ -103,7 +103,8 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
 static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
                                             const char *json_string)
 {
-    return visitor_input_test_init_internal(data, false, json_string, NULL);
+    return test_init_internal(data, false,
+                              qobject_from_json(json_string, &error_abort));
 }
 
 static void test_visitor_in_int(TestInputVisitorData *data,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (7 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:34   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO() Markus Armbruster
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qobject_from_jsonv() takes ownership of %p arguments.  On failure, we
can't generally know whether we failed before or after %p, so
ownership becomes indeterminate.  To avoid leaks, callers passing %p
must terminate on error, e.g. by passing &error_abort.  Trap for the
unwary; document and give the function internal linkage.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/qapi/qmp/qjson.h |  2 --
 qobject/qjson.c          | 13 ++++++++++++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h
index dce78583dc..5ebbe5a118 100644
--- a/include/qapi/qmp/qjson.h
+++ b/include/qapi/qmp/qjson.h
@@ -15,8 +15,6 @@
 #define QJSON_H
 
 QObject *qobject_from_json(const char *string, Error **errp);
-QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
-    GCC_FMT_ATTR(1, 0);
 
 QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
     GCC_FMT_ATTR(1, 0);
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 2e450231ff..ab4040f235 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -39,7 +39,18 @@ static void parse_json(JSONMessageParser *parser, GQueue *tokens)
     s->result = json_parser_parse_err(tokens, s->ap, &s->err);
 }
 
-QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
+/*
+ * Parse @string as JSON value.
+ * If @ap is non-null, interpolate %-escapes.
+ * Takes ownership of %p arguments.
+ * On success, return the JSON value.
+ * On failure, store an error through @errp and return NULL.
+ * Ownership of %p arguments becomes indeterminate then.  To avoid
+ * leaks, callers passing %p must terminate on error, e.g. by passing
+ * &error_abort.
+ */
+static QObject *qobject_from_jsonv(const char *string, va_list *ap,
+                                   Error **errp)
 {
     JSONParsingState state = {};
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (8 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:35   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases) Markus Armbruster
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

The qmp_FOO() take a printf-like format string.  In a few places, we
assign a string literal to a variable and pass that instead of simply
passing the literal.  Clean that up.

Bonus: gets rid of non-literal format strings.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 tests/ahci-test.c | 4 +---
 tests/ide-test.c  | 4 +---
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 7e3491b5bd..19a7ab1bca 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1352,7 +1352,6 @@ static void test_flush_migrate(void)
     AHCIQState *src, *dst;
     AHCICommand *cmd;
     uint8_t px;
-    const char *s;
     char *uri = g_strdup_printf("unix:%s", mig_socket);
 
     prepare_blkdebug_script(debug_path, "flush_to_disk");
@@ -1388,8 +1387,7 @@ static void test_flush_migrate(void)
     ahci_migrate(src, dst, uri);
 
     /* Complete the command */
-    s = "{'execute':'cont' }";
-    qmp_send(s);
+    qmp_send("{'execute':'cont' }");
     qmp_eventwait("RESUME");
     ahci_command_wait(dst, cmd);
     ahci_command_verify(dst, cmd);
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 2384c2c3e2..834ee9005b 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -694,7 +694,6 @@ static void test_retry_flush(const char *machine)
     QPCIDevice *dev;
     QPCIBar bmdma_bar, ide_bar;
     uint8_t data;
-    const char *s;
 
     prepare_blkdebug_script(debug_path, "flush_to_disk");
 
@@ -722,8 +721,7 @@ static void test_retry_flush(const char *machine)
     qmp_eventwait("STOP");
 
     /* Complete the command */
-    s = "{'execute':'cont' }";
-    qmp_discard_response(s);
+    qmp_discard_response("{'execute':'cont' }");
 
     /* Check registers */
     data = qpci_io_readb(dev, ide_bar, reg_device);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases)
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (9 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:39   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add Markus Armbruster
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

When you build QMP input manually like this

    cmd = g_strdup_printf("{ 'execute': 'migrate',"
                          "'arguments': { 'uri': '%s' } }",
                          uri);
    rsp = qmp(cmd);
    g_free(cmd);

you're responsible for escaping the interpolated values for JSON.  Not
done here, and therefore works only for sufficiently nice @uri.  For
instance, if @uri contained a single "'", qobject_from_vjsonf_nofail()
would abort.  A sufficiently nasty @uri could even inject unwanted
members into the arguments object.

Leaving interpolation into JSON to qmp() is more robust:

    rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);

It's also more concise.

Clean up the simple cases where we interpolate exactly a JSON value.

Bonus: gets rid of non-literal format strings.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 tests/libqos/pci-pc.c   |   9 +--
 tests/libqtest.c        |   7 +-
 tests/migration-test.c  |   8 +--
 tests/test-qga.c        | 150 ++++++++++++++++++----------------------
 tests/tpm-util.c        |   9 +--
 tests/vhost-user-test.c |   6 +-
 6 files changed, 77 insertions(+), 112 deletions(-)

diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index a7803308b7..585f5289ec 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -160,14 +160,9 @@ void qpci_free_pc(QPCIBus *bus)
 void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
 {
     QDict *response;
-    char *cmd;
 
-    cmd = g_strdup_printf("{'execute': 'device_del',"
-                          " 'arguments': {"
-                          "   'id': '%s'"
-                          "}}", id);
-    response = qmp(cmd);
-    g_free(cmd);
+    response = qmp("{'execute': 'device_del', 'arguments': {'id': %s}}",
+                   id);
     g_assert(response);
     g_assert(!qdict_haskey(response, "error"));
     qobject_unref(response);
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 3bfb062fcb..e36cc5ede3 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1079,12 +1079,9 @@ void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
 void qtest_qmp_device_del(const char *id)
 {
     QDict *response1, *response2, *event = NULL;
-    char *cmd;
 
-    cmd = g_strdup_printf("{'execute': 'device_del',"
-                          " 'arguments': { 'id': '%s' }}", id);
-    response1 = qmp(cmd);
-    g_free(cmd);
+    response1 = qmp("{'execute': 'device_del', 'arguments': {'id': %s}}",
+                    id);
     g_assert(response1);
     g_assert(!qdict_haskey(response1, "error"));
 
diff --git a/tests/migration-test.c b/tests/migration-test.c
index e079e0bdb6..c6c7089ce1 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -529,14 +529,12 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
 static void deprecated_set_downtime(QTestState *who, const double value)
 {
     QDict *rsp;
-    gchar *cmd;
     char *expected;
     int64_t result_int;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
-                          "'arguments': { 'value': %g } }", value);
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate_set_downtime',"
+                    " 'arguments': { 'value': %f } }", value);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
     result_int = value * 1000L;
diff --git a/tests/test-qga.c b/tests/test-qga.c
index d638b1571a..c552cc0125 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -146,12 +146,11 @@ static void test_qga_sync_delimited(gconstpointer fix)
     guint32 v, r = g_random_int();
     unsigned char c;
     QDict *ret;
-    gchar *cmd;
 
-    cmd = g_strdup_printf("\xff{'execute': 'guest-sync-delimited',"
-                          " 'arguments': {'id': %u } }", r);
-    qmp_fd_send(fixture->fd, cmd);
-    g_free(cmd);
+    qmp_fd_send(fixture->fd,
+                "\xff{'execute': 'guest-sync-delimited',"
+                " 'arguments': {'id': %u } }",
+                r);
 
     /*
      * Read and ignore garbage until resynchronized.
@@ -188,7 +187,6 @@ static void test_qga_sync(gconstpointer fix)
     const TestFixture *fixture = fix;
     guint32 v, r = g_random_int();
     QDict *ret;
-    gchar *cmd;
 
     /*
      * TODO guest-sync is inherently limited: we cannot distinguish
@@ -201,10 +199,9 @@ static void test_qga_sync(gconstpointer fix)
      * invalid JSON. Testing of '\xff' handling is done in
      * guest-sync-delimited instead.
      */
-    cmd = g_strdup_printf("{'execute': 'guest-sync',"
-                          " 'arguments': {'id': %u } }", r);
-    ret = qmp_fd(fixture->fd, cmd);
-    g_free(cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-sync', 'arguments': {'id': %u } }",
+                 r);
 
     g_assert_nonnull(ret);
     qmp_assert_no_error(ret);
@@ -428,7 +425,7 @@ static void test_qga_file_ops(gconstpointer fix)
     const TestFixture *fixture = fix;
     const unsigned char helloworld[] = "Hello World!\n";
     const char *b64;
-    gchar *cmd, *path, *enc;
+    gchar *path, *enc;
     unsigned char *dec;
     QDict *ret, *val;
     int64_t id, eof;
@@ -446,10 +443,10 @@ static void test_qga_file_ops(gconstpointer fix)
 
     enc = g_base64_encode(helloworld, sizeof(helloworld));
     /* write */
-    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
-                          " 'arguments': { 'handle': %" PRId64 ","
-                          " 'buf-b64': '%s' } }", id, enc);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-write',"
+                 " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }",
+                 id, enc);
     g_assert_nonnull(ret);
     qmp_assert_no_error(ret);
 
@@ -459,23 +456,20 @@ static void test_qga_file_ops(gconstpointer fix)
     g_assert_cmpint(count, ==, sizeof(helloworld));
     g_assert_cmpint(eof, ==, 0);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* flush */
-    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
-                          " 'arguments': {'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-flush',"
+                 " 'arguments': {'handle': %" PRId64 "} }",
+                 id);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* close */
-    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
-                          " 'arguments': {'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-close',"
+                 " 'arguments': {'handle': %" PRId64 "} }",
+                 id);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* check content */
     path = g_build_filename(fixture->test_dir, "foo", NULL);
@@ -497,10 +491,10 @@ static void test_qga_file_ops(gconstpointer fix)
     qobject_unref(ret);
 
     /* read */
-    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
-                          " 'arguments': { 'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-read',"
+                 " 'arguments': { 'handle': %" PRId64 "} }",
+                 id);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "count");
     eof = qdict_get_bool(val, "eof");
@@ -510,14 +504,13 @@ static void test_qga_file_ops(gconstpointer fix)
     g_assert_cmpstr(b64, ==, enc);
 
     qobject_unref(ret);
-    g_free(cmd);
     g_free(enc);
 
     /* read eof */
-    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
-                          " 'arguments': { 'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-read',"
+                 " 'arguments': { 'handle': %" PRId64 "} }",
+                 id);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "count");
     eof = qdict_get_bool(val, "eof");
@@ -526,14 +519,13 @@ static void test_qga_file_ops(gconstpointer fix)
     g_assert(eof);
     g_assert_cmpstr(b64, ==, "");
     qobject_unref(ret);
-    g_free(cmd);
 
     /* seek */
-    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
-                          " 'arguments': { 'handle': %" PRId64 ", "
-                          " 'offset': %d, 'whence': '%s' } }",
-                          id, 6, "set");
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-seek',"
+                 " 'arguments': { 'handle': %" PRId64 ", "
+                 " 'offset': %d, 'whence': %s } }",
+                 id, 6, "set");
     qmp_assert_no_error(ret);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "position");
@@ -541,13 +533,12 @@ static void test_qga_file_ops(gconstpointer fix)
     g_assert_cmpint(count, ==, 6);
     g_assert(!eof);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* partial read */
-    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
-                          " 'arguments': { 'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-read',"
+                 " 'arguments': { 'handle': %" PRId64 "} }",
+                 id);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "count");
     eof = qdict_get_bool(val, "eof");
@@ -560,15 +551,13 @@ static void test_qga_file_ops(gconstpointer fix)
     g_free(dec);
 
     qobject_unref(ret);
-    g_free(cmd);
 
     /* close */
-    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
-                          " 'arguments': {'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-close',"
+                 " 'arguments': {'handle': %" PRId64 "} }",
+                 id);
     qobject_unref(ret);
-    g_free(cmd);
 }
 
 static void test_qga_file_write_read(gconstpointer fix)
@@ -576,7 +565,7 @@ static void test_qga_file_write_read(gconstpointer fix)
     const TestFixture *fixture = fix;
     const unsigned char helloworld[] = "Hello World!\n";
     const char *b64;
-    gchar *cmd, *enc;
+    gchar *enc;
     QDict *ret, *val;
     int64_t id, eof;
     gsize count;
@@ -591,10 +580,10 @@ static void test_qga_file_write_read(gconstpointer fix)
 
     enc = g_base64_encode(helloworld, sizeof(helloworld));
     /* write */
-    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
-                          " 'arguments': { 'handle': %" PRId64 ","
-                          " 'buf-b64': '%s' } }", id, enc);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-write',"
+                 " 'arguments': { 'handle': %" PRId64 ","
+                 " 'buf-b64': %s } }", id, enc);
     g_assert_nonnull(ret);
     qmp_assert_no_error(ret);
 
@@ -604,13 +593,12 @@ static void test_qga_file_write_read(gconstpointer fix)
     g_assert_cmpint(count, ==, sizeof(helloworld));
     g_assert_cmpint(eof, ==, 0);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* read (check implicit flush) */
-    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
-                          " 'arguments': { 'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-read',"
+                 " 'arguments': { 'handle': %" PRId64 "} }",
+                 id);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "count");
     eof = qdict_get_bool(val, "eof");
@@ -619,14 +607,13 @@ static void test_qga_file_write_read(gconstpointer fix)
     g_assert(eof);
     g_assert_cmpstr(b64, ==, "");
     qobject_unref(ret);
-    g_free(cmd);
 
     /* seek to 0 */
-    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
-                          " 'arguments': { 'handle': %" PRId64 ", "
-                          " 'offset': %d, 'whence': '%s' } }",
-                          id, 0, "set");
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-seek',"
+                 " 'arguments': { 'handle': %" PRId64 ", "
+                 " 'offset': %d, 'whence': %s } }",
+                 id, 0, "set");
     qmp_assert_no_error(ret);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "position");
@@ -634,13 +621,12 @@ static void test_qga_file_write_read(gconstpointer fix)
     g_assert_cmpint(count, ==, 0);
     g_assert(!eof);
     qobject_unref(ret);
-    g_free(cmd);
 
     /* read */
-    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
-                          " 'arguments': { 'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-read',"
+                 " 'arguments': { 'handle': %" PRId64 "} }",
+                 id);
     val = qdict_get_qdict(ret, "return");
     count = qdict_get_int(val, "count");
     eof = qdict_get_bool(val, "eof");
@@ -649,16 +635,14 @@ static void test_qga_file_write_read(gconstpointer fix)
     g_assert(eof);
     g_assert_cmpstr(b64, ==, enc);
     qobject_unref(ret);
-    g_free(cmd);
     g_free(enc);
 
     /* close */
-    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
-                          " 'arguments': {'handle': %" PRId64 "} }",
-                          id);
-    ret = qmp_fd(fixture->fd, cmd);
+    ret = qmp_fd(fixture->fd,
+                 "{'execute': 'guest-file-close',"
+                 " 'arguments': {'handle': %" PRId64 "} }",
+                 id);
     qobject_unref(ret);
-    g_free(cmd);
 }
 
 static void test_qga_get_time(gconstpointer fix)
@@ -814,7 +798,6 @@ static void test_qga_guest_exec(gconstpointer fix)
     int64_t pid, now, exitcode;
     gsize len;
     bool exited;
-    char *cmd;
 
     /* exec 'echo foo bar' */
     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
@@ -829,10 +812,10 @@ static void test_qga_guest_exec(gconstpointer fix)
 
     /* wait for completion */
     now = g_get_monotonic_time();
-    cmd = g_strdup_printf("{'execute': 'guest-exec-status',"
-                          " 'arguments': { 'pid': %" PRId64 " } }", pid);
     do {
-        ret = qmp_fd(fixture->fd, cmd);
+        ret = qmp_fd(fixture->fd,
+                     "{'execute': 'guest-exec-status',"
+                     " 'arguments': { 'pid': %" PRId64 " } }", pid);
         g_assert_nonnull(ret);
         val = qdict_get_qdict(ret, "return");
         exited = qdict_get_bool(val, "exited");
@@ -842,7 +825,6 @@ static void test_qga_guest_exec(gconstpointer fix)
     } while (!exited &&
              g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
     g_assert(exited);
-    g_free(cmd);
 
     /* check stdout */
     exitcode = qdict_get_int(val, "exitcode");
diff --git a/tests/tpm-util.c b/tests/tpm-util.c
index 672cedf905..3bd2887f1e 100644
--- a/tests/tpm-util.c
+++ b/tests/tpm-util.c
@@ -239,13 +239,10 @@ void tpm_util_swtpm_kill(GPid pid)
 void tpm_util_migrate(QTestState *who, const char *uri)
 {
     QDict *rsp;
-    gchar *cmd;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate',"
-                          "'arguments': { 'uri': '%s' } }",
-                          uri);
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate', 'arguments': { 'uri': %s } }",
+                    uri);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 }
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index fecc832d99..ca6251f5f8 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -709,11 +709,7 @@ static void test_migrate(void)
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate',"
-                          "'arguments': { 'uri': '%s' } }",
-                          uri);
-    rsp = qmp(cmd);
-    g_free(cmd);
+    rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (10 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases) Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:42   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add() Markus Armbruster
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

test_plug_with_device_add_x86() plugs Haswell-i386-cpu and
Haswell-x86_64-cpu with device_add.  It passes socket-id, core-id,
thread-id as JSON strings.  The properties are actually integers.

test_plug_with_device_add_coreid() plugs power8_v2.0-spapr-cpu-core
and qemu-s390x-cpu with device_add.  It passes core-id as JSON string.
The properties are actually integers.

Passing JSON string values to integer properties works only due to
device_add implementation accidents.  Fix the test to pass JSON
numbers.  While there, use %u rather than %i with unsigned int.

Cc: Thomas Huth <thuth@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 tests/cpu-plug-test.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
index 5f39ba0df3..ab3bf6df90 100644
--- a/tests/cpu-plug-test.c
+++ b/tests/cpu-plug-test.c
@@ -88,8 +88,8 @@ static void test_plug_with_device_add_x86(gconstpointer data)
         for (c = 0; c < td->cores; c++) {
             for (t = 0; t < td->threads; t++) {
                 char *id = g_strdup_printf("id-%i-%i-%i", s, c, t);
-                qtest_qmp_device_add(td->device_model, id, "'socket-id':'%i', "
-                                     "'core-id':'%i', 'thread-id':'%i'",
+                qtest_qmp_device_add(td->device_model, id, "'socket-id':%u, "
+                                     "'core-id':%u, 'thread-id':%u",
                                      s, c, t);
                 g_free(id);
             }
@@ -114,7 +114,7 @@ static void test_plug_with_device_add_coreid(gconstpointer data)
 
     for (c = td->cores; c < td->maxcpus / td->sockets / td->threads; c++) {
         char *id = g_strdup_printf("id-%i", c);
-        qtest_qmp_device_add(td->device_model, id, "'core-id':'%i'", c);
+        qtest_qmp_device_add(td->device_model, id, "'core-id':%u", c);
         g_free(id);
     }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (11 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:48   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member Markus Armbruster
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

Leaving interpolation into JSON to qmp() is more robust than building
QMP input manually, as explained in the commit before previous.

qtest_qmp_device_add() and its wrappers interpolate into JSON as
follows:

* qtest_qmp_device_add() interpolates members into a JSON object.

* So do its wrappers qpci_plug_device_test() and usb_test_hotplug().

* usb_test_hotplug() additionally interpolates strings and numbers
  into JSON strings.

Clean them up:

* Have qtest_qmp_device_add() take its extra device properties as
  arguments for for qdict_from_jsonf_nofail() instead of a string
  containing JSON members.

* Drop qpci_plug_device_test(), use qtest_qmp_device_add()
  directly.

* Change usb_test_hotplug() parameter @port to string, to avoid
  interpolation.  Interpolate @hcd_id separately.

Bonus: gets rid of a non-literal format string.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Cc: Thomas Huth <thuth@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/cpu-plug-test.c      |  7 ++++---
 tests/e1000e-test.c        |  6 ++----
 tests/ivshmem-test.c       |  8 +++-----
 tests/libqos/pci.c         |  7 -------
 tests/libqos/pci.h         |  2 --
 tests/libqos/usb.c         | 10 ++++++----
 tests/libqos/usb.h         |  2 +-
 tests/libqtest.c           | 27 +++++++++++----------------
 tests/libqtest.h           |  4 +++-
 tests/usb-hcd-ehci-test.c  |  2 +-
 tests/usb-hcd-ohci-test.c  |  2 +-
 tests/usb-hcd-uhci-test.c  |  4 ++--
 tests/usb-hcd-xhci-test.c  | 10 +++++-----
 tests/virtio-blk-test.c    |  5 +++--
 tests/virtio-net-test.c    |  3 ++-
 tests/virtio-rng-test.c    |  3 ++-
 tests/virtio-scsi-test.c   |  2 +-
 tests/virtio-serial-test.c |  2 +-
 18 files changed, 48 insertions(+), 58 deletions(-)

diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
index ab3bf6df90..f5d57da60e 100644
--- a/tests/cpu-plug-test.c
+++ b/tests/cpu-plug-test.c
@@ -88,8 +88,9 @@ static void test_plug_with_device_add_x86(gconstpointer data)
         for (c = 0; c < td->cores; c++) {
             for (t = 0; t < td->threads; t++) {
                 char *id = g_strdup_printf("id-%i-%i-%i", s, c, t);
-                qtest_qmp_device_add(td->device_model, id, "'socket-id':%u, "
-                                     "'core-id':%u, 'thread-id':%u",
+                qtest_qmp_device_add(td->device_model, id,
+                                     "{'socket-id':%u, 'core-id':%u,"
+                                     " 'thread-id':%u}",
                                      s, c, t);
                 g_free(id);
             }
@@ -114,7 +115,7 @@ static void test_plug_with_device_add_coreid(gconstpointer data)
 
     for (c = td->cores; c < td->maxcpus / td->sockets / td->threads; c++) {
         char *id = g_strdup_printf("id-%i", c);
-        qtest_qmp_device_add(td->device_model, id, "'core-id':%u", c);
+        qtest_qmp_device_add(td->device_model, id, "{'core-id':%u}", c);
         g_free(id);
     }
 
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 32aa738b72..c9408a5d1f 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -456,12 +456,10 @@ static void test_e1000e_multiple_transfers(gconstpointer data)
 
 static void test_e1000e_hotplug(gconstpointer data)
 {
-    static const uint8_t slot = 0x06;
-
     qtest_start("-device e1000e");
 
-    qpci_plug_device_test("e1000e", "e1000e_net", slot, NULL);
-    qpci_unplug_acpi_device_test("e1000e_net", slot);
+    qtest_qmp_device_add("e1000e", "e1000e_net", "{'addr': '0x06'}");
+    qpci_unplug_acpi_device_test("e1000e_net", 0x06);
 
     qtest_end();
 }
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 9b407a3e42..225fde7fff 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -420,19 +420,17 @@ static void test_ivshmem_server_irq(void)
 static void test_ivshmem_hotplug(void)
 {
     const char *arch = qtest_get_arch();
-    gchar *opts;
 
     qtest_start("");
 
-    opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm);
-
-    qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts);
+    qtest_qmp_device_add("ivshmem",
+                         "iv1", "{'addr': %s, 'shm': '%s', 'size': '1M'}",
+                         stringify(PCI_SLOT_HP), tmpshm);
     if (strcmp(arch, "ppc64") != 0) {
         qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
     }
 
     qtest_end();
-    g_free(opts);
 }
 
 static void test_ivshmem_memdev(void)
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 0b73cb23d0..e8c342c257 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -395,10 +395,3 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
     QPCIBar bar = { .addr = addr };
     return bar;
 }
-
-void qpci_plug_device_test(const char *driver, const char *id,
-                           uint8_t slot, const char *opts)
-{
-    qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
-                         opts ? ", " : "", opts ? opts : "");
-}
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 429c382282..0b7e936174 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -109,7 +109,5 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
 void qpci_iounmap(QPCIDevice *dev, QPCIBar addr);
 QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
 
-void qpci_plug_device_test(const char *driver, const char *id,
-                           uint8_t slot, const char *opts);
 void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
 #endif
diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c
index 2a476049a8..49e2f4bc0a 100644
--- a/tests/libqos/usb.c
+++ b/tests/libqos/usb.c
@@ -37,13 +37,14 @@ void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
     g_assert((value & mask) == (expect & mask));
 }
 
-void usb_test_hotplug(const char *hcd_id, const int port,
+void usb_test_hotplug(const char *hcd_id, const char *port,
                       void (*port_check)(void))
 {
-    char  *id = g_strdup_printf("usbdev%d", port);
+    char *id = g_strdup_printf("usbdev%s", port);
+    char *bus = g_strdup_printf("%s.0", hcd_id);
 
-    qtest_qmp_device_add("usb-tablet", id, "'port': '%d', 'bus': '%s.0'",
-                         port, hcd_id);
+    qtest_qmp_device_add("usb-tablet", id, "{'port': %s, 'bus': %s}",
+                         port, bus);
 
     if (port_check) {
         port_check();
@@ -51,5 +52,6 @@ void usb_test_hotplug(const char *hcd_id, const int port,
 
     qtest_qmp_device_del(id);
 
+    g_free(bus);
     g_free(id);
 }
diff --git a/tests/libqos/usb.h b/tests/libqos/usb.h
index 297cfc564d..c506418a13 100644
--- a/tests/libqos/usb.h
+++ b/tests/libqos/usb.h
@@ -13,6 +13,6 @@ void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc,
 void uhci_port_test(struct qhc *hc, int port, uint16_t expect);
 void uhci_deinit(struct qhc *hc);
 
-void usb_test_hotplug(const char *bus_name, const int port,
+void usb_test_hotplug(const char *bus_name, const char *port,
                       void (*port_check)(void));
 #endif
diff --git a/tests/libqtest.c b/tests/libqtest.c
index e36cc5ede3..dfca3af89d 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1032,26 +1032,21 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
 /*
  * Generic hot-plugging test via the device_add QMP command.
  */
-void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
-                          ...)
+void qtest_qmp_device_add(const char *driver, const char *id,
+                          const char *fmt, ...)
 {
-    QDict *response;
-    char *cmd, *opts = NULL;
-    va_list va;
+    QDict *args, *response;
+    va_list ap;
 
-    if (fmt) {
-        va_start(va, fmt);
-        opts = g_strdup_vprintf(fmt, va);
-        va_end(va);
-    }
+    va_start(ap, fmt);
+    args = qdict_from_vjsonf_nofail(fmt, ap);
+    va_end(ap);
 
-    cmd = g_strdup_printf("{'execute': 'device_add',"
-                          " 'arguments': { 'driver': '%s', 'id': '%s'%s%s }}",
-                          driver, id, opts ? ", " : "", opts ? opts : "");
-    g_free(opts);
+    g_assert(!qdict_haskey(args, "driver") && !qdict_haskey(args, "id"));
+    qdict_put_str(args, "driver", driver);
+    qdict_put_str(args, "id", id);
 
-    response = qmp(cmd);
-    g_free(cmd);
+    response = qmp("{'execute': 'device_add', 'arguments': %p}", args);
     g_assert(response);
     g_assert(!qdict_haskey(response, "event")); /* We don't expect any events */
     g_assert(!qdict_haskey(response, "error"));
diff --git a/tests/libqtest.h b/tests/libqtest.h
index a67e5e34eb..ce6c092fc9 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -976,7 +976,9 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine));
  * qtest_qmp_device_add:
  * @driver: Name of the device that should be added
  * @id: Identification string
- * @fmt: printf-like format string for further options to device_add
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail().
+ * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
  *
  * Generic hot-plugging test via the device_add QMP command.
  */
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index 55d4743a2a..f28ea27f37 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -139,7 +139,7 @@ static void pci_ehci_port_3_hotplug(void)
 
 static void pci_ehci_port_hotplug(void)
 {
-    usb_test_hotplug("ich9-ehci-1", 3, pci_ehci_port_3_hotplug);
+    usb_test_hotplug("ich9-ehci-1", "3", pci_ehci_port_3_hotplug);
 }
 
 
diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c
index 4758813d78..48ddbfd26d 100644
--- a/tests/usb-hcd-ohci-test.c
+++ b/tests/usb-hcd-ohci-test.c
@@ -19,7 +19,7 @@ static void test_ohci_init(void)
 
 static void test_ohci_hotplug(void)
 {
-    usb_test_hotplug("ohci", 1, NULL);
+    usb_test_hotplug("ohci", "1", NULL);
 }
 
 int main(int argc, char **argv)
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
index 6a7e5a2fed..a119d6d5c8 100644
--- a/tests/usb-hcd-uhci-test.c
+++ b/tests/usb-hcd-uhci-test.c
@@ -43,12 +43,12 @@ static void test_port_2(void)
 
 static void test_uhci_hotplug(void)
 {
-    usb_test_hotplug("uhci", 2, test_port_2);
+    usb_test_hotplug("uhci", "2", test_port_2);
 }
 
 static void test_usb_storage_hotplug(void)
 {
-    qtest_qmp_device_add("usb-storage", "usbdev0", "'drive': 'drive0'");
+    qtest_qmp_device_add("usb-storage", "usbdev0", "{'drive': 'drive0'}");
 
     qtest_qmp_device_del("usbdev0");
 }
diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c
index 5b1b681bf2..9eb24b00e4 100644
--- a/tests/usb-hcd-xhci-test.c
+++ b/tests/usb-hcd-xhci-test.c
@@ -18,13 +18,13 @@ static void test_xhci_init(void)
 
 static void test_xhci_hotplug(void)
 {
-    usb_test_hotplug("xhci", 1, NULL);
+    usb_test_hotplug("xhci", "1", NULL);
 }
 
 static void test_usb_uas_hotplug(void)
 {
-    qtest_qmp_device_add("usb-uas", "uas", NULL);
-    qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drive0'");
+    qtest_qmp_device_add("usb-uas", "uas", "{}");
+    qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drive0'}");
 
     /* TODO:
         UAS HBA driver in libqos, to check that
@@ -37,10 +37,10 @@ static void test_usb_uas_hotplug(void)
 
 static void test_usb_ccid_hotplug(void)
 {
-    qtest_qmp_device_add("usb-ccid", "ccid", NULL);
+    qtest_qmp_device_add("usb-ccid", "ccid", "{}");
     qtest_qmp_device_del("ccid");
     /* check the device can be added again */
-    qtest_qmp_device_add("usb-ccid", "ccid", NULL);
+    qtest_qmp_device_add("usb-ccid", "ccid", "{}");
     qtest_qmp_device_del("ccid");
 }
 
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 9be9ffb378..d96b4c69e1 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -662,8 +662,9 @@ static void pci_hotplug(void)
     qs = pci_test_start();
 
     /* plug secondary disk */
-    qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
-                          "'drive': 'drive1'");
+    qtest_qmp_device_add("virtio-blk-pci", "drv1",
+                         "{'addr': %s, 'drive': 'drive1'}",
+                         stringify(PCI_SLOT_HP));
 
     dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
     g_assert(dev);
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index b285a262e9..dcb87a8b6e 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -249,7 +249,8 @@ static void hotplug(void)
 
     qtest_start("-device virtio-net-pci");
 
-    qpci_plug_device_test("virtio-net-pci", "net1", PCI_SLOT_HP, NULL);
+    qtest_qmp_device_add("virtio-net-pci", "net1",
+                         "{'addr': %s}", stringify(PCI_SLOT_HP));
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
         qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
index dcecf77463..657d9a4105 100644
--- a/tests/virtio-rng-test.c
+++ b/tests/virtio-rng-test.c
@@ -22,7 +22,8 @@ static void hotplug(void)
 {
     const char *arch = qtest_get_arch();
 
-    qpci_plug_device_test("virtio-rng-pci", "rng1", PCI_SLOT_HP, NULL);
+    qtest_qmp_device_add("virtio-rng-pci", "rng1",
+                         "{'addr': %s}", stringify(PCI_SLOT_HP));
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
         qpci_unplug_acpi_device_test("rng1", PCI_SLOT_HP);
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 037872bb98..0d4f25d369 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -199,7 +199,7 @@ static void hotplug(void)
 
     qs = qvirtio_scsi_start(
             "-drive id=drv1,if=none,file=null-co://,format=raw");
-    qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drv1'");
+    qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drv1'}");
     qtest_qmp_device_del("scsihd");
     qvirtio_scsi_stop(qs);
 }
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
index 7cc7060264..e4b18b1c8a 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -18,7 +18,7 @@ static void virtio_serial_nop(void)
 
 static void hotplug(void)
 {
-    qtest_qmp_device_add("virtserialport", "hp-port", NULL);
+    qtest_qmp_device_add("virtserialport", "hp-port", "{}");
 
     qtest_qmp_device_del("hp-port");
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (12 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 15:50   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success() Markus Armbruster
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert

All callers of wait_command() are only interested in the success
response's "return" member.  Lift its extraction into wait_command().

Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
---
 tests/migration-test.c | 38 +++++++++++++++-----------------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/tests/migration-test.c b/tests/migration-test.c
index c6c7089ce1..e336399a71 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -152,7 +152,7 @@ static void wait_for_serial(const char *side)
 static QDict *wait_command(QTestState *who, const char *command)
 {
     const char *event_string;
-    QDict *response;
+    QDict *response, *ret;
 
     response = qtest_qmp(who, command);
 
@@ -165,7 +165,12 @@ static QDict *wait_command(QTestState *who, const char *command)
         qobject_unref(response);
         response = qtest_qmp_receive(who);
     }
-    return response;
+
+    ret = qdict_get_qdict(response, "return");
+    g_assert(ret);
+    qobject_ref(ret);
+    qobject_unref(response);
+    return ret;
 }
 
 /*
@@ -174,15 +179,7 @@ static QDict *wait_command(QTestState *who, const char *command)
  */
 static QDict *migrate_query(QTestState *who)
 {
-    QDict *rsp, *rsp_return;
-
-    rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
-    rsp_return = qdict_get_qdict(rsp, "return");
-    g_assert(rsp_return);
-    qobject_ref(rsp_return);
-    qobject_unref(rsp);
-
-    return rsp_return;
+    return wait_command(who, "{ 'execute': 'query-migrate' }");
 }
 
 /*
@@ -324,16 +321,16 @@ static void cleanup(const char *filename)
 static void migrate_check_parameter(QTestState *who, const char *parameter,
                                     const char *value)
 {
-    QDict *rsp, *rsp_return;
+    QDict *rsp_return;
     char *result;
 
-    rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
-    rsp_return = qdict_get_qdict(rsp, "return");
+    rsp_return = wait_command(who,
+                              "{ 'execute': 'query-migrate-parameters' }");
     result = g_strdup_printf("%" PRId64,
                              qdict_get_try_int(rsp_return,  parameter, -1));
     g_assert_cmpstr(result, ==, value);
     g_free(result);
-    qobject_unref(rsp);
+    qobject_unref(rsp_return);
 }
 
 static void migrate_set_parameter(QTestState *who, const char *parameter,
@@ -357,7 +354,6 @@ static void migrate_pause(QTestState *who)
     QDict *rsp;
 
     rsp = wait_command(who, "{ 'execute': 'migrate-pause' }");
-    g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 }
 
@@ -370,7 +366,6 @@ static void migrate_recover(QTestState *who, const char *uri)
         "  'arguments': { 'uri': '%s' } }", uri);
 
     rsp = wait_command(who, cmd);
-    g_assert(qdict_haskey(rsp, "return"));
     g_free(cmd);
     qobject_unref(rsp);
 }
@@ -411,7 +406,6 @@ static void migrate_postcopy_start(QTestState *from, QTestState *to)
     QDict *rsp;
 
     rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
-    g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 
     if (!got_stop) {
@@ -689,7 +683,7 @@ static void test_postcopy_recovery(void)
 static void test_baddest(void)
 {
     QTestState *from, *to;
-    QDict *rsp, *rsp_return;
+    QDict *rsp_return;
     char *status;
     bool failed;
 
@@ -705,12 +699,10 @@ static void test_baddest(void)
     } while (!failed);
 
     /* Is the machine currently running? */
-    rsp = wait_command(from, "{ 'execute': 'query-status' }");
-    g_assert(qdict_haskey(rsp, "return"));
-    rsp_return = qdict_get_qdict(rsp, "return");
+    rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
     g_assert(qdict_haskey(rsp_return, "running"));
     g_assert(qdict_get_bool(rsp_return, "running"));
-    qobject_unref(rsp);
+    qobject_unref(rsp_return);
 
     test_migrate_end(from, to, false);
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (13 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:00   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%' Markus Armbruster
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert,
	Stefan Berger

Commit b21373d0713 copied wait_command() from tests/migration-test.c
to tests/tpm-util.c.  Replace both copies by new libqtest helper
qtest_qmp_receive_success().  Also use it to simplify
qtest_qmp_device_del().

Bonus: gets rid of a non-literal format string.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Cc: Thomas Huth <thuth@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Cc: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 tests/libqtest.c       | 69 ++++++++++++++++++++++++++++++------------
 tests/libqtest.h       | 17 +++++++++++
 tests/migration-test.c | 29 ++++++------------
 tests/tpm-util.c       | 32 +++-----------------
 4 files changed, 80 insertions(+), 67 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index dfca3af89d..ed832cd8e6 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1029,6 +1029,35 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
     qobject_unref(response);
 }
 
+QDict *qtest_qmp_receive_success(QTestState *s,
+                                 void (*event_cb)(void *opaque,
+                                                  const char *event,
+                                                  QDict *data),
+                                 void *opaque)
+{
+    QDict *response, *ret, *data;
+    const char *event;
+
+    for (;;) {
+        response = qtest_qmp_receive(s);
+        g_assert(!qdict_haskey(response, "error"));
+        ret = qdict_get_qdict(response, "return");
+        if (ret) {
+            break;
+        }
+        event = qdict_get_str(response, "event");
+        data = qdict_get_qdict(response, "data");
+        if (event_cb) {
+            event_cb(opaque, event, data);
+        }
+        qobject_unref(response);
+    }
+
+    qobject_ref(ret);
+    qobject_unref(response);
+    return ret;
+}
+
 /*
  * Generic hot-plugging test via the device_add QMP command.
  */
@@ -1053,6 +1082,14 @@ void qtest_qmp_device_add(const char *driver, const char *id,
     qobject_unref(response);
 }
 
+static void device_deleted_cb(void *opaque, const char *name, QDict *data)
+{
+    bool *got_event = opaque;
+
+    g_assert_cmpstr(name, ==, "DEVICE_DELETED");
+    *got_event = true;
+}
+
 /*
  * Generic hot-unplugging test via the device_del QMP command.
  * Device deletion will get one response and one event. For example:
@@ -1073,27 +1110,21 @@ void qtest_qmp_device_add(const char *driver, const char *id,
  */
 void qtest_qmp_device_del(const char *id)
 {
-    QDict *response1, *response2, *event = NULL;
+    bool got_event = false;
+    QDict *rsp;
 
-    response1 = qmp("{'execute': 'device_del', 'arguments': {'id': %s}}",
-                    id);
-    g_assert(response1);
-    g_assert(!qdict_haskey(response1, "error"));
-
-    response2 = qmp_receive();
-    g_assert(response2);
-    g_assert(!qdict_haskey(response2, "error"));
-
-    if (qdict_haskey(response1, "event")) {
-        event = response1;
-    } else if (qdict_haskey(response2, "event")) {
-        event = response2;
+    qtest_qmp_send(global_qtest,
+                   "{'execute': 'device_del', 'arguments': {'id': %s}}",
+                   id);
+    rsp = qtest_qmp_receive_success(global_qtest, device_deleted_cb,
+                                    &got_event);
+    qobject_unref(rsp);
+    if (!got_event) {
+        rsp = qmp_receive();
+        g_assert_cmpstr(qdict_get_try_str(rsp, "event"),
+                        ==, "DEVICE_DELETED");
+        qobject_unref(rsp);
     }
-    g_assert(event);
-    g_assert_cmpstr(qdict_get_str(event, "event"), ==, "DEVICE_DELETED");
-
-    qobject_unref(response1);
-    qobject_unref(response2);
 }
 
 bool qmp_rsp_is_err(QDict *rsp)
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ce6c092fc9..ee58fcdf6d 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -169,6 +169,23 @@ void qtest_qmp_eventwait(QTestState *s, const char *event);
  */
 QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
 
+/**
+ * qtest_qmp_receive_success:
+ * @s: #QTestState instance to operate on
+ * @event_cb: Event callback
+ * @opaque: Argument for @event_cb
+ *
+ * Poll QMP messages until a command success response is received.
+ * If @event_cb, call it for each event received, passing @opaque,
+ * the event's name and data.
+ * Return the success response's "return" member.
+ */
+QDict *qtest_qmp_receive_success(QTestState *s,
+                                 void (*event_cb)(void *opaque,
+                                                  const char *name,
+                                                  QDict *data),
+                                 void *opaque);
+
 /**
  * qtest_hmp:
  * @s: #QTestState instance to operate on.
diff --git a/tests/migration-test.c b/tests/migration-test.c
index e336399a71..860b8aa0b9 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -146,31 +146,20 @@ static void wait_for_serial(const char *side)
     } while (true);
 }
 
+static void stop_cb(void *opaque, const char *name, QDict *data)
+{
+    if (!strcmp(name, "STOP")) {
+        got_stop = true;
+    }
+}
+
 /*
  * Events can get in the way of responses we are actually waiting for.
  */
 static QDict *wait_command(QTestState *who, const char *command)
 {
-    const char *event_string;
-    QDict *response, *ret;
-
-    response = qtest_qmp(who, command);
-
-    while (qdict_haskey(response, "event")) {
-        /* OK, it was an event */
-        event_string = qdict_get_str(response, "event");
-        if (!strcmp(event_string, "STOP")) {
-            got_stop = true;
-        }
-        qobject_unref(response);
-        response = qtest_qmp_receive(who);
-    }
-
-    ret = qdict_get_qdict(response, "return");
-    g_assert(ret);
-    qobject_ref(ret);
-    qobject_unref(response);
-    return ret;
+    qtest_qmp_send(who, command);
+    return qtest_qmp_receive_success(who, stop_cb, NULL);
 }
 
 /*
diff --git a/tests/tpm-util.c b/tests/tpm-util.c
index 3bd2887f1e..9f3f156e42 100644
--- a/tests/tpm-util.c
+++ b/tests/tpm-util.c
@@ -22,8 +22,6 @@
 #define TIS_REG(LOCTY, REG) \
     (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
 
-static bool got_stop;
-
 void tpm_util_crb_transfer(QTestState *s,
                            const unsigned char *req, size_t req_size,
                            unsigned char *rsp, size_t rsp_size)
@@ -247,41 +245,19 @@ void tpm_util_migrate(QTestState *who, const char *uri)
     qobject_unref(rsp);
 }
 
-/*
- * Events can get in the way of responses we are actually waiting for.
- */
-static QDict *tpm_util_wait_command(QTestState *who, const char *command)
-{
-    const char *event_string;
-    QDict *response;
-
-    response = qtest_qmp(who, command);
-
-    while (qdict_haskey(response, "event")) {
-        /* OK, it was an event */
-        event_string = qdict_get_str(response, "event");
-        if (!strcmp(event_string, "STOP")) {
-            got_stop = true;
-        }
-        qobject_unref(response);
-        response = qtest_qmp_receive(who);
-    }
-    return response;
-}
-
 void tpm_util_wait_for_migration_complete(QTestState *who)
 {
     while (true) {
-        QDict *rsp, *rsp_return;
+        QDict *rsp_return;
         bool completed;
         const char *status;
 
-        rsp = tpm_util_wait_command(who, "{ 'execute': 'query-migrate' }");
-        rsp_return = qdict_get_qdict(rsp, "return");
+        qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");
+        rsp_return = qtest_qmp_receive_success(who, NULL, NULL);
         status = qdict_get_str(rsp_return, "status");
         completed = strcmp(status, "completed") == 0;
         g_assert_cmpstr(status, !=,  "failed");
-        qobject_unref(rsp);
+        qobject_unref(rsp_return);
         if (completed) {
             return;
         }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%'
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (14 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:02   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1 Markus Armbruster
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert

wait_command() passes its argument @command to qtest_qmp_send().
Falls apart if @command contain '%'.  Two ways to disarm this trap:
suppress interpretation of '%' by passing @command as argument to
format string "%s", or fix it by having wait_command() take the
variable arguments to go with @command.  Do the latter.

This is another step towards compile-time format string checking
without triggering -Wformat-nonliteral.

Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
---
 tests/migration-test.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tests/migration-test.c b/tests/migration-test.c
index 860b8aa0b9..0c92f2b1cd 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -156,9 +156,14 @@ static void stop_cb(void *opaque, const char *name, QDict *data)
 /*
  * Events can get in the way of responses we are actually waiting for.
  */
-static QDict *wait_command(QTestState *who, const char *command)
+static QDict *wait_command(QTestState *who, const char *command, ...)
 {
-    qtest_qmp_send(who, command);
+    va_list ap;
+
+    va_start(ap, command);
+    qtest_qmp_vsend(who, command, ap);
+    va_end(ap);
+
     return qtest_qmp_receive_success(who, stop_cb, NULL);
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (15 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%' Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:04   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2 Markus Armbruster
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert

Leaving interpolation into JSON to qmp() is more robust than building
QMP input manually, as explained in the recent commit "tests: Clean up
string interpolation into QMP input (simple cases)".

migrate_recover() builds QMP input manually because wait_command()
can't interpolate.  Well, it can since the previous commit.  Simplify
accordingly.

Bonus: gets rid of a non-literal format string.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
---
 tests/migration-test.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/migration-test.c b/tests/migration-test.c
index 0c92f2b1cd..323bb60535 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -156,6 +156,7 @@ static void stop_cb(void *opaque, const char *name, QDict *data)
 /*
  * Events can get in the way of responses we are actually waiting for.
  */
+GCC_FMT_ATTR(2, 3)
 static QDict *wait_command(QTestState *who, const char *command, ...)
 {
     va_list ap;
@@ -354,13 +355,12 @@ static void migrate_pause(QTestState *who)
 static void migrate_recover(QTestState *who, const char *uri)
 {
     QDict *rsp;
-    gchar *cmd = g_strdup_printf(
-        "{ 'execute': 'migrate-recover', "
-        "  'id': 'recover-cmd', "
-        "  'arguments': { 'uri': '%s' } }", uri);
 
-    rsp = wait_command(who, cmd);
-    g_free(cmd);
+    rsp = wait_command(who,
+                       "{ 'execute': 'migrate-recover', "
+                       "  'id': 'recover-cmd', "
+                       "  'arguments': { 'uri': %s } }",
+                       uri);
     qobject_unref(rsp);
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (16 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1 Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:05   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3 Markus Armbruster
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert

Leaving interpolation into JSON to qmp() is more robust than building
QMP input manually, as explained in the recent commit "tests: Clean up
string interpolation into QMP input (simple cases)".

migrate() interpolates members into a JSON object.  Change it to take
its extra QMP arguments as arguments for qdict_from_jsonf_nofail()
instead of a string containing JSON members.

Bonus: gets rid of a non-literal format string.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
---
 tests/migration-test.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/tests/migration-test.c b/tests/migration-test.c
index 323bb60535..1c1e56b15b 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -14,6 +14,7 @@
 
 #include "libqtest.h"
 #include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
 #include "qemu/option.h"
 #include "qemu/range.h"
 #include "qemu/sockets.h"
@@ -381,16 +382,19 @@ static void migrate_set_capability(QTestState *who, const char *capability,
     qobject_unref(rsp);
 }
 
-static void migrate(QTestState *who, const char *uri, const char *extra)
+static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
 {
-    QDict *rsp;
-    gchar *cmd;
+    va_list ap;
+    QDict *args, *rsp;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate',"
-                          "  'arguments': { 'uri': '%s' %s } }",
-                          uri, extra ? extra : "");
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    va_start(ap, fmt);
+    args = qdict_from_vjsonf_nofail(fmt, ap);
+    va_end(ap);
+
+    g_assert(!qdict_haskey(args, "uri"));
+    qdict_put_str(args, "uri", uri);
+
+    rsp = qmp("{ 'execute': 'migrate', 'arguments': %p}", args);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 }
@@ -582,7 +586,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate(from, uri, NULL);
+    migrate(from, uri, "{}");
     g_free(uri);
 
     wait_for_migration_pass(from);
@@ -665,7 +669,7 @@ static void test_postcopy_recovery(void)
      * the newly created channel
      */
     wait_for_migration_status(from, "postcopy-paused");
-    migrate(from, uri, ", 'resume': true");
+    migrate(from, uri, "{'resume': true}");
     g_free(uri);
 
     /* Restore the postcopy bandwidth to unlimited */
@@ -684,7 +688,7 @@ static void test_baddest(void)
     if (test_migrate_start(&from, &to, "tcp:0:0", true)) {
         return;
     }
-    migrate(from, "tcp:0:0", NULL);
+    migrate(from, "tcp:0:0", "{}");
     do {
         status = migrate_query_status(from);
         g_assert(!strcmp(status, "setup") || !(strcmp(status, "failed")));
@@ -722,7 +726,7 @@ static void test_precopy_unix(void)
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate(from, uri, NULL);
+    migrate(from, uri, "{}");
 
     wait_for_migration_pass(from);
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (17 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2 Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:11   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking Markus Armbruster
                   ` (3 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake, Juan Quintela, Dr . David Alan Gilbert

Leaving interpolation into JSON to qmp() is more robust than building
QMP input manually, as explained in the recent commit "tests: Clean up
string interpolation into QMP input (simple cases)".

migration-test.c interpolates strings into JSON in a few places:

* migrate_set_parameter() interpolates string parameter @value as a
  JSON number.  Change it to long long.  This requires changing
  migrate_check_parameter() similarly.

* migrate_set_capability() interpolates string parameter @value as a
  JSON boolean.  Change it to bool.

* deprecated_set_speed() interpolates string parameter @value as a
  JSON number.  Change it to long long.

Bonus: gets rid of non-literal format strings.  A step towards
compile-time format string checking without triggering
-Wformat-nonliteral.

Cc: Juan Quintela <quintela@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
---
 tests/migration-test.c | 74 +++++++++++++++++-------------------------
 1 file changed, 29 insertions(+), 45 deletions(-)

diff --git a/tests/migration-test.c b/tests/migration-test.c
index 1c1e56b15b..132c30891d 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -315,31 +315,25 @@ static void cleanup(const char *filename)
 }
 
 static void migrate_check_parameter(QTestState *who, const char *parameter,
-                                    const char *value)
+                                    long long value)
 {
     QDict *rsp_return;
-    char *result;
 
     rsp_return = wait_command(who,
                               "{ 'execute': 'query-migrate-parameters' }");
-    result = g_strdup_printf("%" PRId64,
-                             qdict_get_try_int(rsp_return,  parameter, -1));
-    g_assert_cmpstr(result, ==, value);
-    g_free(result);
+    g_assert_cmpint(qdict_get_int(rsp_return,  parameter), ==, value);
     qobject_unref(rsp_return);
 }
 
 static void migrate_set_parameter(QTestState *who, const char *parameter,
-                                  const char *value)
+                                  long long value)
 {
     QDict *rsp;
-    gchar *cmd;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
-                          "'arguments': { '%s': %s } }",
-                          parameter, value);
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate-set-parameters',"
+                    "'arguments': { %s: %lld } }",
+                    parameter, value);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
     migrate_check_parameter(who, parameter, value);
@@ -366,18 +360,16 @@ static void migrate_recover(QTestState *who, const char *uri)
 }
 
 static void migrate_set_capability(QTestState *who, const char *capability,
-                                   const char *value)
+                                   bool value)
 {
     QDict *rsp;
-    gchar *cmd;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate-set-capabilities',"
-                          "'arguments': { "
-                          "'capabilities': [ { "
-                          "'capability': '%s', 'state': %s } ] } }",
-                          capability, value);
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    rsp = qtest_qmp(who,
+                    "{ 'execute': 'migrate-set-capabilities',"
+                    "'arguments': { "
+                    "'capabilities': [ { "
+                    "'capability': %s, 'state': %i } ] } }",
+                    capability, value);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
 }
@@ -521,29 +513,21 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
 static void deprecated_set_downtime(QTestState *who, const double value)
 {
     QDict *rsp;
-    char *expected;
-    int64_t result_int;
 
     rsp = qtest_qmp(who,
                     "{ 'execute': 'migrate_set_downtime',"
                     " 'arguments': { 'value': %f } }", value);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
-    result_int = value * 1000L;
-    expected = g_strdup_printf("%" PRId64, result_int);
-    migrate_check_parameter(who, "downtime-limit", expected);
-    g_free(expected);
+    migrate_check_parameter(who, "downtime-limit", value * 1000);
 }
 
-static void deprecated_set_speed(QTestState *who, const char *value)
+static void deprecated_set_speed(QTestState *who, long long value)
 {
     QDict *rsp;
-    gchar *cmd;
 
-    cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
-                          "'arguments': { 'value': %s } }", value);
-    rsp = qtest_qmp(who, cmd);
-    g_free(cmd);
+    rsp = qtest_qmp(who, "{ 'execute': 'migrate_set_speed',"
+                          "'arguments': { 'value': %lld } }", value);
     g_assert(qdict_haskey(rsp, "return"));
     qobject_unref(rsp);
     migrate_check_parameter(who, "max-bandwidth", value);
@@ -556,7 +540,7 @@ static void test_deprecated(void)
     from = qtest_start("");
 
     deprecated_set_downtime(from, 0.12345);
-    deprecated_set_speed(from, "12345");
+    deprecated_set_speed(from, 12345);
 
     qtest_quit(from);
 }
@@ -572,16 +556,16 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
         return -1;
     }
 
-    migrate_set_capability(from, "postcopy-ram", "true");
-    migrate_set_capability(to, "postcopy-ram", "true");
-    migrate_set_capability(to, "postcopy-blocktime", "true");
+    migrate_set_capability(from, "postcopy-ram", true);
+    migrate_set_capability(to, "postcopy-ram", true);
+    migrate_set_capability(to, "postcopy-blocktime", true);
 
     /* We want to pick a speed slow enough that the test completes
      * quickly, but that it doesn't complete precopy even on a slow
      * machine, so also set the downtime.
      */
-    migrate_set_parameter(from, "max-bandwidth", "100000000");
-    migrate_set_parameter(from, "downtime-limit", "1");
+    migrate_set_parameter(from, "max-bandwidth", 100000000);
+    migrate_set_parameter(from, "downtime-limit", 1);
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
@@ -632,7 +616,7 @@ static void test_postcopy_recovery(void)
     }
 
     /* Turn postcopy speed down, 4K/s is slow enough on any machines */
-    migrate_set_parameter(from, "max-postcopy-bandwidth", "4096");
+    migrate_set_parameter(from, "max-postcopy-bandwidth", 4096);
 
     /* Now we start the postcopy */
     migrate_postcopy_start(from, to);
@@ -673,7 +657,7 @@ static void test_postcopy_recovery(void)
     g_free(uri);
 
     /* Restore the postcopy bandwidth to unlimited */
-    migrate_set_parameter(from, "max-postcopy-bandwidth", "0");
+    migrate_set_parameter(from, "max-postcopy-bandwidth", 0);
 
     migrate_postcopy_complete(from, to);
 }
@@ -719,9 +703,9 @@ static void test_precopy_unix(void)
      * machine, so also set the downtime.
      */
     /* 1 ms should make it not converge*/
-    migrate_set_parameter(from, "downtime-limit", "1");
+    migrate_set_parameter(from, "downtime-limit", 1);
     /* 1GB/s */
-    migrate_set_parameter(from, "max-bandwidth", "1000000000");
+    migrate_set_parameter(from, "max-bandwidth", 1000000000);
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
@@ -731,7 +715,7 @@ static void test_precopy_unix(void)
     wait_for_migration_pass(from);
 
     /* 300 ms should converge */
-    migrate_set_parameter(from, "downtime-limit", "300");
+    migrate_set_parameter(from, "downtime-limit", 300);
 
     if (!got_stop) {
         qtest_qmp_eventwait(from, "STOP");
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (18 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3 Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:18   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends Markus Armbruster
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qtest_qmp() & friends pass their format string and variable arguments
to qobject_from_vjsonf_nofail().  Unlike qobject_from_jsonv(), they
aren't decorated with GCC_FMT_ATTR().  Fix that to get compile-time
format string checking.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 tests/libqtest.h | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/tests/libqtest.h b/tests/libqtest.h
index ee58fcdf6d..327e402da5 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -82,7 +82,8 @@ void qtest_quit(QTestState *s);
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
-void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
+void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
 
 /**
  * qtest_qmp:
@@ -93,7 +94,8 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and returns the response.
  */
-QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
+QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
 
 /**
  * qtest_qmp_send:
@@ -104,7 +106,8 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qtest_qmp_send(QTestState *s, const char *fmt, ...);
+void qtest_qmp_send(QTestState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
 
 /**
  * qtest_qmpv_discard_response:
@@ -116,7 +119,8 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
-void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
+void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
 
 /**
  * qtest_qmpv:
@@ -128,7 +132,8 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
  *
  * Sends a QMP message to QEMU and returns the response.
  */
-QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
+QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
 
 /**
  * qtest_qmp_vsend:
@@ -140,7 +145,8 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap);
+void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
 
 /**
  * qtest_receive:
@@ -597,7 +603,7 @@ static inline void qtest_end(void)
  *
  * Sends a QMP message to QEMU and returns the response.
  */
-QDict *qmp(const char *fmt, ...);
+QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
 /**
  * qmp_send:
@@ -607,7 +613,7 @@ QDict *qmp(const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and leaves the response in the stream.
  */
-void qmp_send(const char *fmt, ...);
+void qmp_send(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
 /**
  * qmp_discard_response:
@@ -617,7 +623,7 @@ void qmp_send(const char *fmt, ...);
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
-void qmp_discard_response(const char *fmt, ...);
+void qmp_discard_response(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
 /**
  * qmp_receive:
@@ -976,10 +982,10 @@ static inline int64_t clock_set(int64_t val)
 }
 
 QDict *qmp_fd_receive(int fd);
-void qmp_fd_vsend(int fd, const char *fmt, va_list ap);
-void qmp_fd_send(int fd, const char *fmt, ...);
-QDict *qmp_fdv(int fd, const char *fmt, va_list ap);
-QDict *qmp_fd(int fd, const char *fmt, ...);
+void qmp_fd_vsend(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+void qmp_fd_send(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+QDict *qmp_fdv(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+QDict *qmp_fd(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 
 /**
  * qtest_cb_for_every_machine:
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (19 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 16:46   ` Thomas Huth
  2018-07-27 17:05   ` Eric Blake
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf() Markus Armbruster
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency Markus Armbruster
  22 siblings, 2 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qtest_qmp_discard_response(...) is shorthand for
qobject_unref(qtest_qmp(...), except it's not actually shorter.
Moreover, the presence of these functions encourage sloppy testing.
Remove them.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/ahci-test.c              | 12 ++++++------
 tests/boot-order-test.c        |  4 ++--
 tests/drive_del-test.c         |  4 ++--
 tests/fdc-test.c               |  9 +++++----
 tests/ide-test.c               |  4 ++--
 tests/libqtest.c               | 27 +-------------------------
 tests/libqtest.h               | 35 ----------------------------------
 tests/migration-test.c         |  2 +-
 tests/test-filter-mirror.c     |  3 ++-
 tests/test-filter-redirector.c |  5 +++--
 tests/virtio-blk-test.c        | 19 +++++++++---------
 11 files changed, 34 insertions(+), 90 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 19a7ab1bca..7a2d70fa34 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1596,8 +1596,8 @@ static void test_atapi_tray(void)
     rsp = qmp_receive();
     qobject_unref(rsp);
 
-    qmp_discard_response("{'execute': 'blockdev-remove-medium', "
-                         "'arguments': {'id': 'cd0'}}");
+    qobject_unref(qmp("{'execute': 'blockdev-remove-medium', "
+                      "'arguments': {'id': 'cd0'}}"));
 
     /* Test the tray without a medium */
     ahci_atapi_load(ahci, port);
@@ -1607,14 +1607,14 @@ static void test_atapi_tray(void)
     atapi_wait_tray(true);
 
     /* Re-insert media */
-    qmp_discard_response("{'execute': 'blockdev-add', "
+    qobject_unref(qmp("{'execute': 'blockdev-add', "
                           "'arguments': {'node-name': 'node0', "
                                         "'driver': 'raw', "
                                         "'file': { 'driver': 'file', "
-                                                  "'filename': %s }}}", iso);
-    qmp_discard_response("{'execute': 'blockdev-insert-medium',"
+                      "'filename': %s }}}", iso));
+    qobject_unref(qmp("{'execute': 'blockdev-insert-medium',"
                           "'arguments': { 'id': 'cd0', "
-                                         "'node-name': 'node0' }}");
+                      "'node-name': 'node0' }}"));
 
     /* Again, the event shows up first */
     qmp_send("{'execute': 'blockdev-close-tray',"
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index e70f5dedba..2ec86c0ee2 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -13,7 +13,7 @@
 #include "qemu/osdep.h"
 #include "libqos/fw_cfg.h"
 #include "libqtest.h"
-
+#include "qapi/qmp/qdict.h"
 #include "hw/nvram/fw_cfg_keys.h"
 
 typedef struct {
@@ -36,7 +36,7 @@ static void test_a_boot_order(const char *machine,
                                 test_args);
     actual = read_boot_order();
     g_assert_cmphex(actual, ==, expected_boot);
-    qmp_discard_response("{ 'execute': 'system_reset' }");
+    qobject_unref(qmp("{ 'execute': 'system_reset' }"));
     /*
      * system_reset only requests reset.  We get a RESET event after
      * the actual reset completes.  Need to wait for that.
diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c
index 852fefc8f3..92489be0ba 100644
--- a/tests/drive_del-test.c
+++ b/tests/drive_del-test.c
@@ -36,8 +36,8 @@ static void device_del(void)
     QDict *response;
 
     /* Complication: ignore DEVICE_DELETED event */
-    qmp_discard_response("{'execute': 'device_del',"
-                         " 'arguments': { 'id': 'dev0' } }");
+    qobject_unref(qmp("{'execute': 'device_del',"
+                      " 'arguments': { 'id': 'dev0' } }"));
     response = qmp_receive();
     g_assert(response);
     g_assert(qdict_haskey(response, "return"));
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 325712e0f2..5775555e71 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -26,6 +26,7 @@
 
 
 #include "libqtest.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu-common.h"
 
 #define TEST_IMAGE_SIZE 1440 * 1024
@@ -298,9 +299,9 @@ static void test_media_insert(void)
 
     /* Insert media in drive. DSKCHK should not be reset until a step pulse
      * is sent. */
-    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
+    qobject_unref(qmp("{'execute':'blockdev-change-medium', 'arguments':{"
                          " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
-                         test_image);
+                      test_image));
 
     dir = inb(FLOPPY_BASE + reg_dir);
     assert_bit_set(dir, DSKCHG);
@@ -329,8 +330,8 @@ static void test_media_change(void)
 
     /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
      * reset the bit. */
-    qmp_discard_response("{'execute':'eject', 'arguments':{"
-                         " 'id':'floppy0' }}");
+    qobject_unref(qmp("{'execute':'eject', 'arguments':{"
+                      " 'id':'floppy0' }}"));
 
     dir = inb(FLOPPY_BASE + reg_dir);
     assert_bit_set(dir, DSKCHG);
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 834ee9005b..48bb0e6519 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -29,7 +29,7 @@
 #include "libqos/libqos.h"
 #include "libqos/pci-pc.h"
 #include "libqos/malloc-pc.h"
-
+#include "qapi/qmp/qdict.h"
 #include "qemu-common.h"
 #include "qemu/bswap.h"
 #include "hw/pci/pci_ids.h"
@@ -721,7 +721,7 @@ static void test_retry_flush(const char *machine)
     qmp_eventwait("STOP");
 
     /* Complete the command */
-    qmp_discard_response("{'execute':'cont' }");
+    qobject_unref(qmp("{'execute':'cont' }"));
 
     /* Check registers */
     data = qpci_io_readb(dev, ide_bar, reg_device);
diff --git a/tests/libqtest.c b/tests/libqtest.c
index ed832cd8e6..2f81bc6382 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -254,7 +254,7 @@ QTestState *qtest_init(const char *extra_args)
     /* Read the QMP greeting and then do the handshake */
     greeting = qtest_qmp_receive(s);
     qobject_unref(greeting);
-    qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }");
+    qobject_unref(qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }"));
 
     return s;
 }
@@ -587,23 +587,6 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...)
     va_end(ap);
 }
 
-void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
-{
-    QDict *response = qtest_qmpv(s, fmt, ap);
-    qobject_unref(response);
-}
-
-void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_qmpv(s, fmt, ap);
-    va_end(ap);
-    qobject_unref(response);
-}
-
 QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
 {
     QDict *response;
@@ -975,14 +958,6 @@ void qmp_send(const char *fmt, ...)
     va_end(ap);
 }
 
-void qmp_discard_response(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qtest_qmpv_discard_response(global_qtest, fmt, ap);
-    va_end(ap);
-}
 char *hmp(const char *fmt, ...)
 {
     va_list ap;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 327e402da5..58dea82c76 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -73,18 +73,6 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
  */
 void qtest_quit(QTestState *s);
 
-/**
- * qtest_qmp_discard_response:
- * @s: #QTestState instance to operate on.
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().
- * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
- *
- * Sends a QMP message to QEMU and consumes the response.
- */
-void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...)
-    GCC_FMT_ATTR(2, 3);
-
 /**
  * qtest_qmp:
  * @s: #QTestState instance to operate on.
@@ -109,19 +97,6 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
 void qtest_qmp_send(QTestState *s, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
 
-/**
- * qtest_qmpv_discard_response:
- * @s: #QTestState instance to operate on.
- * @fmt: QMP message to send to QEMU, formatted like
- * qobject_from_jsonf_nofail().
- * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
- * @ap: QMP message arguments
- *
- * Sends a QMP message to QEMU and consumes the response.
- */
-void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
-    GCC_FMT_ATTR(2, 0);
-
 /**
  * qtest_qmpv:
  * @s: #QTestState instance to operate on.
@@ -615,16 +590,6 @@ QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
  */
 void qmp_send(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
-/**
- * qmp_discard_response:
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().
- * Only understands '%((l|ll|I64)?d|[ipsf])', see parse_escape().
- *
- * Sends a QMP message to QEMU and consumes the response.
- */
-void qmp_discard_response(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-
 /**
  * qmp_receive:
  *
diff --git a/tests/migration-test.c b/tests/migration-test.c
index 132c30891d..1bcd32e284 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -491,7 +491,7 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
             usleep(1000 * 10);
         } while (dest_byte_a == dest_byte_b);
 
-        qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
+        qobject_unref(qtest_qmp(to, "{ 'execute' : 'stop'}"));
 
         /* With it stopped, check nothing changes */
         qtest_memread(to, start_address, &dest_byte_c, 1);
diff --git a/tests/test-filter-mirror.c b/tests/test-filter-mirror.c
index 6c6f710dc6..1ab4759b80 100644
--- a/tests/test-filter-mirror.c
+++ b/tests/test-filter-mirror.c
@@ -10,6 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu/iov.h"
 #include "qemu/sockets.h"
 #include "qemu/error-report.h"
@@ -57,7 +58,7 @@ static void test_mirror(void)
     };
 
     /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response("{ 'execute' : 'query-status'}");
+    qobject_unref(qmp("{ 'execute' : 'query-status'}"));
     ret = iov_send(send_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
     g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
     close(send_sock[0]);
diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c
index fbaf19bbd8..5b6c594867 100644
--- a/tests/test-filter-redirector.c
+++ b/tests/test-filter-redirector.c
@@ -52,6 +52,7 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu/iov.h"
 #include "qemu/sockets.h"
 #include "qemu/error-report.h"
@@ -104,7 +105,7 @@ static void test_redirector_tx(void)
     g_assert_cmpint(recv_sock, !=, -1);
 
     /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response("{ 'execute' : 'query-status'}");
+    qobject_unref(qmp("{ 'execute' : 'query-status'}"));
 
     struct iovec iov[] = {
         {
@@ -182,7 +183,7 @@ static void test_redirector_rx(void)
     send_sock = unix_connect(sock_path1, NULL);
     g_assert_cmpint(send_sock, !=, -1);
     /* send a qmp command to guarantee that 'connected' is setting to true. */
-    qmp_discard_response("{ 'execute' : 'query-status'}");
+    qobject_unref(qmp("{ 'execute' : 'query-status'}"));
 
     ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf));
     g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index d96b4c69e1..5955bf6d57 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -16,6 +16,7 @@
 #include "libqos/virtio-pci.h"
 #include "libqos/virtio-mmio.h"
 #include "libqos/malloc-generic.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu/bswap.h"
 #include "standard-headers/linux/virtio_ids.h"
 #include "standard-headers/linux/virtio_config.h"
@@ -409,9 +410,9 @@ static void pci_config(void)
 
     qvirtio_set_driver_ok(&dev->vdev);
 
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
+    qobject_unref(qmp("{ 'execute': 'block_resize', "
+                      " 'arguments': { 'device': 'drive0', "
+                      " 'size': %d } }", n_size));
     qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
 
     capacity = qvirtio_config_readq(&dev->vdev, 0);
@@ -459,9 +460,9 @@ static void pci_msix(void)
 
     qvirtio_set_driver_ok(&dev->vdev);
 
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
+    qobject_unref(qmp("{ 'execute': 'block_resize', "
+                      " 'arguments': { 'device': 'drive0', "
+                      " 'size': %d } }", n_size));
 
     qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
 
@@ -725,9 +726,9 @@ static void mmio_basic(void)
 
     test_basic(&dev->vdev, alloc, vq);
 
-    qmp_discard_response("{ 'execute': 'block_resize', "
-                         " 'arguments': { 'device': 'drive0', "
-                         " 'size': %d } }", n_size);
+    qobject_unref(qmp("{ 'execute': 'block_resize', "
+                      " 'arguments': { 'device': 'drive0', "
+                      " 'size': %d } }", n_size));
 
     qvirtio_wait_queue_isr(&dev->vdev, vq, QVIRTIO_BLK_TIMEOUT_US);
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf()
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (20 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 17:08   ` Eric Blake
  2018-07-27 17:18   ` Thomas Huth
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency Markus Armbruster
  22 siblings, 2 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

qtest_init() creates a new QTestState, and leaves @global_qtest alone.
qtest_start() additionally assigns it to @global_qtest, but
qtest_startf() additionall sets assigns NULL to @global_qtest.  This
makes no sense.  Replace it by qtest_initf() that works like
qtest_init(), i.e. leaves @global_qtest alone.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/boot-order-test.c        |  8 ++++----
 tests/boot-serial-test.c       | 10 +++++-----
 tests/cdrom-test.c             |  6 +++---
 tests/endianness-test.c        | 24 ++++++++++++------------
 tests/ipmi-bt-test.c           |  2 +-
 tests/libqtest.c               |  9 ++++-----
 tests/libqtest.h               | 17 ++++++++---------
 tests/m25p80-test.c            |  6 +++---
 tests/m48t59-test.c            |  2 +-
 tests/machine-none-test.c      |  2 +-
 tests/numa-test.c              |  4 ++--
 tests/pnv-xscom-test.c         |  8 ++++----
 tests/prom-env-test.c          | 10 +++++-----
 tests/qmp-test.c               |  2 +-
 tests/sdhci-test.c             |  6 +++---
 tests/tco-test.c               |  6 +++---
 tests/test-filter-mirror.c     |  2 +-
 tests/test-filter-redirector.c |  4 ++--
 tests/virtio-balloon-test.c    |  4 ++--
 tests/virtio-blk-test.c        |  8 ++++----
 tests/virtio-console-test.c    | 12 ++++++------
 tests/virtio-serial-test.c     |  4 ++--
 tests/vmgenid-test.c           |  6 +++---
 23 files changed, 80 insertions(+), 82 deletions(-)

diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index 2ec86c0ee2..bf0702945b 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -30,10 +30,10 @@ static void test_a_boot_order(const char *machine,
 {
     uint64_t actual;
 
-    global_qtest = qtest_startf("-nodefaults%s%s %s",
-                                machine ? " -M " : "",
-                                machine ?: "",
-                                test_args);
+    global_qtest = qtest_initf("-nodefaults%s%s %s",
+                               machine ? " -M " : "",
+                               machine ?: "",
+                               test_args);
     actual = read_boot_order();
     g_assert_cmphex(actual, ==, expected_boot);
     qobject_unref(qmp("{ 'execute': 'system_reset' }"));
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index 952a2e7ead..1355df924d 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -172,11 +172,11 @@ static void test_machine(const void *data)
      * Make sure that this test uses tcg if available: It is used as a
      * fast-enough smoketest for that.
      */
-    global_qtest = qtest_startf("%s %s -M %s,accel=tcg:kvm "
-                                "-chardev file,id=serial0,path=%s "
-                                "-no-shutdown -serial chardev:serial0 %s",
-                                codeparam, code ? codetmp : "",
-                                test->machine, serialtmp, test->extra);
+    global_qtest = qtest_initf("%s %s -M %s,accel=tcg:kvm "
+                               "-chardev file,id=serial0,path=%s "
+                               "-no-shutdown -serial chardev:serial0 %s",
+                               codeparam, code ? codetmp : "",
+                               test->machine, serialtmp, test->extra);
     if (code) {
         unlink(codetmp);
     }
diff --git a/tests/cdrom-test.c b/tests/cdrom-test.c
index 7a1fce5dfb..9b43dc9ab4 100644
--- a/tests/cdrom-test.c
+++ b/tests/cdrom-test.c
@@ -99,7 +99,7 @@ static void test_cdrom_param(gconstpointer data)
     QTestState *qts;
     char *resp;
 
-    qts = qtest_startf("-M %s -cdrom %s", (const char *)data, isoimage);
+    qts = qtest_initf("-M %s -cdrom %s", (const char *)data, isoimage);
     resp = qtest_hmp(qts, "info block");
     g_assert(strstr(resp, isoimage) != 0);
     g_free(resp);
@@ -120,8 +120,8 @@ static void test_cdboot(gconstpointer data)
 {
     QTestState *qts;
 
-    qts = qtest_startf("-accel kvm:tcg -no-shutdown %s%s", (const char *)data,
-                       isoimage);
+    qts = qtest_initf("-accel kvm:tcg -no-shutdown %s%s", (const char *)data,
+                      isoimage);
     boot_sector_test(qts);
     qtest_quit(qts);
 }
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
index 546e0969e4..48680cd131 100644
--- a/tests/endianness-test.c
+++ b/tests/endianness-test.c
@@ -115,10 +115,10 @@ static void test_endianness(gconstpointer data)
 {
     const TestCase *test = data;
 
-    global_qtest = qtest_startf("-M %s%s%s -device pc-testdev",
-                                test->machine,
-                                test->superio ? " -device " : "",
-                                test->superio ?: "");
+    global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
+                               test->machine,
+                               test->superio ? " -device " : "",
+                               test->superio ?: "");
     isa_outl(test, 0xe0, 0x87654321);
     g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
     g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
@@ -187,10 +187,10 @@ static void test_endianness_split(gconstpointer data)
 {
     const TestCase *test = data;
 
-    global_qtest = qtest_startf("-M %s%s%s -device pc-testdev",
-                                test->machine,
-                                test->superio ? " -device " : "",
-                                test->superio ?: "");
+    global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
+                               test->machine,
+                               test->superio ? " -device " : "",
+                               test->superio ?: "");
     isa_outl(test, 0xe8, 0x87654321);
     g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
     g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
@@ -231,10 +231,10 @@ static void test_endianness_combine(gconstpointer data)
 {
     const TestCase *test = data;
 
-    global_qtest = qtest_startf("-M %s%s%s -device pc-testdev",
-                                test->machine,
-                                test->superio ? " -device " : "",
-                                test->superio ?: "");
+    global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
+                               test->machine,
+                               test->superio ? " -device " : "",
+                               test->superio ?: "");
     isa_outl(test, 0xe0, 0x87654321);
     g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
     g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
diff --git a/tests/ipmi-bt-test.c b/tests/ipmi-bt-test.c
index 8be18e3f42..f4a81b5265 100644
--- a/tests/ipmi-bt-test.c
+++ b/tests/ipmi-bt-test.c
@@ -414,7 +414,7 @@ int main(int argc, char **argv)
     /* Run the tests */
     g_test_init(&argc, &argv, NULL);
 
-    global_qtest = qtest_startf(
+    global_qtest = qtest_initf(
         " -chardev socket,id=ipmi0,host=localhost,port=%d,reconnect=10"
         " -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
         " -device isa-ipmi-bt,bmc=bmc0", emu_port);
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 2f81bc6382..a0d44793fa 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -259,24 +259,23 @@ QTestState *qtest_init(const char *extra_args)
     return s;
 }
 
-QTestState *qtest_vstartf(const char *fmt, va_list ap)
+QTestState *qtest_vinitf(const char *fmt, va_list ap)
 {
     char *args = g_strdup_vprintf(fmt, ap);
     QTestState *s;
 
-    s = qtest_start(args);
+    s = qtest_init(args);
     g_free(args);
-    global_qtest = NULL;
     return s;
 }
 
-QTestState *qtest_startf(const char *fmt, ...)
+QTestState *qtest_initf(const char *fmt, ...)
 {
     va_list ap;
     QTestState *s;
 
     va_start(ap, fmt);
-    s = qtest_vstartf(fmt, ap);
+    s = qtest_vinitf(fmt, ap);
     va_end(ap);
     return s;
 }
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 58dea82c76..3848086928 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -22,33 +22,32 @@ typedef struct QTestState QTestState;
 extern QTestState *global_qtest;
 
 /**
- * qtest_startf:
+ * qtest_initf:
  * @fmt...: Format for creating other arguments to pass to QEMU, formatted
  * like sprintf().
  *
- * Start QEMU and return the resulting #QTestState (but unlike qtest_start(),
- * #global_qtest is left at NULL).
+ * Convenience wrapper around qtest_start().
  *
  * Returns: #QTestState instance.
  */
-QTestState *qtest_startf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+QTestState *qtest_initf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
 /**
- * qtest_vstartf:
+ * qtest_vinitf:
  * @fmt: Format for creating other arguments to pass to QEMU, formatted
  * like vsprintf().
  * @ap: Format arguments.
  *
- * Start QEMU and return the resulting #QTestState (but unlike qtest_start(),
- * #global_qtest is left at NULL).
+ * Convenience wrapper around qtest_start().
  *
  * Returns: #QTestState instance.
  */
-QTestState *qtest_vstartf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+QTestState *qtest_vinitf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
 
 /**
  * qtest_init:
- * @extra_args: other arguments to pass to QEMU.
+ * @extra_args: other arguments to pass to QEMU.  CAUTION: these
+ * arguments are subject to word splitting and shell evaluation.
  *
  * Returns: #QTestState instance.
  */
diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c
index c276e738e9..055f7246a8 100644
--- a/tests/m25p80-test.c
+++ b/tests/m25p80-test.c
@@ -363,9 +363,9 @@ int main(int argc, char **argv)
     g_assert(ret == 0);
     close(fd);
 
-    global_qtest = qtest_startf("-m 256 -machine palmetto-bmc "
-                                "-drive file=%s,format=raw,if=mtd",
-                                tmp_path);
+    global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
+                               "-drive file=%s,format=raw,if=mtd",
+                               tmp_path);
 
     qtest_add_func("/m25p80/read_jedec", test_read_jedec);
     qtest_add_func("/m25p80/erase_sector", test_erase_sector);
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
index 5b695971c7..4abf9c605c 100644
--- a/tests/m48t59-test.c
+++ b/tests/m48t59-test.c
@@ -146,7 +146,7 @@ static void cmos_get_date_time(QTestState *s, struct tm *date)
 
 static QTestState *m48t59_qtest_start(void)
 {
-    return qtest_startf("-M %s -rtc clock=vm", base_machine);
+    return qtest_initf("-M %s -rtc clock=vm", base_machine);
 }
 
 static void bcd_check_time(void)
diff --git a/tests/machine-none-test.c b/tests/machine-none-test.c
index f286557b3e..7e72466354 100644
--- a/tests/machine-none-test.c
+++ b/tests/machine-none-test.c
@@ -84,7 +84,7 @@ static void test_machine_cpu_cli(void)
         }
         return; /* TODO: die here to force all targets have a test */
     }
-    global_qtest = qtest_startf("-machine none -cpu '%s'", cpu_model);
+    global_qtest = qtest_initf("-machine none -cpu '%s'", cpu_model);
 
     response = qmp("{ 'execute': 'quit' }");
     g_assert(qdict_haskey(response, "return"));
diff --git a/tests/numa-test.c b/tests/numa-test.c
index 893f826acb..9824fdd587 100644
--- a/tests/numa-test.c
+++ b/tests/numa-test.c
@@ -267,8 +267,8 @@ static void pc_dynamic_cpu_cfg(const void *data)
     QList *cpus;
     QTestState *qs;
 
-    qs = qtest_startf("%s %s", data ? (char *)data : "",
-                              "-nodefaults --preconfig -smp 2");
+    qs = qtest_initf("%s -nodefaults --preconfig -smp 2",
+                     data ? (char *)data : "");
 
     /* create 2 numa nodes */
     g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
index efb7c838b5..70f4c84d1b 100644
--- a/tests/pnv-xscom-test.c
+++ b/tests/pnv-xscom-test.c
@@ -79,8 +79,8 @@ static void test_cfam_id(const void *data)
 {
     const PnvChip *chip = data;
 
-    global_qtest = qtest_startf("-M powernv,accel=tcg -cpu %s",
-                                chip->cpu_model);
+    global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s",
+                               chip->cpu_model);
     test_xscom_cfam_id(chip);
     qtest_quit(global_qtest);
 }
@@ -114,8 +114,8 @@ static void test_core(const void *data)
 {
     const PnvChip *chip = data;
 
-    global_qtest = qtest_startf("-M powernv,accel=tcg -cpu %s",
-                                chip->cpu_model);
+    global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s",
+                               chip->cpu_model);
     test_xscom_core(chip);
     qtest_quit(global_qtest);
 }
diff --git a/tests/prom-env-test.c b/tests/prom-env-test.c
index 8c867e631a..198d007f1b 100644
--- a/tests/prom-env-test.c
+++ b/tests/prom-env-test.c
@@ -49,11 +49,11 @@ static void test_machine(const void *machine)
     /* The pseries firmware boots much faster without the default devices */
     extra_args = strcmp(machine, "pseries") == 0 ? "-nodefaults" : "";
 
-    global_qtest = qtest_startf("-M %s,accel=tcg %s "
-                                "-prom-env 'use-nvramrc?=true' "
-                                "-prom-env 'nvramrc=%x %x l!' ",
-                                (const char *)machine, extra_args,
-                                MAGIC, ADDRESS);
+    global_qtest = qtest_initf("-M %s,accel=tcg %s "
+                               "-prom-env 'use-nvramrc?=true' "
+                               "-prom-env 'nvramrc=%x %x l!' ",
+                               (const char *)machine, extra_args,
+                               MAGIC, ADDRESS);
     check_guest_memory();
     qtest_quit(global_qtest);
 }
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 5eb15daebc..487ef946ed 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -436,7 +436,7 @@ static void add_query_tests(QmpSchema *schema)
 static void test_qmp_preconfig(void)
 {
     QDict *rsp, *ret;
-    QTestState *qs = qtest_startf("%s --preconfig", common_args);
+    QTestState *qs = qtest_initf("%s --preconfig", common_args);
 
     /* preconfig state */
     /* enabled commands, no error expected  */
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
index 1d825eb010..982f5ebbb2 100644
--- a/tests/sdhci-test.c
+++ b/tests/sdhci-test.c
@@ -184,8 +184,8 @@ static QSDHCI *machine_start(const struct sdhci_t *test)
         uint16_t vendor_id, device_id;
         uint64_t barsize;
 
-        global_qtest = qtest_startf("-machine %s -device sdhci-pci",
-                                    test->machine);
+        global_qtest = qtest_initf("-machine %s -device sdhci-pci",
+                                   test->machine);
 
         s->pci.bus = qpci_init_pc(global_qtest, NULL);
 
@@ -200,7 +200,7 @@ static QSDHCI *machine_start(const struct sdhci_t *test)
         qpci_device_enable(s->pci.dev);
     } else {
         /* SysBus */
-        global_qtest = qtest_startf("-machine %s", test->machine);
+        global_qtest = qtest_initf("-machine %s", test->machine);
         s->addr = test->sdhci.addr;
     }
 
diff --git a/tests/tco-test.c b/tests/tco-test.c
index 9945fb8469..6bee9a37d3 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -58,9 +58,9 @@ static void test_init(TestData *d)
 {
     QTestState *qs;
 
-    qs = qtest_startf("-machine q35 %s %s",
-                      d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
-                      !d->args ? "" : d->args);
+    qs = qtest_initf("-machine q35 %s %s",
+                     d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
+                     !d->args ? "" : d->args);
     global_qtest = qs;
     qtest_irq_intercept_in(qs, "ioapic");
 
diff --git a/tests/test-filter-mirror.c b/tests/test-filter-mirror.c
index 1ab4759b80..1d66b5dbb0 100644
--- a/tests/test-filter-mirror.c
+++ b/tests/test-filter-mirror.c
@@ -37,7 +37,7 @@ static void test_mirror(void)
     ret = mkstemp(sock_path);
     g_assert_cmpint(ret, !=, -1);
 
-    global_qtest = qtest_startf(
+    global_qtest = qtest_initf(
         "-netdev socket,id=qtest-bn0,fd=%d "
         "-device %s,netdev=qtest-bn0,id=qtest-e0 "
         "-chardev socket,id=mirror0,path=%s,server,nowait "
diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c
index 5b6c594867..934ddee427 100644
--- a/tests/test-filter-redirector.c
+++ b/tests/test-filter-redirector.c
@@ -87,7 +87,7 @@ static void test_redirector_tx(void)
     ret = mkstemp(sock_path1);
     g_assert_cmpint(ret, !=, -1);
 
-    global_qtest = qtest_startf(
+    global_qtest = qtest_initf(
         "-netdev socket,id=qtest-bn0,fd=%d "
         "-device %s,netdev=qtest-bn0,id=qtest-e0 "
         "-chardev socket,id=redirector0,path=%s,server,nowait "
@@ -156,7 +156,7 @@ static void test_redirector_rx(void)
     ret = mkstemp(sock_path1);
     g_assert_cmpint(ret, !=, -1);
 
-    global_qtest = qtest_startf(
+    global_qtest = qtest_initf(
         "-netdev socket,id=qtest-bn0,fd=%d "
         "-device %s,netdev=qtest-bn0,id=qtest-e0 "
         "-chardev socket,id=redirector0,path=%s,server,nowait "
diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c
index 0a07e036bb..5a1d0ccbb7 100644
--- a/tests/virtio-balloon-test.c
+++ b/tests/virtio-balloon-test.c
@@ -23,8 +23,8 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
     qtest_add_func("/virtio/balloon/nop", balloon_nop);
 
-    global_qtest = qtest_startf("-device virtio-balloon-%s",
-                                qvirtio_get_dev_type());
+    global_qtest = qtest_initf("-device virtio-balloon-%s",
+                               qvirtio_get_dev_type());
     ret = g_test_run();
 
     qtest_end();
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 5955bf6d57..d9893516bb 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -90,10 +90,10 @@ static void arm_test_start(void)
 
     tmp_path = drive_create();
 
-    global_qtest = qtest_startf("-machine virt "
-                                "-drive if=none,id=drive0,file=%s,format=raw "
-                                "-device virtio-blk-device,drive=drive0",
-                                tmp_path);
+    global_qtest = qtest_initf("-machine virt "
+                               "-drive if=none,id=drive0,file=%s,format=raw "
+                               "-device virtio-blk-device,drive=drive0",
+                               tmp_path);
     unlink(tmp_path);
     g_free(tmp_path);
 }
diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c
index 945bae5a15..a7c6f167c3 100644
--- a/tests/virtio-console-test.c
+++ b/tests/virtio-console-test.c
@@ -14,17 +14,17 @@
 /* Tests only initialization so far. TODO: Replace with functional tests */
 static void console_nop(void)
 {
-    global_qtest = qtest_startf("-device virtio-serial-%s,id=vser0 "
-                                "-device virtconsole,bus=vser0.0",
-                                qvirtio_get_dev_type());
+    global_qtest = qtest_initf("-device virtio-serial-%s,id=vser0 "
+                               "-device virtconsole,bus=vser0.0",
+                               qvirtio_get_dev_type());
     qtest_end();
 }
 
 static void serialport_nop(void)
 {
-    global_qtest = qtest_startf("-device virtio-serial-%s,id=vser0 "
-                                "-device virtserialport,bus=vser0.0",
-                                qvirtio_get_dev_type());
+    global_qtest = qtest_initf("-device virtio-serial-%s,id=vser0 "
+                               "-device virtserialport,bus=vser0.0",
+                               qvirtio_get_dev_type());
     qtest_end();
 }
 
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
index e4b18b1c8a..8da9980a24 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -31,8 +31,8 @@ int main(int argc, char **argv)
     qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
     qtest_add_func("/virtio/serial/hotplug", hotplug);
 
-    global_qtest = qtest_startf("-device virtio-serial-%s",
-                                qvirtio_get_dev_type());
+    global_qtest = qtest_initf("-device virtio-serial-%s",
+                               qvirtio_get_dev_type());
     ret = g_test_run();
 
     qtest_end();
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
index 8d915c610c..0a6fb55f2e 100644
--- a/tests/vmgenid-test.c
+++ b/tests/vmgenid-test.c
@@ -142,7 +142,7 @@ static void vmgenid_set_guid_test(void)
 
     g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
 
-    global_qtest = qtest_startf(GUID_CMD(VGID_GUID));
+    global_qtest = qtest_initf(GUID_CMD(VGID_GUID));
 
     /* Read the GUID from accessing guest memory */
     read_guid_from_memory(&measured);
@@ -155,7 +155,7 @@ static void vmgenid_set_guid_auto_test(void)
 {
     QemuUUID measured;
 
-    global_qtest = qtest_startf(GUID_CMD("auto"));
+    global_qtest = qtest_initf(GUID_CMD("auto"));
 
     read_guid_from_memory(&measured);
 
@@ -171,7 +171,7 @@ static void vmgenid_query_monitor_test(void)
 
     g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
 
-    global_qtest = qtest_startf(GUID_CMD(VGID_GUID));
+    global_qtest = qtest_initf(GUID_CMD(VGID_GUID));
 
     /* Read the GUID via the monitor */
     read_guid_from_monitor(&measured);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency
  2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
                   ` (21 preceding siblings ...)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf() Markus Armbruster
@ 2018-07-27 15:13 ` Markus Armbruster
  2018-07-27 17:10   ` Eric Blake
  2018-07-27 17:19   ` Thomas Huth
  22 siblings, 2 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-27 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: thuth, f4bug, eblake

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/libqtest.c | 12 ++++++------
 tests/libqtest.h |  4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index a0d44793fa..3706f30aa2 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -538,7 +538,7 @@ QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
     return qmp_fd_receive(fd);
 }
 
-QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
+QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
 {
     qtest_qmp_vsend(s, fmt, ap);
 
@@ -572,7 +572,7 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
     QDict *response;
 
     va_start(ap, fmt);
-    response = qtest_qmpv(s, fmt, ap);
+    response = qtest_vqmp(s, fmt, ap);
     va_end(ap);
     return response;
 }
@@ -608,7 +608,7 @@ void qtest_qmp_eventwait(QTestState *s, const char *event)
     qobject_unref(response);
 }
 
-char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap)
+char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
 {
     char *cmd;
     QDict *resp;
@@ -637,7 +637,7 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...)
     char *ret;
 
     va_start(ap, fmt);
-    ret = qtest_hmpv(s, fmt, ap);
+    ret = qtest_vhmp(s, fmt, ap);
     va_end(ap);
     return ret;
 }
@@ -943,7 +943,7 @@ QDict *qmp(const char *fmt, ...)
     QDict *response;
 
     va_start(ap, fmt);
-    response = qtest_qmpv(global_qtest, fmt, ap);
+    response = qtest_vqmp(global_qtest, fmt, ap);
     va_end(ap);
     return response;
 }
@@ -963,7 +963,7 @@ char *hmp(const char *fmt, ...)
     char *ret;
 
     va_start(ap, fmt);
-    ret = qtest_hmpv(global_qtest, fmt, ap);
+    ret = qtest_vhmp(global_qtest, fmt, ap);
     va_end(ap);
     return ret;
 }
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 3848086928..7e60abc9fd 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -106,7 +106,7 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...)
  *
  * Sends a QMP message to QEMU and returns the response.
  */
-QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
+QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
     GCC_FMT_ATTR(2, 0);
 
 /**
@@ -189,7 +189,7 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
  *
  * Returns: the command's output.  The caller should g_free() it.
  */
-char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap)
+char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
     GCC_FMT_ATTR(2, 0);
 
 /**
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages Markus Armbruster
@ 2018-07-27 15:24   ` Eric Blake
  2018-07-30  5:41     ` Markus Armbruster
  2018-07-27 16:35   ` Thomas Huth
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:24 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> The functions to receive messages are called qtest_qmp_receive() and
> qmp_receive(), qmp_fd_receive().  The ones to send messages are called
> qtest_async_qmp(), qtest_async_qmpv(), qmp_async(), qmp_fd_send(),
> qmp_fd_sendv().  Inconsistent.  Rename the *_async* ones to
> qmp_send(), qtest_qmp_send(), qtest_qmp_vsend().  Rename
> qmp_fd_sendv() to qmp_fd_vsend().
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

> @@ -1592,8 +1592,8 @@ static void test_atapi_tray(void)
>       atapi_wait_tray(false);
>   
>       /* Remove media */
> -    qmp_async("{'execute': 'blockdev-open-tray', "
> -               "'arguments': {'id': 'cd0'}}");
> +    qmp_send("{'execute': 'blockdev-open-tray',"
> +             " 'arguments': {'id': 'cd0'}}");

Could perhaps fit in one line now, but I won't insist.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages Markus Armbruster
@ 2018-07-27 15:24   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:24 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qtest_qmp_device_del() still uses the qmp("") hack to receive a
> message, even though we have qmp_receive() since commit 66e0c7b187e.
> Put it to use.
> 
> Bonus: gets rid of empty format strings.  A step towards compile-time
> format string checking without triggering -Wformat-zero-length.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>   tests/libqtest.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting Markus Armbruster
@ 2018-07-27 15:25   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:25 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qtest_init() still uses the qtest_qmp_discard_response(s, "") hack to
> receive the greeting, even though we have qtest_qmp_receive() since
> commit 66e0c7b187e.  Put it to use.
> 
> Bonus: gets rid of an empty format string.  A step towards
> compile-time format string checking without triggering
> -Wformat-zero-length.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>   tests/libqtest.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail() Markus Armbruster
@ 2018-07-27 15:28   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:28 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Commit ab45015a968 "qobject: Let qobject_from_jsonf() fail instead of
> abort" fails to accomplish its stated aim: the function can still
> abort due to its use of &error_abort.
> 
> Its rationale for letting it fail is that all remaining users cope
> fine with failure.  Well, they're just fine with aborting, too; it's
> what they do on failure.
> 
> Simply reverting the broken commit would bring back the unfortunate
> asymmetry between qobject_from_jsonf() and qobject_from_jsonv(): one
> aborts, the other returns null.  So also rename it to
> qobject_from_jsonf_nofail().
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail() Markus Armbruster
@ 2018-07-27 15:30   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:30 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Every printf()-like function sooner or later needs its vprintf()-like
> buddy.  The next commit will need qobject_from_jsonf_nofail()'s buddy,
> and qdict_from_jsonf_nofail()'s buddy will be used later in this
> series.  Add both.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit Markus Armbruster
@ 2018-07-27 15:31   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:31 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   tests/libqtest.c | 18 +++++++-----------
>   1 file changed, 7 insertions(+), 11 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity Markus Armbruster
@ 2018-07-27 15:33   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:33 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> When visitor_input_test_init_internal()'s argument @ap is null, then
> @json_string is interpreted literally, else it's gets %-escapes
> interpolated.  This is awkward.
> 
> One caller always passes null @ap, and the others never do.  Lift the
> building of the QObject into the callers, where it can be done without
> such ambiguity.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>   tests/test-qobject-input-visitor.c | 19 ++++++++++---------
>   1 file changed, 10 insertions(+), 9 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away Markus Armbruster
@ 2018-07-27 15:34   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:34 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qobject_from_jsonv() takes ownership of %p arguments.  On failure, we
> can't generally know whether we failed before or after %p, so
> ownership becomes indeterminate.  To avoid leaks, callers passing %p
> must terminate on error, e.g. by passing &error_abort.  Trap for the
> unwary; document and give the function internal linkage.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   include/qapi/qmp/qjson.h |  2 --
>   qobject/qjson.c          | 13 ++++++++++++-
>   2 files changed, 12 insertions(+), 3 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO() Markus Armbruster
@ 2018-07-27 15:35   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:35 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> The qmp_FOO() take a printf-like format string.  In a few places, we
> assign a string literal to a variable and pass that instead of simply
> passing the literal.  Clean that up.
> 
> Bonus: gets rid of non-literal format strings.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   tests/ahci-test.c | 4 +---
>   tests/ide-test.c  | 4 +---
>   2 files changed, 2 insertions(+), 6 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases)
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases) Markus Armbruster
@ 2018-07-27 15:39   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:39 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> When you build QMP input manually like this
> 
>      cmd = g_strdup_printf("{ 'execute': 'migrate',"
>                            "'arguments': { 'uri': '%s' } }",
>                            uri);
>      rsp = qmp(cmd);
>      g_free(cmd);
> 
> you're responsible for escaping the interpolated values for JSON.  Not
> done here, and therefore works only for sufficiently nice @uri.  For
> instance, if @uri contained a single "'", qobject_from_vjsonf_nofail()
> would abort.  A sufficiently nasty @uri could even inject unwanted
> members into the arguments object.
> 
> Leaving interpolation into JSON to qmp() is more robust:
> 
>      rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
> 
> It's also more concise.
> 
> Clean up the simple cases where we interpolate exactly a JSON value.
> 
> Bonus: gets rid of non-literal format strings.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---

>   
> -    cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
> -                          "'arguments': { 'value': %g } }", value);
> -    rsp = qtest_qmp(who, cmd);
> -    g_free(cmd);
> +    rsp = qtest_qmp(who,
> +                    "{ 'execute': 'migrate_set_downtime',"
> +                    " 'arguments': { 'value': %f } }", value);

Looks a bit awkward changing %g to %f, but matches the limited subset 
that our parser accepts and doesn't change the accuracy needed for the 
test to pass.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add Markus Armbruster
@ 2018-07-27 15:42   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:42 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> test_plug_with_device_add_x86() plugs Haswell-i386-cpu and
> Haswell-x86_64-cpu with device_add.  It passes socket-id, core-id,
> thread-id as JSON strings.  The properties are actually integers.
> 
> test_plug_with_device_add_coreid() plugs power8_v2.0-spapr-cpu-core
> and qemu-s390x-cpu with device_add.  It passes core-id as JSON string.
> The properties are actually integers.
> 
> Passing JSON string values to integer properties works only due to
> device_add implementation accidents.  Fix the test to pass JSON
> numbers.  While there, use %u rather than %i with unsigned int.
> 
> Cc: Thomas Huth <thuth@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>   tests/cpu-plug-test.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add() Markus Armbruster
@ 2018-07-27 15:48   ` Eric Blake
  2018-07-30  6:04     ` Markus Armbruster
  2018-07-30  8:34     ` Markus Armbruster
  0 siblings, 2 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:48 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Leaving interpolation into JSON to qmp() is more robust than building
> QMP input manually, as explained in the commit before previous.
> 
> qtest_qmp_device_add() and its wrappers interpolate into JSON as
> follows:
> 
> * qtest_qmp_device_add() interpolates members into a JSON object.
> 
> * So do its wrappers qpci_plug_device_test() and usb_test_hotplug().
> 
> * usb_test_hotplug() additionally interpolates strings and numbers
>    into JSON strings.
> 
> Clean them up:
> 
> * Have qtest_qmp_device_add() take its extra device properties as
>    arguments for for qdict_from_jsonf_nofail() instead of a string

s/for for/for/

>    containing JSON members.
> 
> * Drop qpci_plug_device_test(), use qtest_qmp_device_add()
>    directly.
> 
> * Change usb_test_hotplug() parameter @port to string, to avoid
>    interpolation.  Interpolate @hcd_id separately.
> 
> Bonus: gets rid of a non-literal format string.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Cc: Thomas Huth <thuth@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> +++ b/tests/ivshmem-test.c
> @@ -420,19 +420,17 @@ static void test_ivshmem_server_irq(void)
>   static void test_ivshmem_hotplug(void)
>   {
>       const char *arch = qtest_get_arch();
> -    gchar *opts;
>   
>       qtest_start("");
>   
> -    opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm);
> -
> -    qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts);
> +    qtest_qmp_device_add("ivshmem",
> +                         "iv1", "{'addr': %s, 'shm': '%s', 'size': '1M'}",

Umm, how does this still pass?  You want 'shm':%s, not 'shm':'%s'.

(We really want to assert that any % interpolations in our JSON parser 
are NOT embedded in '').

With that error fixed,
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member Markus Armbruster
@ 2018-07-27 15:50   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 15:50 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> All callers of wait_command() are only interested in the success
> response's "return" member.  Lift its extraction into wait_command().
> 
> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> ---
>   tests/migration-test.c | 38 +++++++++++++++-----------------------
>   1 file changed, 15 insertions(+), 23 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success() Markus Armbruster
@ 2018-07-27 16:00   ` Eric Blake
  2018-07-30  6:10     ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:00 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert, Stefan Berger

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Commit b21373d0713 copied wait_command() from tests/migration-test.c
> to tests/tpm-util.c.  Replace both copies by new libqtest helper
> qtest_qmp_receive_success().  Also use it to simplify
> qtest_qmp_device_del().
> 
> Bonus: gets rid of a non-literal format string.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.

Where? [1]

> 
> Cc: Thomas Huth <thuth@redhat.com>
> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Cc: Stefan Berger <stefanb@linux.vnet.ibm.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> ---

> +++ b/tests/libqtest.c
> @@ -1029,6 +1029,35 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
>       qobject_unref(response);
>   }
>   
> +QDict *qtest_qmp_receive_success(QTestState *s,
> +                                 void (*event_cb)(void *opaque,
> +                                                  const char *event,
> +                                                  QDict *data),
> +                                 void *opaque)
> +{

I like the new signature!

> +++ b/tests/migration-test.c

>   /*
>    * Events can get in the way of responses we are actually waiting for.
>    */
>   static QDict *wait_command(QTestState *who, const char *command)
>   {

[1] This is still taking a format non-literal command...

> -    const char *event_string;
> -    QDict *response, *ret;
> -
> -    response = qtest_qmp(who, command);
...
> +    qtest_qmp_send(who, command);

and is passing it on through.

> +    return qtest_qmp_receive_success(who, stop_cb, NULL);
>   }
>   

> +++ b/tests/tpm-util.c

> -/*
> - * Events can get in the way of responses we are actually waiting for.
> - */
> -static QDict *tpm_util_wait_command(QTestState *who, const char *command)
> -{

Maybe you were counting this instance,

>   void tpm_util_wait_for_migration_complete(QTestState *who)
>   {
>       while (true) {
> -        QDict *rsp, *rsp_return;
> +        QDict *rsp_return;
>           bool completed;
>           const char *status;
>   
> -        rsp = tpm_util_wait_command(who, "{ 'execute': 'query-migrate' }");
> -        rsp_return = qdict_get_qdict(rsp, "return");
> +        qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");

where you did indeed drop a format non-literal?

But on the assumption that there's more cleanups later in the series, 
this is indeed incrementally better, so

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%'
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%' Markus Armbruster
@ 2018-07-27 16:02   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:02 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> wait_command() passes its argument @command to qtest_qmp_send().
> Falls apart if @command contain '%'.  Two ways to disarm this trap:
> suppress interpretation of '%' by passing @command as argument to
> format string "%s", or fix it by having wait_command() take the
> variable arguments to go with @command.  Do the latter.
> 
> This is another step towards compile-time format string checking
> without triggering -Wformat-nonliteral.
> 

Aha - fixes up the complaints I had on 15/23.

> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> ---
>   tests/migration-test.c | 9 +++++++--
>   1 file changed, 7 insertions(+), 2 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1 Markus Armbruster
@ 2018-07-27 16:04   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:04 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Leaving interpolation into JSON to qmp() is more robust than building
> QMP input manually, as explained in the recent commit "tests: Clean up
> string interpolation into QMP input (simple cases)".
> 
> migrate_recover() builds QMP input manually because wait_command()
> can't interpolate.  Well, it can since the previous commit.  Simplify
> accordingly.
> 
> Bonus: gets rid of a non-literal format string.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> ---
>   tests/migration-test.c | 12 ++++++------
>   1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/migration-test.c b/tests/migration-test.c
> index 0c92f2b1cd..323bb60535 100644
> --- a/tests/migration-test.c
> +++ b/tests/migration-test.c
> @@ -156,6 +156,7 @@ static void stop_cb(void *opaque, const char *name, QDict *data)
>   /*
>    * Events can get in the way of responses we are actually waiting for.
>    */
> +GCC_FMT_ATTR(2, 3)
>   static QDict *wait_command(QTestState *who, const char *command, ...)

Placement of function-level attributes is so weird (before the return 
type on implementations, but after the () in declarations) - not your fault.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2 Markus Armbruster
@ 2018-07-27 16:05   ` Eric Blake
  2018-07-30  6:19     ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:05 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Leaving interpolation into JSON to qmp() is more robust than building
> QMP input manually, as explained in the recent commit "tests: Clean up
> string interpolation into QMP input (simple cases)".
> 
> migrate() interpolates members into a JSON object.  Change it to take
> its extra QMP arguments as arguments for qdict_from_jsonf_nofail()
> instead of a string containing JSON members.
> 
> Bonus: gets rid of a non-literal format string.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> ---
>   tests/migration-test.c | 28 ++++++++++++++++------------
>   1 file changed, 16 insertions(+), 12 deletions(-)
> 

> +++ b/tests/migration-test.c
> @@ -14,6 +14,7 @@
>   
>   #include "libqtest.h"
>   #include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qjson.h"
>   #include "qemu/option.h"
>   #include "qemu/range.h"
>   #include "qemu/sockets.h"
> @@ -381,16 +382,19 @@ static void migrate_set_capability(QTestState *who, const char *capability,
>       qobject_unref(rsp);
>   }
>   
> -static void migrate(QTestState *who, const char *uri, const char *extra)
> +static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
>   {

No gcc attribute?

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3 Markus Armbruster
@ 2018-07-27 16:11   ` Eric Blake
  2018-07-30  6:25     ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:11 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: thuth, f4bug, Juan Quintela, Dr . David Alan Gilbert

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Leaving interpolation into JSON to qmp() is more robust than building
> QMP input manually, as explained in the recent commit "tests: Clean up
> string interpolation into QMP input (simple cases)".
> 
> migration-test.c interpolates strings into JSON in a few places:
> 
> * migrate_set_parameter() interpolates string parameter @value as a
>    JSON number.  Change it to long long.  This requires changing
>    migrate_check_parameter() similarly.
> 
> * migrate_set_capability() interpolates string parameter @value as a
>    JSON boolean.  Change it to bool.
> 
> * deprecated_set_speed() interpolates string parameter @value as a
>    JSON number.  Change it to long long.
> 
> Bonus: gets rid of non-literal format strings.  A step towards
> compile-time format string checking without triggering
> -Wformat-nonliteral.
> 
> Cc: Juan Quintela <quintela@redhat.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> ---
>   tests/migration-test.c | 74 +++++++++++++++++-------------------------
>   1 file changed, 29 insertions(+), 45 deletions(-)
> 
> diff --git a/tests/migration-test.c b/tests/migration-test.c
> index 1c1e56b15b..132c30891d 100644
> --- a/tests/migration-test.c
> +++ b/tests/migration-test.c
> @@ -315,31 +315,25 @@ static void cleanup(const char *filename)
>   }
>   
>   static void migrate_check_parameter(QTestState *who, const char *parameter,
> -                                    const char *value)
> +                                    long long value)
>   {
>       QDict *rsp_return;
> -    char *result;
>   
>       rsp_return = wait_command(who,
>                                 "{ 'execute': 'query-migrate-parameters' }");
> -    result = g_strdup_printf("%" PRId64,
> -                             qdict_get_try_int(rsp_return,  parameter, -1));
> -    g_assert_cmpstr(result, ==, value);

The old code allows defaulting to -1 if the value is not present;

> -    g_free(result);
> +    g_assert_cmpint(qdict_get_int(rsp_return,  parameter), ==, value);

the new code requires the value to be found.  Matters if any of the 
callers passed "-1" in the old code, but a search of the file doesn't 
spot any such callers. So I think you're okay.

Also, while touching this line, it would be nice to get rid of the 
double space before parameter.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking Markus Armbruster
@ 2018-07-27 16:18   ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 16:18 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qtest_qmp() & friends pass their format string and variable arguments
> to qobject_from_vjsonf_nofail().  Unlike qobject_from_jsonv(), they
> aren't decorated with GCC_FMT_ATTR().  Fix that to get compile-time
> format string checking.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   tests/libqtest.h | 32 +++++++++++++++++++-------------
>   1 file changed, 19 insertions(+), 13 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages Markus Armbruster
  2018-07-27 15:24   ` Eric Blake
@ 2018-07-27 16:35   ` Thomas Huth
  2018-07-27 17:06     ` Eric Blake
  1 sibling, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-07-27 16:35 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: f4bug, eblake

On 07/27/2018 05:13 PM, Markus Armbruster wrote:
> [...] Rename qmp_fd_sendv() to qmp_fd_vsend().

Why? I think it's also quite common to have the "v" at the end, e.g.
object_new_with_propv, gdb_do_syscallv, qobject_from_jsonv, etc.

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends Markus Armbruster
@ 2018-07-27 16:46   ` Thomas Huth
  2018-07-27 17:03     ` Eric Blake
  2018-07-27 17:05   ` Eric Blake
  1 sibling, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-07-27 16:46 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: f4bug, eblake

On 07/27/2018 05:13 PM, Markus Armbruster wrote:
> qtest_qmp_discard_response(...) is shorthand for
> qobject_unref(qtest_qmp(...), except it's not actually shorter.

But the latter is IMHO harder to read.
And it might be shorter in the compiled binary (one function call vs. two).

> Moreover, the presence of these functions encourage sloppy testing.

Shouldn't we then rather fix the tests to check for valid responses
instead of replacing this function with harder-to-read code?

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 16:46   ` Thomas Huth
@ 2018-07-27 17:03     ` Eric Blake
  2018-07-30  6:32       ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 17:03 UTC (permalink / raw)
  To: thuth, Markus Armbruster, qemu-devel; +Cc: f4bug

On 07/27/2018 11:46 AM, Thomas Huth wrote:
> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>> qtest_qmp_discard_response(...) is shorthand for
>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
> 
> But the latter is IMHO harder to read.

Maybe, but then it lends itself well to:

QObject *rsp = qtest_qmp(...);
qobject_unref(rsp);

which is where you do insert tests for valid responses.

> And it might be shorter in the compiled binary (one function call vs. two).

The size of the test binaries is not our biggest concern.

> 
>> Moreover, the presence of these functions encourage sloppy testing.
> 
> Shouldn't we then rather fix the tests to check for valid responses
> instead of replacing this function with harder-to-read code?

I think such fixes are now easier to make, but can be separate followup 
patches. The mechanical conversion is fine to me.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends Markus Armbruster
  2018-07-27 16:46   ` Thomas Huth
@ 2018-07-27 17:05   ` Eric Blake
  2018-07-30  6:28     ` Markus Armbruster
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 17:05 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qtest_qmp_discard_response(...) is shorthand for
> qobject_unref(qtest_qmp(...), except it's not actually shorter.
> Moreover, the presence of these functions encourage sloppy testing.
> Remove them.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>


> +++ b/tests/ahci-test.c
> @@ -1607,14 +1607,14 @@ static void test_atapi_tray(void)
>       atapi_wait_tray(true);
>   
>       /* Re-insert media */
> -    qmp_discard_response("{'execute': 'blockdev-add', "
> +    qobject_unref(qmp("{'execute': 'blockdev-add', "
>                             "'arguments': {'node-name': 'node0', "
>                                           "'driver': 'raw', "
>                                           "'file': { 'driver': 'file', "
> -                                                  "'filename': %s }}}", iso);
> -    qmp_discard_response("{'execute': 'blockdev-insert-medium',"
> +                      "'filename': %s }}}", iso));

Why did you fix indentation for some, but not all, of the lines here?

> +    qobject_unref(qmp("{'execute': 'blockdev-insert-medium',"
>                             "'arguments': { 'id': 'cd0', "
> -                                         "'node-name': 'node0' }}");
> +                      "'node-name': 'node0' }}"));

Again, indentation looks odd.

> +++ b/tests/fdc-test.c
> @@ -26,6 +26,7 @@
>   
>   
>   #include "libqtest.h"
> +#include "qapi/qmp/qdict.h"
>   #include "qemu-common.h"
>   
>   #define TEST_IMAGE_SIZE 1440 * 1024
> @@ -298,9 +299,9 @@ static void test_media_insert(void)
>   
>       /* Insert media in drive. DSKCHK should not be reset until a step pulse
>        * is sent. */
> -    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
> +    qobject_unref(qmp("{'execute':'blockdev-change-medium', 'arguments':{"
>                            " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
> -                         test_image);
> +                      test_image));

Another place where indentation looks odd.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages
  2018-07-27 16:35   ` Thomas Huth
@ 2018-07-27 17:06     ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 17:06 UTC (permalink / raw)
  To: thuth, Markus Armbruster, qemu-devel; +Cc: f4bug

On 07/27/2018 11:35 AM, Thomas Huth wrote:
> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>> [...] Rename qmp_fd_sendv() to qmp_fd_vsend().
> 
> Why? I think it's also quite common to have the "v" at the end, e.g.
> object_new_with_propv, gdb_do_syscallv, qobject_from_jsonv, etc.

Actually, I think 'printf' vs. 'vprintf' is the model to be following, 
and patch 23/23 brings in even more consistency.  I'm in favor of this 
rename.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf() Markus Armbruster
@ 2018-07-27 17:08   ` Eric Blake
  2018-07-30  6:32     ` Markus Armbruster
  2018-07-27 17:18   ` Thomas Huth
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-27 17:08 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> qtest_init() creates a new QTestState, and leaves @global_qtest alone.
> qtest_start() additionally assigns it to @global_qtest, but
> qtest_startf() additionall sets assigns NULL to @global_qtest.  This

s/additionall sets/additionally/

> makes no sense.  Replace it by qtest_initf() that works like
> qtest_init(), i.e. leaves @global_qtest alone.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency Markus Armbruster
@ 2018-07-27 17:10   ` Eric Blake
  2018-07-27 17:19   ` Thomas Huth
  1 sibling, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 17:10 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: thuth, f4bug

On 07/27/2018 10:13 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>

Might be worth adding mention of WHAT it is consistent with (as Thomas 
pointed out on 2/23, we still have inconsistencies with 
object_new_with_propv and such)

> ---
>   tests/libqtest.c | 12 ++++++------
>   tests/libqtest.h |  4 ++--
>   2 files changed, 8 insertions(+), 8 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf()
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf() Markus Armbruster
  2018-07-27 17:08   ` Eric Blake
@ 2018-07-27 17:18   ` Thomas Huth
  2018-07-27 18:52     ` Eric Blake
  1 sibling, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-07-27 17:18 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: f4bug, eblake

On 07/27/2018 05:13 PM, Markus Armbruster wrote:
> qtest_init() creates a new QTestState, and leaves @global_qtest alone.
> qtest_start() additionally assigns it to @global_qtest, but
> qtest_startf() additionall sets assigns NULL to @global_qtest.  This
> makes no sense.  Replace it by qtest_initf() that works like
> qtest_init(), i.e. leaves @global_qtest alone.

FWIW, the original idea was to get rid of global_qtest, and then to
remove qtest_init instead:

https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg02723.html

Not sure whether Eric is still working on these patches, though.

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency
  2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency Markus Armbruster
  2018-07-27 17:10   ` Eric Blake
@ 2018-07-27 17:19   ` Thomas Huth
  2018-07-30  6:47     ` Markus Armbruster
  1 sibling, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-07-27 17:19 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: f4bug, eblake

On 07/27/2018 05:13 PM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  tests/libqtest.c | 12 ++++++------
>  tests/libqtest.h |  4 ++--
>  2 files changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index a0d44793fa..3706f30aa2 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -538,7 +538,7 @@ QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
>      return qmp_fd_receive(fd);
>  }
>  
> -QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
> +QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)

Unless you also add something to our coding conventions which mandates
the naming to be always this way, I think this is just unnecessary code
churn.

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf()
  2018-07-27 17:18   ` Thomas Huth
@ 2018-07-27 18:52     ` Eric Blake
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Blake @ 2018-07-27 18:52 UTC (permalink / raw)
  To: thuth, Markus Armbruster, qemu-devel; +Cc: f4bug

On 07/27/2018 12:18 PM, Thomas Huth wrote:
> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>> qtest_init() creates a new QTestState, and leaves @global_qtest alone.
>> qtest_start() additionally assigns it to @global_qtest, but
>> qtest_startf() additionall sets assigns NULL to @global_qtest.  This
>> makes no sense.  Replace it by qtest_initf() that works like
>> qtest_init(), i.e. leaves @global_qtest alone.
> 
> FWIW, the original idea was to get rid of global_qtest, and then to
> remove qtest_init instead:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg02723.html
> 
> Not sure whether Eric is still working on these patches, though.

As pointed out in the cover letter, there are still some good things to 
salvage from my series, but at this point, it's been closer to a year 
since I last posted anything, so it is just as easy for me to 
rebase/rework from scratch for salvaging the good things, after this 
series lands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages
  2018-07-27 15:24   ` Eric Blake
@ 2018-07-30  5:41     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  5:41 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, thuth, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> The functions to receive messages are called qtest_qmp_receive() and
>> qmp_receive(), qmp_fd_receive().  The ones to send messages are called
>> qtest_async_qmp(), qtest_async_qmpv(), qmp_async(), qmp_fd_send(),
>> qmp_fd_sendv().  Inconsistent.  Rename the *_async* ones to
>> qmp_send(), qtest_qmp_send(), qtest_qmp_vsend().  Rename
>> qmp_fd_sendv() to qmp_fd_vsend().
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>> @@ -1592,8 +1592,8 @@ static void test_atapi_tray(void)
>>       atapi_wait_tray(false);
>>         /* Remove media */
>> -    qmp_async("{'execute': 'blockdev-open-tray', "
>> -               "'arguments': {'id': 'cd0'}}");
>> +    qmp_send("{'execute': 'blockdev-open-tray',"
>> +             " 'arguments': {'id': 'cd0'}}");
>
> Could perhaps fit in one line now, but I won't insist.

I tried, it doesn't fit.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-27 15:48   ` Eric Blake
@ 2018-07-30  6:04     ` Markus Armbruster
  2018-07-30  8:34     ` Markus Armbruster
  1 sibling, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:04 UTC (permalink / raw)
  To: Eric Blake; +Cc: Markus Armbruster, qemu-devel, thuth, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> Leaving interpolation into JSON to qmp() is more robust than building
>> QMP input manually, as explained in the commit before previous.
>>
>> qtest_qmp_device_add() and its wrappers interpolate into JSON as
>> follows:
>>
>> * qtest_qmp_device_add() interpolates members into a JSON object.
>>
>> * So do its wrappers qpci_plug_device_test() and usb_test_hotplug().
>>
>> * usb_test_hotplug() additionally interpolates strings and numbers
>>    into JSON strings.
>>
>> Clean them up:
>>
>> * Have qtest_qmp_device_add() take its extra device properties as
>>    arguments for for qdict_from_jsonf_nofail() instead of a string
>
> s/for for/for/

Fixing...

>>    containing JSON members.
>>
>> * Drop qpci_plug_device_test(), use qtest_qmp_device_add()
>>    directly.
>>
>> * Change usb_test_hotplug() parameter @port to string, to avoid
>>    interpolation.  Interpolate @hcd_id separately.
>>
>> Bonus: gets rid of a non-literal format string.  A step towards
>> compile-time format string checking without triggering
>> -Wformat-nonliteral.
>>
>> Cc: Thomas Huth <thuth@redhat.com>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>> +++ b/tests/ivshmem-test.c
>> @@ -420,19 +420,17 @@ static void test_ivshmem_server_irq(void)
>>   static void test_ivshmem_hotplug(void)
>>   {
>>       const char *arch = qtest_get_arch();
>> -    gchar *opts;
>>         qtest_start("");
>>   -    opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm);
>> -
>> -    qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts);
>> +    qtest_qmp_device_add("ivshmem",
>> +                         "iv1", "{'addr': %s, 'shm': '%s', 'size': '1M'}",
>
> Umm, how does this still pass?  You want 'shm':%s, not 'shm':'%s'.

Good catch.

It passes, because the value of "shm" is an arbitrary file name under
/dev/shm/.

> (We really want to assert that any % interpolations in our JSON parser
> are NOT embedded in '').
>
> With that error fixed,
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success()
  2018-07-27 16:00   ` Eric Blake
@ 2018-07-30  6:10     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:10 UTC (permalink / raw)
  To: Eric Blake
  Cc: Markus Armbruster, qemu-devel, thuth, Stefan Berger, f4bug,
	Dr . David Alan Gilbert, Juan Quintela

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> Commit b21373d0713 copied wait_command() from tests/migration-test.c
>> to tests/tpm-util.c.  Replace both copies by new libqtest helper
>> qtest_qmp_receive_success().  Also use it to simplify
>> qtest_qmp_device_del().
>>
>> Bonus: gets rid of a non-literal format string.  A step towards
>> compile-time format string checking without triggering
>> -Wformat-nonliteral.
>
> Where? [1]
>
>>
>> Cc: Thomas Huth <thuth@redhat.com>
>> Cc: Juan Quintela <quintela@redhat.com>
>> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> Cc: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Juan Quintela <quintela@redhat.com>
>> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> ---
>
>> +++ b/tests/libqtest.c
>> @@ -1029,6 +1029,35 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
>>       qobject_unref(response);
>>   }
>>   +QDict *qtest_qmp_receive_success(QTestState *s,
>> +                                 void (*event_cb)(void *opaque,
>> +                                                  const char *event,
>> +                                                  QDict *data),
>> +                                 void *opaque)
>> +{
>
> I like the new signature!
>
>> +++ b/tests/migration-test.c
>
>>   /*
>>    * Events can get in the way of responses we are actually waiting for.
>>    */
>>   static QDict *wait_command(QTestState *who, const char *command)
>>   {
>
> [1] This is still taking a format non-literal command...
>
>> -    const char *event_string;
>> -    QDict *response, *ret;
>> -
>> -    response = qtest_qmp(who, command);
> ...
>> +    qtest_qmp_send(who, command);
>
> and is passing it on through.

No worse than before.  Will be fixed in the next two patches.

>> +    return qtest_qmp_receive_success(who, stop_cb, NULL);
>>   }
>>   
>
>> +++ b/tests/tpm-util.c
>
>> -/*
>> - * Events can get in the way of responses we are actually waiting for.
>> - */
>> -static QDict *tpm_util_wait_command(QTestState *who, const char *command)
>> -{
>
> Maybe you were counting this instance,
>

    -    const char *event_string;
    -    QDict *response;
    -
    -    response = qtest_qmp(who, command);

/work/armbru/qemu/tests/tpm-util.c: In function ‘tpm_util_wait_command’:
/work/armbru/qemu/tests/tpm-util.c:258:5: warning: format not a string literal and no format arguments [-Wformat-security]
     response = qtest_qmp(who, command);
     ^~~~~~~~

    -
    -    while (qdict_haskey(response, "event")) {
    -        /* OK, it was an event */
    -        event_string = qdict_get_str(response, "event");
    -        if (!strcmp(event_string, "STOP")) {
    -            got_stop = true;
    -        }
    -        qobject_unref(response);
    -        response = qtest_qmp_receive(who);
    -    }
    -    return response;
    -}
>>   void tpm_util_wait_for_migration_complete(QTestState *who)
>>   {
>>       while (true) {
>> -        QDict *rsp, *rsp_return;
>> +        QDict *rsp_return;
>>           bool completed;
>>           const char *status;
>>   -        rsp = tpm_util_wait_command(who, "{ 'execute':
>> 'query-migrate' }");
>> -        rsp_return = qdict_get_qdict(rsp, "return");
>> +        qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");
>
> where you did indeed drop a format non-literal?

> But on the assumption that there's more cleanups later in the series,
> this is indeed incrementally better, so
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2
  2018-07-27 16:05   ` Eric Blake
@ 2018-07-30  6:19     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:19 UTC (permalink / raw)
  To: Eric Blake
  Cc: qemu-devel, thuth, f4bug, Dr . David Alan Gilbert, Juan Quintela

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> Leaving interpolation into JSON to qmp() is more robust than building
>> QMP input manually, as explained in the recent commit "tests: Clean up
>> string interpolation into QMP input (simple cases)".
>>
>> migrate() interpolates members into a JSON object.  Change it to take
>> its extra QMP arguments as arguments for qdict_from_jsonf_nofail()
>> instead of a string containing JSON members.
>>
>> Bonus: gets rid of a non-literal format string.  A step towards
>> compile-time format string checking without triggering
>> -Wformat-nonliteral.
>>
>> Cc: Juan Quintela <quintela@redhat.com>
>> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Juan Quintela <quintela@redhat.com>
>> ---
>>   tests/migration-test.c | 28 ++++++++++++++++------------
>>   1 file changed, 16 insertions(+), 12 deletions(-)
>>
>
>> +++ b/tests/migration-test.c
>> @@ -14,6 +14,7 @@
>>     #include "libqtest.h"
>>   #include "qapi/qmp/qdict.h"
>> +#include "qapi/qmp/qjson.h"
>>   #include "qemu/option.h"
>>   #include "qemu/range.h"
>>   #include "qemu/sockets.h"
>> @@ -381,16 +382,19 @@ static void migrate_set_capability(QTestState *who, const char *capability,
>>       qobject_unref(rsp);
>>   }
>>   -static void migrate(QTestState *who, const char *uri, const char
>> *extra)
>> +static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
>>   {
>
> No gcc attribute?

Good point; adding one.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3
  2018-07-27 16:11   ` Eric Blake
@ 2018-07-30  6:25     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:25 UTC (permalink / raw)
  To: Eric Blake
  Cc: Markus Armbruster, qemu-devel, thuth, f4bug,
	Dr . David Alan Gilbert, Juan Quintela

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> Leaving interpolation into JSON to qmp() is more robust than building
>> QMP input manually, as explained in the recent commit "tests: Clean up
>> string interpolation into QMP input (simple cases)".
>>
>> migration-test.c interpolates strings into JSON in a few places:
>>
>> * migrate_set_parameter() interpolates string parameter @value as a
>>    JSON number.  Change it to long long.  This requires changing
>>    migrate_check_parameter() similarly.
>>
>> * migrate_set_capability() interpolates string parameter @value as a
>>    JSON boolean.  Change it to bool.
>>
>> * deprecated_set_speed() interpolates string parameter @value as a
>>    JSON number.  Change it to long long.
>>
>> Bonus: gets rid of non-literal format strings.  A step towards
>> compile-time format string checking without triggering
>> -Wformat-nonliteral.
>>
>> Cc: Juan Quintela <quintela@redhat.com>
>> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Juan Quintela <quintela@redhat.com>
>> ---
>>   tests/migration-test.c | 74 +++++++++++++++++-------------------------
>>   1 file changed, 29 insertions(+), 45 deletions(-)
>>
>> diff --git a/tests/migration-test.c b/tests/migration-test.c
>> index 1c1e56b15b..132c30891d 100644
>> --- a/tests/migration-test.c
>> +++ b/tests/migration-test.c
>> @@ -315,31 +315,25 @@ static void cleanup(const char *filename)
>>   }
>>     static void migrate_check_parameter(QTestState *who, const char
>> *parameter,
>> -                                    const char *value)
>> +                                    long long value)
>>   {
>>       QDict *rsp_return;
>> -    char *result;
>>         rsp_return = wait_command(who,
>>                                 "{ 'execute': 'query-migrate-parameters' }");
>> -    result = g_strdup_printf("%" PRId64,
>> -                             qdict_get_try_int(rsp_return,  parameter, -1));
>> -    g_assert_cmpstr(result, ==, value);
>
> The old code allows defaulting to -1 if the value is not present;
>
>> -    g_free(result);
>> +    g_assert_cmpint(qdict_get_int(rsp_return,  parameter), ==, value);
>
> the new code requires the value to be found.  Matters if any of the
> callers passed "-1" in the old code, but a search of the file doesn't
> spot any such callers. So I think you're okay.

Also:

    ##
    # @MigrationParameters:
    #
    # The optional members aren't actually optional.
    #

This is due to commit 1bda8b3c695.

> Also, while touching this line, it would be nice to get rid of the
> double space before parameter.

Of course.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 17:05   ` Eric Blake
@ 2018-07-30  6:28     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:28 UTC (permalink / raw)
  To: Eric Blake; +Cc: Markus Armbruster, qemu-devel, thuth, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> qtest_qmp_discard_response(...) is shorthand for
>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>> Moreover, the presence of these functions encourage sloppy testing.
>> Remove them.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>
>> +++ b/tests/ahci-test.c
>> @@ -1607,14 +1607,14 @@ static void test_atapi_tray(void)
>>       atapi_wait_tray(true);
>>         /* Re-insert media */
>> -    qmp_discard_response("{'execute': 'blockdev-add', "
>> +    qobject_unref(qmp("{'execute': 'blockdev-add', "
>>                             "'arguments': {'node-name': 'node0', "
>>                                           "'driver': 'raw', "
>>                                           "'file': { 'driver': 'file', "
>> -                                                  "'filename': %s }}}", iso);
>> -    qmp_discard_response("{'execute': 'blockdev-insert-medium',"
>> +                      "'filename': %s }}}", iso));
>
> Why did you fix indentation for some, but not all, of the lines here?

Editing accident, fixing.

>> +    qobject_unref(qmp("{'execute': 'blockdev-insert-medium',"
>>                             "'arguments': { 'id': 'cd0', "
>> -                                         "'node-name': 'node0' }}");
>> +                      "'node-name': 'node0' }}"));
>
> Again, indentation looks odd.

Likewise.

>> +++ b/tests/fdc-test.c
>> @@ -26,6 +26,7 @@
>>       #include "libqtest.h"
>> +#include "qapi/qmp/qdict.h"
>>   #include "qemu-common.h"
>>     #define TEST_IMAGE_SIZE 1440 * 1024
>> @@ -298,9 +299,9 @@ static void test_media_insert(void)
>>         /* Insert media in drive. DSKCHK should not be reset until a
>> step pulse
>>        * is sent. */
>> -    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
>> +    qobject_unref(qmp("{'execute':'blockdev-change-medium', 'arguments':{"
>>                            " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
>> -                         test_image);
>> +                      test_image));
>
> Another place where indentation looks odd.

Likewise.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-27 17:03     ` Eric Blake
@ 2018-07-30  6:32       ` Markus Armbruster
  2018-08-01  6:46         ` Thomas Huth
  0 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:32 UTC (permalink / raw)
  To: Eric Blake; +Cc: thuth, qemu-devel, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 11:46 AM, Thomas Huth wrote:
>> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>>> qtest_qmp_discard_response(...) is shorthand for
>>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>>
>> But the latter is IMHO harder to read.

Doing things sloppily looks a bit uglier now.  That's a feature.

> Maybe, but then it lends itself well to:
>
> QObject *rsp = qtest_qmp(...);
> qobject_unref(rsp);
>
> which is where you do insert tests for valid responses.
>
>> And it might be shorter in the compiled binary (one function call vs. two).

I'd be quite sympathetic to this argument...

> The size of the test binaries is not our biggest concern.

... outside tests/.

>>> Moreover, the presence of these functions encourage sloppy testing.
>>
>> Shouldn't we then rather fix the tests to check for valid responses
>> instead of replacing this function with harder-to-read code?

I'd welcome such patches, but this series is already pretty long.

> I think such fixes are now easier to make, but can be separate
> followup patches. The mechanical conversion is fine to me.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf()
  2018-07-27 17:08   ` Eric Blake
@ 2018-07-30  6:32     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:32 UTC (permalink / raw)
  To: Eric Blake; +Cc: Markus Armbruster, qemu-devel, thuth, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/27/2018 10:13 AM, Markus Armbruster wrote:
>> qtest_init() creates a new QTestState, and leaves @global_qtest alone.
>> qtest_start() additionally assigns it to @global_qtest, but
>> qtest_startf() additionall sets assigns NULL to @global_qtest.  This
>
> s/additionall sets/additionally/

Fixing...

>> makes no sense.  Replace it by qtest_initf() that works like
>> qtest_init(), i.e. leaves @global_qtest alone.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency
  2018-07-27 17:19   ` Thomas Huth
@ 2018-07-30  6:47     ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  6:47 UTC (permalink / raw)
  To: Thomas Huth; +Cc: Markus Armbruster, qemu-devel, f4bug

Thomas Huth <thuth@redhat.com> writes:

> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  tests/libqtest.c | 12 ++++++------
>>  tests/libqtest.h |  4 ++--
>>  2 files changed, 8 insertions(+), 8 deletions(-)
>> 
>> diff --git a/tests/libqtest.c b/tests/libqtest.c
>> index a0d44793fa..3706f30aa2 100644
>> --- a/tests/libqtest.c
>> +++ b/tests/libqtest.c
>> @@ -538,7 +538,7 @@ QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
>>      return qmp_fd_receive(fd);
>>  }
>>  
>> -QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
>> +QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap)
>
> Unless you also add something to our coding conventions which mandates
> the naming to be always this way, I think this is just unnecessary code
> churn.

Consistency isn't "necessary", but it helps.

Tree-wide consistency would be nice, but my aim right now is local
consistency in libqtest.h.  Four out of its six functions taking va_list
are sensibly named.  This patch renames the remaining two.  Well worth
the diffstat, in my opinion.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-27 15:48   ` Eric Blake
  2018-07-30  6:04     ` Markus Armbruster
@ 2018-07-30  8:34     ` Markus Armbruster
  2018-07-30 15:25       ` Eric Blake
  1 sibling, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-07-30  8:34 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, thuth, f4bug

Eric Blake <eblake@redhat.com> writes:

[...]
> (We really want to assert that any % interpolations in our JSON parser
> are NOT embedded in '').

I'll look into that, but it'll be in a separate series.

[...]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-30  8:34     ` Markus Armbruster
@ 2018-07-30 15:25       ` Eric Blake
  2018-07-31  6:16         ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Blake @ 2018-07-30 15:25 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, thuth, f4bug

On 07/30/2018 03:34 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
> [...]
>> (We really want to assert that any % interpolations in our JSON parser
>> are NOT embedded in '').
> 
> I'll look into that, but it'll be in a separate series.

Agreed.  In fact, my more ambitious series had reached that point by 
implementing %% interpolation inside strings, combined with asserting 
that %% cannot occur except within strings during the JSON parse, then 
during the JSON interpolation that the only use of % within strings was 
the %% escape (so that we no longer risk consuming a va-arg during 
string interpolation, while still benefiting from gcc's -Wformat 
checking).  So probably one of the easier things to revive, once this 
series lands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add()
  2018-07-30 15:25       ` Eric Blake
@ 2018-07-31  6:16         ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-07-31  6:16 UTC (permalink / raw)
  To: Eric Blake; +Cc: thuth, qemu-devel, f4bug

Eric Blake <eblake@redhat.com> writes:

> On 07/30/2018 03:34 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>>
>> [...]
>>> (We really want to assert that any % interpolations in our JSON parser
>>> are NOT embedded in '').
>>
>> I'll look into that, but it'll be in a separate series.
>
> Agreed.  In fact, my more ambitious series had reached that point by
> implementing %% interpolation inside strings, combined with asserting
> that %% cannot occur except within strings during the JSON parse, then
> during the JSON interpolation that the only use of % within strings
> was the %% escape (so that we no longer risk consuming a va-arg during
> string interpolation, while still benefiting from gcc's -Wformat
> checking).  So probably one of the easier things to revive, once this
> series lands.

The problem: the compiler recognizes conversion specifications the JSON
parser doesn't recognize.  Can lead to crashes or silent misbehavior.

The JSON lexer recognizes conversion specification tokens, and the JSON
parser accepts them as JSON value.  The lexer rejects conversion
specification tokens we don't support.  Conversion specifications within
tokens are not recognized.  Since only string tokens can contain '%',
conversion specifications can hide from the JSON parser only there.

I can see three ways to fix that.  All three make the JSON parser
recognize all conversion specifications.  They differ in which ones
fail.

1. Obey:

   The ones inside strings work as in sprintf().

   Example:
   "{ 'str': %s, 'act': '%.0f%%', 'max': '100%%' }", str, p * 100.0

   Encourages interpolation into strings, which is problematic, as
   explained in PATCH 11 "tests: Clean up string interpolation into QMP
   input (simple cases)".  Moreover, supporting some conversion
   specifications only in strings (e.g. %g, %.0f, %%) could be
   confusing.

2. Obey "%%" in strings, reject the rest

   You can only interpolate strings, not into strings.  To put a '%'
   intro a string, you have to double it.

   Example:
   "{ 'str': %s, 'pct': %s, 'max': '100%%' }", str, pct
   where pct = g_strdup_printf("%0.f%%", p * 100.0)

   Strings are interpreted differently when the JSON parser has
   interpolation enabled.  That's the price we have to pay for not
   having to interpolate strings containing '%'.

3. Reject:

   You can't have '%' in strings.  To get a string containing '%', you
   have to interpolate it.

   Example:
   "{ 'str': %s, 'pct': %s, 'max': %s }", str, pct, "100%"
   where pct = g_strdup_printf("%0.f%%", p * 100.0)

   This is the simplest solution.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-07-30  6:32       ` Markus Armbruster
@ 2018-08-01  6:46         ` Thomas Huth
  2018-08-02  4:53           ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-08-01  6:46 UTC (permalink / raw)
  To: Markus Armbruster, Eric Blake; +Cc: qemu-devel, f4bug

On 07/30/2018 08:32 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> On 07/27/2018 11:46 AM, Thomas Huth wrote:
>>> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>>>> qtest_qmp_discard_response(...) is shorthand for
>>>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>>>
>>> But the latter is IMHO harder to read.
> 
> Doing things sloppily looks a bit uglier now.  That's a feature.
> 
>> Maybe, but then it lends itself well to:
>>
>> QObject *rsp = qtest_qmp(...);
>> qobject_unref(rsp);
>>
>> which is where you do insert tests for valid responses.
>>
>>> And it might be shorter in the compiled binary (one function call vs. two).
> 
> I'd be quite sympathetic to this argument...
> 
>> The size of the test binaries is not our biggest concern.
> 
> ... outside tests/.
> 
>>>> Moreover, the presence of these functions encourage sloppy testing.
>>>
>>> Shouldn't we then rather fix the tests to check for valid responses
>>> instead of replacing this function with harder-to-read code?
> 
> I'd welcome such patches, but this series is already pretty long.

Then maybe rather drop this patch from this series, and fix the issues
in a separate series instead?

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-08-01  6:46         ` Thomas Huth
@ 2018-08-02  4:53           ` Markus Armbruster
  2018-08-02  5:30             ` Thomas Huth
  0 siblings, 1 reply; 69+ messages in thread
From: Markus Armbruster @ 2018-08-02  4:53 UTC (permalink / raw)
  To: Thomas Huth; +Cc: Eric Blake, qemu-devel, f4bug

Thomas Huth <thuth@redhat.com> writes:

> On 07/30/2018 08:32 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> On 07/27/2018 11:46 AM, Thomas Huth wrote:
>>>> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>>>>> qtest_qmp_discard_response(...) is shorthand for
>>>>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>>>>
>>>> But the latter is IMHO harder to read.
>> 
>> Doing things sloppily looks a bit uglier now.  That's a feature.
>> 
>>> Maybe, but then it lends itself well to:
>>>
>>> QObject *rsp = qtest_qmp(...);
>>> qobject_unref(rsp);
>>>
>>> which is where you do insert tests for valid responses.
>>>
>>>> And it might be shorter in the compiled binary (one function call vs. two).
>> 
>> I'd be quite sympathetic to this argument...
>> 
>>> The size of the test binaries is not our biggest concern.
>> 
>> ... outside tests/.
>> 
>>>>> Moreover, the presence of these functions encourage sloppy testing.
>>>>
>>>> Shouldn't we then rather fix the tests to check for valid responses
>>>> instead of replacing this function with harder-to-read code?
>> 
>> I'd welcome such patches, but this series is already pretty long.
>
> Then maybe rather drop this patch from this series, and fix the issues
> in a separate series instead?

Do you insist?

I fail to see how changing

    qmp_discard_response("{ 'execute': 'system_reset' }");

to

    qobject_unref(qmp("{ 'execute': 'system_reset' }"));

is so awful it would justify demanding I pause my work on libqtest to
first figure out which parts of ignored responses are worth checking,
then code up the checks.

Would you accept

    rsp = qmp("{ 'execute': 'system_reset' }"));
    qobject_unref(rsp);

?

If none of the above is acceptable to you, then I'll push the crap that
needs to go from libqtest into the crap-using tests, like this:

    /* TODO actually test the results and get rid of this */
    #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__));

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-08-02  4:53           ` Markus Armbruster
@ 2018-08-02  5:30             ` Thomas Huth
  2018-08-02 18:31               ` Markus Armbruster
  0 siblings, 1 reply; 69+ messages in thread
From: Thomas Huth @ 2018-08-02  5:30 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Eric Blake, qemu-devel, f4bug

On 08/02/2018 06:53 AM, Markus Armbruster wrote:
> Thomas Huth <thuth@redhat.com> writes:
> 
>> On 07/30/2018 08:32 AM, Markus Armbruster wrote:
>>> Eric Blake <eblake@redhat.com> writes:
>>>
>>>> On 07/27/2018 11:46 AM, Thomas Huth wrote:
>>>>> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>>>>>> qtest_qmp_discard_response(...) is shorthand for
>>>>>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>>>>>
>>>>> But the latter is IMHO harder to read.
>>>
>>> Doing things sloppily looks a bit uglier now.  That's a feature.
>>>
>>>> Maybe, but then it lends itself well to:
>>>>
>>>> QObject *rsp = qtest_qmp(...);
>>>> qobject_unref(rsp);
>>>>
>>>> which is where you do insert tests for valid responses.
>>>>
>>>>> And it might be shorter in the compiled binary (one function call vs. two).
>>>
>>> I'd be quite sympathetic to this argument...
>>>
>>>> The size of the test binaries is not our biggest concern.
>>>
>>> ... outside tests/.
>>>
>>>>>> Moreover, the presence of these functions encourage sloppy testing.
>>>>>
>>>>> Shouldn't we then rather fix the tests to check for valid responses
>>>>> instead of replacing this function with harder-to-read code?
>>>
>>> I'd welcome such patches, but this series is already pretty long.
>>
>> Then maybe rather drop this patch from this series, and fix the issues
>> in a separate series instead?
> 
> Do you insist?

No. But I'd still like to convince you that this patch is unnecessary
right now.

> I fail to see how changing
> 
>     qmp_discard_response("{ 'execute': 'system_reset' }");
> 
> to
> 
>     qobject_unref(qmp("{ 'execute': 'system_reset' }"));
> 
> is so awful it would justify demanding I pause my work on libqtest to
> first figure out which parts of ignored responses are worth checking,
> then code up the checks.

First, you don't have to pause this series just because of this, since
the remaining two patches do not depend on this one.
Then, I still fail to see the real benefit here. You've found something
that needs proper clean up later (by adding checks for valid responses).
So IMHO simply add a big fat warning comment to the description of
qmp_discard_response would be sufficient. Then you can easily grep for
"qmp_discard_response" later to find the spots that need fixing. If you
replace it with that ugly nested construct instead, we still should fix
it later, but it's a little bit harder to grep, and since we need to
change it later again anyway, it just sounds like unnecessary code churn
to me. So do you really need this so badly (for your later work?), or
could you simply skip this patch?

> Would you accept
> 
>     rsp = qmp("{ 'execute': 'system_reset' }"));
>     qobject_unref(rsp);
> 
> ?

While this is easier to read, I think we lose the easy way to grep for
the spots that need fixing later here, so let's better not do this.

> If none of the above is acceptable to you, then I'll push the crap that
> needs to go from libqtest into the crap-using tests, like this:
> 
>     /* TODO actually test the results and get rid of this */
>     #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__));

Fine for me.

 Thomas

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends
  2018-08-02  5:30             ` Thomas Huth
@ 2018-08-02 18:31               ` Markus Armbruster
  0 siblings, 0 replies; 69+ messages in thread
From: Markus Armbruster @ 2018-08-02 18:31 UTC (permalink / raw)
  To: Thomas Huth; +Cc: qemu-devel, f4bug

Thomas Huth <thuth@redhat.com> writes:

> On 08/02/2018 06:53 AM, Markus Armbruster wrote:
>> Thomas Huth <thuth@redhat.com> writes:
>> 
>>> On 07/30/2018 08:32 AM, Markus Armbruster wrote:
>>>> Eric Blake <eblake@redhat.com> writes:
>>>>
>>>>> On 07/27/2018 11:46 AM, Thomas Huth wrote:
>>>>>> On 07/27/2018 05:13 PM, Markus Armbruster wrote:
>>>>>>> qtest_qmp_discard_response(...) is shorthand for
>>>>>>> qobject_unref(qtest_qmp(...), except it's not actually shorter.
>>>>>>
>>>>>> But the latter is IMHO harder to read.
>>>>
>>>> Doing things sloppily looks a bit uglier now.  That's a feature.
>>>>
>>>>> Maybe, but then it lends itself well to:
>>>>>
>>>>> QObject *rsp = qtest_qmp(...);
>>>>> qobject_unref(rsp);
>>>>>
>>>>> which is where you do insert tests for valid responses.
>>>>>
>>>>>> And it might be shorter in the compiled binary (one function call vs. two).
>>>>
>>>> I'd be quite sympathetic to this argument...
>>>>
>>>>> The size of the test binaries is not our biggest concern.
>>>>
>>>> ... outside tests/.
>>>>
>>>>>>> Moreover, the presence of these functions encourage sloppy testing.
>>>>>>
>>>>>> Shouldn't we then rather fix the tests to check for valid responses
>>>>>> instead of replacing this function with harder-to-read code?
>>>>
>>>> I'd welcome such patches, but this series is already pretty long.
>>>
>>> Then maybe rather drop this patch from this series, and fix the issues
>>> in a separate series instead?
>> 
>> Do you insist?
>
> No. But I'd still like to convince you that this patch is unnecessary
> right now.
>
>> I fail to see how changing
>> 
>>     qmp_discard_response("{ 'execute': 'system_reset' }");
>> 
>> to
>> 
>>     qobject_unref(qmp("{ 'execute': 'system_reset' }"));
>> 
>> is so awful it would justify demanding I pause my work on libqtest to
>> first figure out which parts of ignored responses are worth checking,
>> then code up the checks.
>
> First, you don't have to pause this series just because of this, since
> the remaining two patches do not depend on this one.

I intend to swap with the previous patch in v3 to reduce churn.

> Then, I still fail to see the real benefit here. You've found something
> that needs proper clean up later (by adding checks for valid responses).
> So IMHO simply add a big fat warning comment to the description of
> qmp_discard_response would be sufficient.

Warnings in function comments are ineffective at counterproliferation.
People copy code without examining the called functions' comments.

>                                           Then you can easily grep for
> "qmp_discard_response" later to find the spots that need fixing. If you
> replace it with that ugly nested construct instead, we still should fix
> it later, but it's a little bit harder to grep, and since we need to
> change it later again anyway, it just sounds like unnecessary code churn
> to me. So do you really need this so badly (for your later work?), or
> could you simply skip this patch?
>
>> Would you accept
>> 
>>     rsp = qmp("{ 'execute': 'system_reset' }"));
>>     qobject_unref(rsp);
>> 
>> ?
>
> While this is easier to read, I think we lose the easy way to grep for
> the spots that need fixing later here, so let's better not do this.
>
>> If none of the above is acceptable to you, then I'll push the crap that
>> needs to go from libqtest into the crap-using tests, like this:
>> 
>>     /* TODO actually test the results and get rid of this */
>>     #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__));
>
> Fine for me.

Sold.

^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2018-08-02 18:32 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-27 15:13 [Qemu-devel] [PATCH v2 00/23] tests: Compile-time format string checking for libqtest.h Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 01/23] libqtest: Document calling conventions Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 02/23] libqtest: Rename functions to send QMP messages Markus Armbruster
2018-07-27 15:24   ` Eric Blake
2018-07-30  5:41     ` Markus Armbruster
2018-07-27 16:35   ` Thomas Huth
2018-07-27 17:06     ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 03/23] libqtest: Clean up how we read device_del messages Markus Armbruster
2018-07-27 15:24   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 04/23] libqtest: Clean up how we read the QMP greeting Markus Armbruster
2018-07-27 15:25   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 05/23] qobject: Replace qobject_from_jsonf() by qobject_from_jsonf_nofail() Markus Armbruster
2018-07-27 15:28   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 06/23] qobject: New qobject_from_vjsonf_nofail(), qdict_from_vjsonf_nofail() Markus Armbruster
2018-07-27 15:30   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 07/23] libqtest: Simplify qmp_fd_vsend() a bit Markus Armbruster
2018-07-27 15:31   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 08/23] test-qobject-input-visitor: Avoid format string ambiguity Markus Armbruster
2018-07-27 15:33   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 09/23] qobject: qobject_from_jsonv() is dangerous, hide it away Markus Armbruster
2018-07-27 15:34   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 10/23] tests: Pass literal format strings directly to qmp_FOO() Markus Armbruster
2018-07-27 15:35   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 11/23] tests: Clean up string interpolation into QMP input (simple cases) Markus Armbruster
2018-07-27 15:39   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 12/23] cpu-plug-test: Don't pass integers as strings to device_add Markus Armbruster
2018-07-27 15:42   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 13/23] tests: Clean up string interpolation around qtest_qmp_device_add() Markus Armbruster
2018-07-27 15:48   ` Eric Blake
2018-07-30  6:04     ` Markus Armbruster
2018-07-30  8:34     ` Markus Armbruster
2018-07-30 15:25       ` Eric Blake
2018-07-31  6:16         ` Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 14/23] migration-test: Make wait_command() return the "return" member Markus Armbruster
2018-07-27 15:50   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 15/23] tests: New helper qtest_qmp_receive_success() Markus Armbruster
2018-07-27 16:00   ` Eric Blake
2018-07-30  6:10     ` Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 16/23] migration-test: Make wait_command() cope with '%' Markus Armbruster
2018-07-27 16:02   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 17/23] migration-test: Clean up string interpolation into QMP, part 1 Markus Armbruster
2018-07-27 16:04   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 18/23] migration-test: Clean up string interpolation into QMP, part 2 Markus Armbruster
2018-07-27 16:05   ` Eric Blake
2018-07-30  6:19     ` Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 19/23] migration-test: Clean up string interpolation into QMP, part 3 Markus Armbruster
2018-07-27 16:11   ` Eric Blake
2018-07-30  6:25     ` Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 20/23] libqtest: Enable compile-time format string checking Markus Armbruster
2018-07-27 16:18   ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 21/23] libqtest: Remove qtest_qmp_discard_response() & friends Markus Armbruster
2018-07-27 16:46   ` Thomas Huth
2018-07-27 17:03     ` Eric Blake
2018-07-30  6:32       ` Markus Armbruster
2018-08-01  6:46         ` Thomas Huth
2018-08-02  4:53           ` Markus Armbruster
2018-08-02  5:30             ` Thomas Huth
2018-08-02 18:31               ` Markus Armbruster
2018-07-27 17:05   ` Eric Blake
2018-07-30  6:28     ` Markus Armbruster
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 22/23] libqtest: Replace qtest_startf() by qtest_initf() Markus Armbruster
2018-07-27 17:08   ` Eric Blake
2018-07-30  6:32     ` Markus Armbruster
2018-07-27 17:18   ` Thomas Huth
2018-07-27 18:52     ` Eric Blake
2018-07-27 15:13 ` [Qemu-devel] [PATCH v2 23/23] libqtest: Rename qtest_FOOv() to qtest_vFOO() for consistency Markus Armbruster
2018-07-27 17:10   ` Eric Blake
2018-07-27 17:19   ` Thomas Huth
2018-07-30  6:47     ` Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.