0a122b
From 5f073207f144613806bc0b004a01ef66da9ad5e0 Mon Sep 17 00:00:00 2001
0a122b
Message-Id: <5f073207f144613806bc0b004a01ef66da9ad5e0.1387288155.git.minovotn@redhat.com>
0a122b
In-Reply-To: <527da6c2ce2c09d0183aa8595fc95f136f61b6df.1387288155.git.minovotn@redhat.com>
0a122b
References: <527da6c2ce2c09d0183aa8595fc95f136f61b6df.1387288155.git.minovotn@redhat.com>
0a122b
From: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Date: Thu, 12 Dec 2013 16:21:25 +0100
0a122b
Subject: [PATCH 5/8] libqtest: add qmp(fmt, ...) -> QDict* function
0a122b
MIME-Version: 1.0
0a122b
Content-Type: text/plain; charset=UTF-8
0a122b
Content-Transfer-Encoding: 8bit
0a122b
0a122b
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Message-id: <1386865288-1575-6-git-send-email-stefanha@redhat.com>
0a122b
Patchwork-id: 56259
0a122b
O-Subject: [RHEL7 qemu-kvm PATCH 5/8] libqtest: add qmp(fmt, ...) -> QDict* function
0a122b
Bugzilla: 1003773
0a122b
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
0a122b
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
0a122b
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
0a122b
0a122b
Add a qtest qmp() function that returns the response object.  This
0a122b
allows test cases to verify the result or to check for error responses.
0a122b
It also allows waiting for QMP events.
0a122b
0a122b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Reviewed-by: Eric Blake <eblake@redhat.com>
0a122b
Reviewed-by: Andreas Färber <afaerber@suse.de>
0a122b
(cherry picked from commit 0c460dac03e7919079525d8e24ef2c4c607c219d)
0a122b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
---
0a122b
 tests/libqtest.c | 66 ++++++++++++++++++++++++++++++++++++++++++++------------
0a122b
 tests/libqtest.h | 37 +++++++++++++++++++++++++++++++
0a122b
 2 files changed, 89 insertions(+), 14 deletions(-)
0a122b
0a122b
Signed-off-by: Michal Novotny <minovotn@redhat.com>
0a122b
---
0a122b
 tests/libqtest.c | 66 ++++++++++++++++++++++++++++++++++++++++++++------------
0a122b
 tests/libqtest.h | 37 +++++++++++++++++++++++++++++++
0a122b
 2 files changed, 89 insertions(+), 14 deletions(-)
0a122b
0a122b
diff --git a/tests/libqtest.c b/tests/libqtest.c
0a122b
index dc4c983..83424c3 100644
0a122b
--- a/tests/libqtest.c
0a122b
+++ b/tests/libqtest.c
0a122b
@@ -30,6 +30,8 @@
0a122b
 
0a122b
 #include "qemu/compiler.h"
0a122b
 #include "qemu/osdep.h"
0a122b
+#include "qapi/qmp/json-streamer.h"
0a122b
+#include "qapi/qmp/json-parser.h"
0a122b
 
0a122b
 #define MAX_IRQ 256
0a122b
 
0a122b
@@ -291,16 +293,38 @@ redo:
0a122b
     return words;
0a122b
 }
0a122b
 
0a122b
-void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
0a122b
+typedef struct {
0a122b
+    JSONMessageParser parser;
0a122b
+    QDict *response;
0a122b
+} QMPResponseParser;
0a122b
+
0a122b
+static void qmp_response(JSONMessageParser *parser, QList *tokens)
0a122b
 {
0a122b
-    bool has_reply = false;
0a122b
-    int nesting = 0;
0a122b
+    QMPResponseParser *qmp = container_of(parser, QMPResponseParser, parser);
0a122b
+    QObject *obj;
0a122b
+
0a122b
+    obj = json_parser_parse(tokens, NULL);
0a122b
+    if (!obj) {
0a122b
+        fprintf(stderr, "QMP JSON response parsing failed\n");
0a122b
+        exit(1);
0a122b
+    }
0a122b
+
0a122b
+    g_assert(qobject_type(obj) == QTYPE_QDICT);
0a122b
+    g_assert(!qmp->response);
0a122b
+    qmp->response = (QDict *)obj;
0a122b
+}
0a122b
+
0a122b
+QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
0a122b
+{
0a122b
+    QMPResponseParser qmp;
0a122b
 
0a122b
     /* Send QMP request */
0a122b
     socket_sendf(s->qmp_fd, fmt, ap);
0a122b
 
0a122b
     /* Receive reply */
0a122b
-    while (!has_reply || nesting > 0) {
0a122b
+    qmp.response = NULL;
0a122b
+    json_message_parser_init(&qmp.parser, qmp_response);
0a122b
+    while (!qmp.response) {
0a122b
         ssize_t len;
0a122b
         char c;
0a122b
 
0a122b
@@ -314,25 +338,39 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
0a122b
             exit(1);
0a122b
         }
0a122b
 
0a122b
-        switch (c) {
0a122b
-        case '{':
0a122b
-            nesting++;
0a122b
-            has_reply = true;
0a122b
-            break;
0a122b
-        case '}':
0a122b
-            nesting--;
0a122b
-            break;
0a122b
-        }
0a122b
+        json_message_parser_feed(&qmp.parser, &c, 1);
0a122b
     }
0a122b
+    json_message_parser_destroy(&qmp.parser);
0a122b
+
0a122b
+    return qmp.response;
0a122b
+}
0a122b
+
0a122b
+QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
0a122b
+{
0a122b
+    va_list ap;
0a122b
+    QDict *response;
0a122b
+
0a122b
+    va_start(ap, fmt);
0a122b
+    response = qtest_qmpv(s, fmt, ap);
0a122b
+    va_end(ap);
0a122b
+    return response;
0a122b
+}
0a122b
+
0a122b
+void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
0a122b
+{
0a122b
+    QDict *response = qtest_qmpv(s, fmt, ap);
0a122b
+    QDECREF(response);
0a122b
 }
0a122b
 
0a122b
 void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...)
0a122b
 {
0a122b
     va_list ap;
0a122b
+    QDict *response;
0a122b
 
0a122b
     va_start(ap, fmt);
0a122b
-    qtest_qmpv_discard_response(s, fmt, ap);
0a122b
+    response = qtest_qmpv(s, fmt, ap);
0a122b
     va_end(ap);
0a122b
+    QDECREF(response);
0a122b
 }
0a122b
 
0a122b
 const char *qtest_get_arch(void)
0a122b
diff --git a/tests/libqtest.h b/tests/libqtest.h
0a122b
index 3faa49b..0d914f6 100644
0a122b
--- a/tests/libqtest.h
0a122b
+++ b/tests/libqtest.h
0a122b
@@ -22,6 +22,7 @@
0a122b
 #include <stdbool.h>
0a122b
 #include <stdarg.h>
0a122b
 #include <sys types.h="">
0a122b
+#include "qapi/qmp/qdict.h"
0a122b
 
0a122b
 typedef struct QTestState QTestState;
0a122b
 
0a122b
@@ -53,6 +54,15 @@ void qtest_quit(QTestState *s);
0a122b
 void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
0a122b
 
0a122b
 /**
0a122b
+ * qtest_qmp:
0a122b
+ * @s: #QTestState instance to operate on.
0a122b
+ * @fmt...: QMP message to send to qemu
0a122b
+ *
0a122b
+ * Sends a QMP message to QEMU and returns the response.
0a122b
+ */
0a122b
+QDict *qtest_qmp(QTestState *s, const char *fmt, ...);
0a122b
+
0a122b
+/**
0a122b
  * qtest_qmpv_discard_response:
0a122b
  * @s: #QTestState instance to operate on.
0a122b
  * @fmt: QMP message to send to QEMU
0a122b
@@ -63,6 +73,16 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
0a122b
 void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
0a122b
 
0a122b
 /**
0a122b
+ * qtest_qmpv:
0a122b
+ * @s: #QTestState instance to operate on.
0a122b
+ * @fmt: QMP message to send to QEMU
0a122b
+ * @ap: QMP message arguments
0a122b
+ *
0a122b
+ * Sends a QMP message to QEMU and returns the response.
0a122b
+ */
0a122b
+QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
0a122b
+
0a122b
+/**
0a122b
  * qtest_get_irq:
0a122b
  * @s: #QTestState instance to operate on.
0a122b
  * @num: Interrupt to observe.
0a122b
@@ -331,6 +351,23 @@ static inline void qtest_end(void)
0a122b
 }
0a122b
 
0a122b
 /**
0a122b
+ * qmp:
0a122b
+ * @fmt...: QMP message to send to qemu
0a122b
+ *
0a122b
+ * Sends a QMP message to QEMU and returns the response.
0a122b
+ */
0a122b
+static inline QDict *qmp(const char *fmt, ...)
0a122b
+{
0a122b
+    va_list ap;
0a122b
+    QDict *response;
0a122b
+
0a122b
+    va_start(ap, fmt);
0a122b
+    response = qtest_qmpv(global_qtest, fmt, ap);
0a122b
+    va_end(ap);
0a122b
+    return response;
0a122b
+}
0a122b
+
0a122b
+/**
0a122b
  * qmp_discard_response:
0a122b
  * @fmt...: QMP message to send to qemu
0a122b
  *
0a122b
-- 
0a122b
1.7.11.7
0a122b