diff mbox series

[RFC,v3,27/27] tests: qmp-test: add oob test

Message ID 20171106094643.14881-28-peterx@redhat.com
State New
Headers show
Series [RFC,v3,01/27] char-io: fix possible race on IOWatchPoll | expand

Commit Message

Peter Xu Nov. 6, 2017, 9:46 a.m. UTC
Test the new OOB capability.  Here we used the "dump-guest-memory"
command to hang the thread a bit to test working of OOB preemption.
Note that currently it is only running for x86/arm/ppc/s390x.

Note that for some platforms we may need to specify "-cpu" to make sure
the dump-guest-memory commands can really work.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 tests/qmp-test.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

Comments

Stefan Hajnoczi Nov. 15, 2017, 10:21 a.m. UTC | #1
On Mon, Nov 06, 2017 at 05:46:43PM +0800, Peter Xu wrote:
> +    /*
> +     * Try a time-consuming command, following by a OOB command, make
> +     * sure we get OOB command before the time-consuming one (which is
> +     * run in the parser).
> +     *
> +     * When writting up this test script, the only command that
> +     * support OOB is migrate-incoming.  It's not the best command to
> +     * test OOB but we don't really have a choice here.  We will check
> +     * arriving order but not command errors, which does not really
> +     * matter to us.
> +     */
> +    qmp_async("{ 'execute': 'dump-guest-memory',"
> +              "  'arguments': { 'paging': true, "
> +              "                 'protocol': 'file:/dev/null' }, "
> +              "  'id': 'time-consuming-cmd'}");
> +    qmp_async("{ 'execute': 'migrate-incoming', "
> +              "  'control': { 'run-oob': true }, "
> +              "  'id': 'oob-cmd' }");
> +
> +    /* Ignore all events.  Wait for 2 acks */
> +    while (acks < 2) {
> +        resp = qmp_receive();
> +        if (qdict_haskey(resp, "event")) {
> +            /* Skip possible events */
> +            continue;
> +        }
> +        cmd_id = qdict_get_str(resp, "id");
> +        if (acks == 0) {
> +            /* Need to receive OOB response first */
> +            g_assert_cmpstr(cmd_id, ==, "oob-cmd");
> +        } else if (acks == 1) {
> +            g_assert_cmpstr(cmd_id, ==, "time-consuming-cmd");
> +        }
> +        acks++;
> +    }

This test is non-deterministic.  The dump-guest-memory command could
complete first on a fast machine.

On a slow machine this test might take a long time...

Please introduce a test command that is deterministic.  For example,
when 'x-oob-test' is invoked without 'run-oob': true it waits until
invoked again, this time with 'run-oob': true.

We have similar interfaces in the block layer for controlling the order
in which parallel I/O requests are processed.  This allows test cases to
deterministically take specific code paths.
Peter Xu Nov. 16, 2017, 8:02 a.m. UTC | #2
On Wed, Nov 15, 2017 at 10:21:16AM +0000, Stefan Hajnoczi wrote:
> On Mon, Nov 06, 2017 at 05:46:43PM +0800, Peter Xu wrote:
> > +    /*
> > +     * Try a time-consuming command, following by a OOB command, make
> > +     * sure we get OOB command before the time-consuming one (which is
> > +     * run in the parser).
> > +     *
> > +     * When writting up this test script, the only command that
> > +     * support OOB is migrate-incoming.  It's not the best command to
> > +     * test OOB but we don't really have a choice here.  We will check
> > +     * arriving order but not command errors, which does not really
> > +     * matter to us.
> > +     */
> > +    qmp_async("{ 'execute': 'dump-guest-memory',"
> > +              "  'arguments': { 'paging': true, "
> > +              "                 'protocol': 'file:/dev/null' }, "
> > +              "  'id': 'time-consuming-cmd'}");
> > +    qmp_async("{ 'execute': 'migrate-incoming', "
> > +              "  'control': { 'run-oob': true }, "
> > +              "  'id': 'oob-cmd' }");
> > +
> > +    /* Ignore all events.  Wait for 2 acks */
> > +    while (acks < 2) {
> > +        resp = qmp_receive();
> > +        if (qdict_haskey(resp, "event")) {
> > +            /* Skip possible events */
> > +            continue;
> > +        }
> > +        cmd_id = qdict_get_str(resp, "id");
> > +        if (acks == 0) {
> > +            /* Need to receive OOB response first */
> > +            g_assert_cmpstr(cmd_id, ==, "oob-cmd");
> > +        } else if (acks == 1) {
> > +            g_assert_cmpstr(cmd_id, ==, "time-consuming-cmd");
> > +        }
> > +        acks++;
> > +    }
> 
> This test is non-deterministic.  The dump-guest-memory command could
> complete first on a fast machine.
> 
> On a slow machine this test might take a long time...
> 
> Please introduce a test command that is deterministic.  For example,
> when 'x-oob-test' is invoked without 'run-oob': true it waits until
> invoked again, this time with 'run-oob': true.

Yes this sounds good.

> 
> We have similar interfaces in the block layer for controlling the order
> in which parallel I/O requests are processed.  This allows test cases to
> deterministically take specific code paths.

It's great to know that I can create a command to test it.  That
should be much easier.  Thanks,
diff mbox series

Patch

diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 729ec59b0a..7c1b9f9b9e 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -157,6 +157,98 @@  static void test_qmp_protocol(void)
     qtest_end();
 }
 
+/* Tests for Out-Of-Band support. */
+static void test_qmp_oob(void)
+{
+    QDict *resp;
+    int acks = 0;
+    char *qtest_params;
+    const char *cmd_id, *extra_params;
+    const char *arch = qtest_get_arch();
+
+    /*
+     * Some archs need to specify cpu to make sure dump-guest-memory
+     * can work.  I chose CPU type randomly.
+     */
+    if (g_strcmp0(arch, "aarch64") == 0) {
+        extra_params = "-cpu cortex-a57";
+    } else if (g_strcmp0(arch, "ppc64") == 0) {
+        extra_params = "-cpu power8";
+    } else {
+        extra_params = "";
+    }
+
+    /*
+     * Let's have some memory to make sure dump-guest-memory will be
+     * time consuming.  That is required to test OOB functionaility.
+     */
+    qtest_params = g_strdup_printf("-nodefaults -machine none -m 1G %s",
+                                   extra_params);
+    global_qtest = qtest_init_without_qmp_handshake(qtest_params);
+    g_free(qtest_params);
+
+    /* Ignore the greeting message. */
+    resp = qmp_receive();
+    g_assert(qdict_get_qdict(resp, "QMP"));
+    QDECREF(resp);
+
+    /* Try a fake capability, it should fail. */
+    resp = qmp("{ 'execute': 'qmp_capabilities', "
+               "  'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
+    g_assert(qdict_haskey(resp, "error"));
+
+    /* Now, enable OOB in current QMP session, it should success. */
+    resp = qmp("{ 'execute': 'qmp_capabilities', "
+               "  'arguments': { 'enable': [ 'oob' ] } }");
+    g_assert(qdict_haskey(resp, "return"));
+
+    /*
+     * Try any command that does not support OOB but with OOB flag. We
+     * should get failure.
+     */
+    resp = qmp("{ 'execute': 'query-cpus',"
+               "  'control': { 'run-oob': true } }");
+    g_assert(qdict_haskey(resp, "error"));
+
+    /*
+     * Try a time-consuming command, following by a OOB command, make
+     * sure we get OOB command before the time-consuming one (which is
+     * run in the parser).
+     *
+     * When writting up this test script, the only command that
+     * support OOB is migrate-incoming.  It's not the best command to
+     * test OOB but we don't really have a choice here.  We will check
+     * arriving order but not command errors, which does not really
+     * matter to us.
+     */
+    qmp_async("{ 'execute': 'dump-guest-memory',"
+              "  'arguments': { 'paging': true, "
+              "                 'protocol': 'file:/dev/null' }, "
+              "  'id': 'time-consuming-cmd'}");
+    qmp_async("{ 'execute': 'migrate-incoming', "
+              "  'control': { 'run-oob': true }, "
+              "  'id': 'oob-cmd' }");
+
+    /* Ignore all events.  Wait for 2 acks */
+    while (acks < 2) {
+        resp = qmp_receive();
+        if (qdict_haskey(resp, "event")) {
+            /* Skip possible events */
+            continue;
+        }
+        cmd_id = qdict_get_str(resp, "id");
+        if (acks == 0) {
+            /* Need to receive OOB response first */
+            g_assert_cmpstr(cmd_id, ==, "oob-cmd");
+        } else if (acks == 1) {
+            g_assert_cmpstr(cmd_id, ==, "time-consuming-cmd");
+        }
+        acks++;
+    }
+
+    qtest_end();
+}
+
 static int query_error_class(const char *cmd)
 {
     static struct {
@@ -335,6 +427,7 @@  int main(int argc, char *argv[])
     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);