Commit aed877c5 authored by Markus Armbruster's avatar Markus Armbruster
Browse files

qmp-test: Cover syntax and lexical errors



qmp-test neglects to cover QMP input that isn't valid JSON.  libqtest
doesn't let us send such input.  Add qtest_qmp_send_raw() for this
purpose, and put it to use in qmp-test.

Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Message-Id: <20180823164025.12553-7-armbru@redhat.com>
[Commit message typo fixed]
parent d93bb9d5
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -604,6 +604,23 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...)
    va_end(ap);
}

void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
{
    bool log = getenv("QTEST_LOG") != NULL;
    va_list ap;
    char *str;

    va_start(ap, fmt);
    str = g_strdup_vprintf(fmt, ap);
    va_end(ap);

    if (log) {
        fprintf(stderr, "%s", str);
    }
    socket_send(s->qmp_fd, str, strlen(str));
    g_free(str);
}

QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
{
    QDict *response;
+11 −0
Original line number Diff line number Diff line
@@ -96,6 +96,17 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
void qtest_qmp_send(QTestState *s, const char *fmt, ...)
    GCC_FMT_ATTR(2, 3);

/**
 * qtest_qmp_send_raw:
 * @s: #QTestState instance to operate on.
 * @fmt...: text to send, formatted like sprintf()
 *
 * Sends text to the QMP monitor verbatim.  Need not be valid JSON;
 * this is useful for negative tests.
 */
void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
    GCC_FMT_ATTR(2, 3);

/**
 * qtest_qmpv:
 * @s: #QTestState instance to operate on.
+40 −1
Original line number Diff line number Diff line
/*
 * QMP protocol test cases
 *
 * Copyright (c) 2017 Red Hat Inc.
 * Copyright (c) 2017-2018 Red Hat Inc.
 *
 * Authors:
 *  Markus Armbruster <armbru@redhat.com>
@@ -42,10 +42,49 @@ 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: 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: interpolation */
    qtest_qmp_send_raw(qts, "%%p\n");
    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");