diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-08-25 10:11:54 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-08-25 10:11:54 +0100 |
commit | cc9821fa9ac43728a7ece0a5e42e0147e6aadbf4 (patch) | |
tree | cdeb23078fab646764f9c0ee38bca585d8be0f89 /tests/qmp-test.c | |
parent | e2e6fa67931fdba493e10cc55abcc99a65c92c7b (diff) | |
parent | 37aded92c27d0e56cd27f1c29494fc9f8c873cdd (diff) |
Merge remote-tracking branch 'remotes/armbru/tags/pull-qobject-2018-08-24' into staging
QObject patches for 2018-08-24
# gpg: Signature made Fri 24 Aug 2018 20:28:53 BST
# gpg: using RSA key 3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-qobject-2018-08-24: (58 commits)
json: Update references to RFC 7159 to RFC 8259
json: Support %% in JSON strings when interpolating
json: Improve safety of qobject_from_jsonf_nofail() & friends
json: Keep interpolation state in JSONParserContext
tests/drive_del-test: Fix harmless JSON interpolation bug
json: Clean up headers
qobject: Drop superfluous includes of qemu-common.h
json: Make JSONToken opaque outside json-parser.c
json: Unbox tokens queue in JSONMessageParser
json: Streamline json_message_process_token()
json: Enforce token count and size limits more tightly
qjson: Have qobject_from_json() & friends reject empty and blank
json: Assert json_parser_parse() consumes all tokens on success
json: Fix streamer not to ignore trailing unterminated structures
json: Fix latent parser aborts at end of input
qjson: Fix qobject_from_json() & friends for multiple values
json: Improve names of lexer states related to numbers
json: Replace %I64d, %I64u by %PRId64, %PRIu64
json: Leave rejecting invalid interpolation to parser
json: Pass lexical errors and limit violations to callback
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests/qmp-test.c')
-rw-r--r-- | tests/qmp-test.c | 252 |
1 files changed, 60 insertions, 192 deletions
diff --git a/tests/qmp-test.c b/tests/qmp-test.c index 487ef946ed..4ae2245484 100644 --- a/tests/qmp-test.c +++ b/tests/qmp-test.c @@ -1,10 +1,10 @@ /* * QMP protocol test cases * - * Copyright (c) 2017 Red Hat Inc. + * Copyright (c) 2017-2018 Red Hat Inc. * * Authors: - * Markus Armbruster <armbru@redhat.com>, + * Markus Armbruster <armbru@redhat.com> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -13,13 +13,10 @@ #include "qemu/osdep.h" #include "libqtest.h" #include "qapi/error.h" -#include "qapi/qapi-visit-introspect.h" #include "qapi/qapi-visit-misc.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" #include "qapi/qobject-input-visitor.h" -#include "qapi/util.h" -#include "qapi/visitor.h" #include "qapi/qmp/qstring.h" const char common_args[] = "-nodefaults -machine none"; @@ -45,10 +42,67 @@ static void test_version(QObject *version) visit_free(v); } +static bool recovered(QTestState *qts) +{ + QDict *resp; + bool ret; + + resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }"); + ret = !strcmp(get_error_class(resp), "CommandNotFound"); + qobject_unref(resp); + return ret; +} + static void test_malformed(QTestState *qts) { QDict *resp; + /* syntax error */ + qtest_qmp_send_raw(qts, "{]\n"); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + + /* lexical error: impossible byte outside string */ + qtest_qmp_send_raw(qts, "{\xFF"); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + + /* lexical error: funny control character outside string */ + qtest_qmp_send_raw(qts, "{\x01"); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + + /* lexical error: impossible byte in string */ + qtest_qmp_send_raw(qts, "{'bad \xFF"); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + + /* lexical error: control character in string */ + qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n"); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + + /* lexical error: interpolation */ + qtest_qmp_send_raw(qts, "%%p\n"); + /* two errors, one for "%", one for "p" */ + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + resp = qtest_qmp_receive(qts); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + qobject_unref(resp); + g_assert(recovered(qts)); + /* Not even a dictionary */ resp = qtest_qmp(qts, "null"); g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); @@ -253,184 +307,6 @@ static void test_qmp_oob(void) qtest_quit(qts); } -/* Query smoke tests */ - -static int query_error_class(const char *cmd) -{ - static struct { - const char *cmd; - int err_class; - } fails[] = { - /* Success depends on build configuration: */ -#ifndef CONFIG_SPICE - { "query-spice", ERROR_CLASS_COMMAND_NOT_FOUND }, -#endif -#ifndef CONFIG_VNC - { "query-vnc", ERROR_CLASS_GENERIC_ERROR }, - { "query-vnc-servers", ERROR_CLASS_GENERIC_ERROR }, -#endif -#ifndef CONFIG_REPLICATION - { "query-xen-replication-status", ERROR_CLASS_COMMAND_NOT_FOUND }, -#endif - /* Likewise, and require special QEMU command-line arguments: */ - { "query-acpi-ospm-status", ERROR_CLASS_GENERIC_ERROR }, - { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE }, - { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR }, - { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR }, - { NULL, -1 } - }; - int i; - - for (i = 0; fails[i].cmd; i++) { - if (!strcmp(cmd, fails[i].cmd)) { - return fails[i].err_class; - } - } - return -1; -} - -static void test_query(const void *data) -{ - const char *cmd = data; - int expected_error_class = query_error_class(cmd); - QDict *resp, *error; - const char *error_class; - - qtest_start(common_args); - - resp = qmp("{ 'execute': %s }", cmd); - error = qdict_get_qdict(resp, "error"); - error_class = error ? qdict_get_str(error, "class") : NULL; - - if (expected_error_class < 0) { - g_assert(qdict_haskey(resp, "return")); - } else { - g_assert(error); - g_assert_cmpint(qapi_enum_parse(&QapiErrorClass_lookup, error_class, - -1, &error_abort), - ==, expected_error_class); - } - qobject_unref(resp); - - qtest_end(); -} - -static bool query_is_blacklisted(const char *cmd) -{ - const char *blacklist[] = { - /* Not actually queries: */ - "add-fd", - /* Success depends on target arch: */ - "query-cpu-definitions", /* arm, i386, ppc, s390x */ - "query-gic-capabilities", /* arm */ - /* Success depends on target-specific build configuration: */ - "query-pci", /* CONFIG_PCI */ - /* Success depends on launching SEV guest */ - "query-sev-launch-measure", - /* Success depends on Host or Hypervisor SEV support */ - "query-sev", - "query-sev-capabilities", - NULL - }; - int i; - - for (i = 0; blacklist[i]; i++) { - if (!strcmp(cmd, blacklist[i])) { - return true; - } - } - return false; -} - -typedef struct { - SchemaInfoList *list; - GHashTable *hash; -} QmpSchema; - -static void qmp_schema_init(QmpSchema *schema) -{ - QDict *resp; - Visitor *qiv; - SchemaInfoList *tail; - - qtest_start(common_args); - resp = qmp("{ 'execute': 'query-qmp-schema' }"); - - qiv = qobject_input_visitor_new(qdict_get(resp, "return")); - visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort); - visit_free(qiv); - - qobject_unref(resp); - qtest_end(); - - schema->hash = g_hash_table_new(g_str_hash, g_str_equal); - - /* Build @schema: hash table mapping entity name to SchemaInfo */ - for (tail = schema->list; tail; tail = tail->next) { - g_hash_table_insert(schema->hash, tail->value->name, tail->value); - } -} - -static SchemaInfo *qmp_schema_lookup(QmpSchema *schema, const char *name) -{ - return g_hash_table_lookup(schema->hash, name); -} - -static void qmp_schema_cleanup(QmpSchema *schema) -{ - qapi_free_SchemaInfoList(schema->list); - g_hash_table_destroy(schema->hash); -} - -static bool object_type_has_mandatory_members(SchemaInfo *type) -{ - SchemaInfoObjectMemberList *tail; - - g_assert(type->meta_type == SCHEMA_META_TYPE_OBJECT); - - for (tail = type->u.object.members; tail; tail = tail->next) { - if (!tail->value->has_q_default) { - return true; - } - } - - return false; -} - -static void add_query_tests(QmpSchema *schema) -{ - SchemaInfoList *tail; - SchemaInfo *si, *arg_type, *ret_type; - char *test_name; - - /* Test the query-like commands */ - for (tail = schema->list; tail; tail = tail->next) { - si = tail->value; - if (si->meta_type != SCHEMA_META_TYPE_COMMAND) { - continue; - } - - if (query_is_blacklisted(si->name)) { - continue; - } - - arg_type = qmp_schema_lookup(schema, si->u.command.arg_type); - if (object_type_has_mandatory_members(arg_type)) { - continue; - } - - ret_type = qmp_schema_lookup(schema, si->u.command.ret_type); - if (ret_type->meta_type == SCHEMA_META_TYPE_OBJECT - && !ret_type->u.object.members) { - continue; - } - - test_name = g_strdup_printf("qmp/%s", si->name); - qtest_add_data_func(test_name, si->name, test_query); - g_free(test_name); - } -} - /* Preconfig tests */ static void test_qmp_preconfig(void) @@ -474,19 +350,11 @@ static void test_qmp_preconfig(void) int main(int argc, char *argv[]) { - QmpSchema schema; - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("qmp/protocol", test_qmp_protocol); qtest_add_func("qmp/oob", test_qmp_oob); - qmp_schema_init(&schema); - add_query_tests(&schema); qtest_add_func("qmp/preconfig", test_qmp_preconfig); - ret = g_test_run(); - - qmp_schema_cleanup(&schema); - return ret; + return g_test_run(); } |