aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/qapi-schema/qapi-schema-test.json2
-rw-r--r--tests/qmp-test.c107
-rw-r--r--tests/test-qga.c34
-rw-r--r--tests/test-qmp-cmds.c23
4 files changed, 119 insertions, 47 deletions
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 16209b57b3..11aa4c8f8d 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -144,7 +144,7 @@
{ 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' }
{ 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true }
-# Smoke test on Out-Of-Band and allow-preconfig-test
+# Smoke test on out-of-band and allow-preconfig-test
{ 'command': 'test-flags-command', 'allow-oob': true, 'allow-preconfig': true }
# For testing integer range flattening in opts-visitor. The following schema
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index a49cbc6fde..ceaf4a6789 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -135,16 +135,65 @@ static void test_qmp_protocol(void)
qtest_quit(qts);
}
-/* Tests for Out-Of-Band support. */
+/* Out-of-band tests */
+
+char tmpdir[] = "/tmp/qmp-test-XXXXXX";
+char *fifo_name;
+
+static void setup_blocking_cmd(void)
+{
+ if (!mkdtemp(tmpdir)) {
+ g_error("mkdtemp: %s", strerror(errno));
+ }
+ fifo_name = g_strdup_printf("%s/fifo", tmpdir);
+ if (mkfifo(fifo_name, 0666)) {
+ g_error("mkfifo: %s", strerror(errno));
+ }
+}
+
+static void cleanup_blocking_cmd(void)
+{
+ unlink(fifo_name);
+ rmdir(tmpdir);
+}
+
+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);
+}
+
+static void unblock_blocked_cmd(void)
+{
+ int fd = open(fifo_name, O_WRONLY);
+ g_assert(fd >= 0);
+ close(fd);
+}
+
+static void send_oob_cmd_that_fails(QTestState *s, const char *id)
+{
+ qtest_async_qmp(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
+}
+
+static void recv_cmd_id(QTestState *s, const char *id)
+{
+ QDict *resp = qtest_qmp_receive(s);
+
+ g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
+ qobject_unref(resp);
+}
+
static void test_qmp_oob(void)
{
QTestState *qts;
QDict *resp, *q;
- int acks = 0;
const QListEntry *entry;
QList *capabilities;
QString *qstr;
- const char *cmd_id;
qts = qtest_init_without_qmp_handshake(true, common_args);
@@ -179,43 +228,33 @@ static void test_qmp_oob(void)
* Try any command that does not support OOB but with OOB flag. We
* should get failure.
*/
- resp = qtest_qmp(qts,
- "{ 'execute': 'query-cpus',"
- " 'control': { 'run-oob': true } }");
+ resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
g_assert(qdict_haskey(resp, "error"));
qobject_unref(resp);
- /*
- * First send the "x-oob-test" command with lock=true and
- * oob=false, it should hang the dispatcher and main thread;
- * later, we send another lock=false with oob=true to continue
- * that thread processing. Finally we should receive replies from
- * both commands.
- */
- qtest_async_qmp(qts,
- "{ 'execute': 'x-oob-test',"
- " 'arguments': { 'lock': true }, "
- " 'id': 'lock-cmd'}");
- qtest_async_qmp(qts,
- "{ 'execute': 'x-oob-test', "
- " 'arguments': { 'lock': false }, "
- " 'control': { 'run-oob': true }, "
- " 'id': 'unlock-cmd' }");
-
- /* Ignore all events. Wait for 2 acks */
- while (acks < 2) {
- resp = qtest_qmp_receive(qts);
- cmd_id = qdict_get_str(resp, "id");
- if (!g_strcmp0(cmd_id, "lock-cmd") ||
- !g_strcmp0(cmd_id, "unlock-cmd")) {
- acks++;
- }
- qobject_unref(resp);
- }
+ /* 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' }");
+ send_oob_cmd_that_fails(qts, "oob-1");
+ recv_cmd_id(qts, "oob-1");
+ unblock_blocked_cmd();
+ recv_cmd_id(qts, "ib-blocks-1");
+ recv_cmd_id(qts, "ib-quick-1");
+
+ /* Even malformed in-band command fails in-band */
+ send_cmd_that_blocks(qts, "blocks-2");
+ qtest_async_qmp(qts, "{ 'id': 'err-2' }");
+ unblock_blocked_cmd();
+ recv_cmd_id(qts, "blocks-2");
+ recv_cmd_id(qts, "err-2");
+ cleanup_blocking_cmd();
qtest_quit(qts);
}
+/* Query smoke tests */
+
static int query_error_class(const char *cmd)
{
static struct {
@@ -392,6 +431,8 @@ static void add_query_tests(QmpSchema *schema)
}
}
+/* Preconfig tests */
+
static void test_qmp_preconfig(void)
{
QDict *rsp, *ret;
diff --git a/tests/test-qga.c b/tests/test-qga.c
index 350f27812a..d638b1571a 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -227,6 +227,38 @@ static void test_qga_ping(gconstpointer fix)
qobject_unref(ret);
}
+static void test_qga_invalid_id(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *error;
+ const char *class;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
+ g_assert_nonnull(ret);
+
+ error = qdict_get_qdict(ret, "error");
+ class = qdict_get_try_str(error, "class");
+ g_assert_cmpstr(class, ==, "GenericError");
+
+ qobject_unref(ret);
+}
+
+static void test_qga_invalid_oob(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *error;
+ const char *class;
+
+ ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}");
+ g_assert_nonnull(ret);
+
+ error = qdict_get_qdict(ret, "error");
+ class = qdict_get_try_str(error, "class");
+ g_assert_cmpstr(class, ==, "GenericError");
+
+ qobject_unref(ret);
+}
+
static void test_qga_invalid_args(gconstpointer fix)
{
const TestFixture *fixture = fix;
@@ -982,6 +1014,8 @@ int main(int argc, char **argv)
g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
+ g_test_add_data_func("/qga/invalid-id", &fix, test_qga_invalid_id);
+ g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob);
g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args);
g_test_add_data_func("/qga/fsfreeze-status", &fix,
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index ce277c9c3b..ba41a6161e 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -110,13 +110,13 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
static void test_dispatch_cmd(void)
{
QDict *req = qdict_new();
- QObject *resp;
+ QDict *resp;
qdict_put_str(req, "execute", "user_def_cmd");
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
assert(resp != NULL);
- assert(!qdict_haskey(qobject_to(QDict, resp), "error"));
+ assert(!qdict_haskey(resp, "error"));
qobject_unref(resp);
qobject_unref(req);
@@ -127,13 +127,13 @@ static void test_dispatch_cmd_failure(void)
{
QDict *req = qdict_new();
QDict *args = qdict_new();
- QObject *resp;
+ QDict *resp;
qdict_put_str(req, "execute", "user_def_cmd2");
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
assert(resp != NULL);
- assert(qdict_haskey(qobject_to(QDict, resp), "error"));
+ assert(qdict_haskey(resp, "error"));
qobject_unref(resp);
qobject_unref(req);
@@ -145,9 +145,9 @@ static void test_dispatch_cmd_failure(void)
qdict_put_str(req, "execute", "user_def_cmd");
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
assert(resp != NULL);
- assert(qdict_haskey(qobject_to(QDict, resp), "error"));
+ assert(qdict_haskey(resp, "error"));
qobject_unref(resp);
qobject_unref(req);
@@ -155,18 +155,15 @@ static void test_dispatch_cmd_failure(void)
static QObject *test_qmp_dispatch(QDict *req)
{
- QObject *resp_obj;
QDict *resp;
QObject *ret;
- resp_obj = qmp_dispatch(&qmp_commands, QOBJECT(req));
- assert(resp_obj);
- resp = qobject_to(QDict, resp_obj);
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
assert(resp && !qdict_haskey(resp, "error"));
ret = qdict_get(resp, "return");
assert(ret);
qobject_ref(ret);
- qobject_unref(resp_obj);
+ qobject_unref(resp);
return ret;
}