From nobody Mon Feb 9 02:27:43 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 148854464501237.91007902746094; Fri, 3 Mar 2017 04:37:25 -0800 (PST) Received: from localhost ([::1]:57515 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjmSY-0002EB-Ua for importer@patchew.org; Fri, 03 Mar 2017 07:37:23 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42370) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjmOF-0007uW-2M for qemu-devel@nongnu.org; Fri, 03 Mar 2017 07:32:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cjmOC-0007xX-1Y for qemu-devel@nongnu.org; Fri, 03 Mar 2017 07:32:55 -0500 Received: from mx1.redhat.com ([209.132.183.28]:52884) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cjmOB-0007wo-Pp for qemu-devel@nongnu.org; Fri, 03 Mar 2017 07:32:51 -0500 Received: from smtp.corp.redhat.com (int-mx16.intmail.prod.int.phx2.redhat.com [10.5.11.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 035BD7E9DC for ; Fri, 3 Mar 2017 12:32:52 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 95A1D2D655; Fri, 3 Mar 2017 12:32:51 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 047A21138650; Fri, 3 Mar 2017 13:32:49 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Fri, 3 Mar 2017 13:32:23 +0100 Message-Id: <1488544368-30622-4-git-send-email-armbru@redhat.com> In-Reply-To: <1488544368-30622-1-git-send-email-armbru@redhat.com> References: <1488544368-30622-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.74 on 10.5.11.28 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Fri, 03 Mar 2017 12:32:52 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 03/28] qmp-test: New, covering basic QMP protocol X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- MAINTAINERS | 1 + tests/Makefile.include | 5 +- tests/libqtest.c | 17 ++++-- tests/libqtest.h | 8 +++ tests/qmp-test.c | 139 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 tests/qmp-test.c diff --git a/MAINTAINERS b/MAINTAINERS index be79f68..d0ded4b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1393,6 +1393,7 @@ F: qmp.c F: monitor.c F: docs/*qmp-* F: scripts/qmp/ +F: tests/qmp-test.c T: git git://repo.or.cz/qemu/armbru.git qapi-next =20 Register API diff --git a/tests/Makefile.include b/tests/Makefile.include index 3310c17..4f52239 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -133,7 +133,9 @@ check-block-$(CONFIG_POSIX) +=3D tests/qemu-iotests-qui= ck.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. =20 -check-qtest-generic-y =3D tests/device-introspect-test$(EXESUF) +check-qtest-generic-y =3D tests/qmp-test$(EXESUF) +gcov-files-generic-y =3D monitor.c qapi/qmp-dispatch.c +check-qtest-generic-y +=3D tests/device-introspect-test$(EXESUF) gcov-files-generic-y =3D qdev-monitor.c qmp.c =20 gcov-files-ipack-y +=3D hw/ipack/ipack.c @@ -653,6 +655,7 @@ libqos-imx-obj-y =3D $(libqos-obj-y) tests/libqos/i2c-i= mx.o libqos-usb-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos= /usb.o libqos-virtio-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/lib= qos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/lib= qos/malloc-generic.o =20 +tests/qmp-test$(EXESUF): tests/qmp-test.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o diff --git a/tests/libqtest.c b/tests/libqtest.c index 951a3b4..ca6b641 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -149,7 +149,7 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *d= ata) g_hook_prepend(&abrt_hooks, hook); } =20 -QTestState *qtest_init(const char *extra_args) +QTestState *qtest_init_without_qmp_handshake(const char *extra_args) { QTestState *s; int sock, qmpsock, i; @@ -204,10 +204,6 @@ QTestState *qtest_init(const char *extra_args) s->irq_level[i] =3D false; } =20 - /* Read the QMP greeting and then do the handshake */ - qtest_qmp_discard_response(s, ""); - qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }"); - if (getenv("QTEST_STOP")) { kill(s->qemu_pid, SIGSTOP); } @@ -219,6 +215,17 @@ QTestState *qtest_init(const char *extra_args) return s; } =20 +QTestState *qtest_init(const char *extra_args) +{ + QTestState *s =3D qtest_init_without_qmp_handshake(extra_args); + + /* Read the QMP greeting and then do the handshake */ + qtest_qmp_discard_response(s, ""); + qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }"); + + return s; +} + void qtest_quit(QTestState *s) { qtest_instances =3D g_list_remove(qtest_instances, s); diff --git a/tests/libqtest.h b/tests/libqtest.h index 90f182e..2c9962d 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -32,6 +32,14 @@ extern QTestState *global_qtest; QTestState *qtest_init(const char *extra_args); =20 /** + * qtest_init_without_qmp_handshake: + * @extra_args: other arguments to pass to QEMU. + * + * Returns: #QTestState instance. + */ +QTestState *qtest_init_without_qmp_handshake(const char *extra_args); + +/** * qtest_quit: * @s: #QTestState instance to operate on. * diff --git a/tests/qmp-test.c b/tests/qmp-test.c new file mode 100644 index 0000000..405e49e --- /dev/null +++ b/tests/qmp-test.c @@ -0,0 +1,139 @@ +/* + * QMP protocol test cases + * + * Copyright (c) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster , + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qapi-visit.h" +#include "qapi/error.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/visitor.h" + +const char common_args[] =3D "-nodefaults -machine none"; + +static const char *get_error_class(QDict *resp) +{ + QDict *error =3D qdict_get_qdict(resp, "error"); + const char *desc =3D qdict_get_try_str(error, "desc"); + + g_assert(desc); + return error ? qdict_get_try_str(error, "class") : NULL; +} + +static void test_version(QObject *version) +{ + Visitor *v; + VersionInfo *vinfo; + + g_assert(version); + v =3D qobject_input_visitor_new(version, true); + visit_type_VersionInfo(v, "version", &vinfo, &error_abort); + qapi_free_VersionInfo(vinfo); + visit_free(v); +} + +static void test_malformed(void) +{ + QDict *resp; + + /* Not even a dictionary */ + resp =3D qmp("null"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + QDECREF(resp); + + /* No "execute" key */ + resp =3D qmp("{}"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + QDECREF(resp); + + /* "execute" isn't a string */ + resp =3D qmp("{ 'execute': true }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + QDECREF(resp); + + /* "arguments" isn't a dictionary */ + resp =3D qmp("{ 'execute': 'no-such-cmd', 'arguments': [] }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + QDECREF(resp); + + /* extra key */ + resp =3D qmp("{ 'execute': 'no-such-cmd', 'extra': true }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + QDECREF(resp); +} + +static void test_qmp_protocol(void) +{ + QDict *resp, *q, *ret; + QList *capabilities; + + global_qtest =3D qtest_init_without_qmp_handshake(common_args); + + /* Test greeting */ + resp =3D qmp_receive(); + q =3D qdict_get_qdict(resp, "QMP"); + g_assert(q); + test_version(qdict_get(q, "version")); + capabilities =3D qdict_get_qlist(q, "capabilities"); + g_assert(capabilities && qlist_empty(capabilities)); + QDECREF(resp); + + /* Test valid command before handshake */ + resp =3D qmp("{ 'execute': 'query-version' }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "CommandNotFound"); + QDECREF(resp); + + /* Test malformed commands before handshake */ + test_malformed(); + + /* Test handshake */ + resp =3D qmp("{ 'execute': 'qmp_capabilities' }"); + ret =3D qdict_get_qdict(resp, "return"); + g_assert(ret && !qdict_size(ret)); + QDECREF(resp); + + /* Test repeated handshake */ + resp =3D qmp("{ 'execute': 'qmp_capabilities' }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "CommandNotFound"); + QDECREF(resp); + + /* Test valid command */ + resp =3D qmp("{ 'execute': 'query-version' }"); + test_version(qdict_get(resp, "return")); + QDECREF(resp); + + /* Test malformed commands */ + test_malformed(); + + /* Test 'id' */ + resp =3D qmp("{ 'execute': 'query-name', 'id': 'cookie#1' }"); + ret =3D qdict_get_qdict(resp, "return"); + g_assert(ret); + g_assert_cmpstr(qdict_get_try_str(resp, "id"), =3D=3D, "cookie#1"); + QDECREF(resp); + + /* Test command failure with 'id' */ + resp =3D qmp("{ 'execute': 'human-monitor-command', 'id': 2 }"); + g_assert_cmpstr(get_error_class(resp), =3D=3D, "GenericError"); + g_assert_cmpint(qdict_get_int(resp, "id"), =3D=3D, 2); + QDECREF(resp); + + qtest_end(); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("qmp/protocol", test_qmp_protocol); + + return g_test_run(); +} --=20 2.7.4