Skip to content

Commit

Permalink
qmp-test: Cover syntax and lexical errors
Browse files Browse the repository at this point in the history
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: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20180823164025.12553-7-armbru@redhat.com>
[Commit message typo fixed]
  • Loading branch information
Markus Armbruster committed Aug 24, 2018
1 parent d93bb9d commit aed877c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
17 changes: 17 additions & 0 deletions tests/libqtest.c
Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions tests/libqtest.h
Expand Up @@ -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.
Expand Down
41 changes: 40 additions & 1 deletion tests/qmp-test.c
@@ -1,7 +1,7 @@
/*
* QMP protocol test cases
*
* Copyright (c) 2017 Red Hat Inc.
* Copyright (c) 2017-2018 Red Hat Inc.
*
* Authors:
* Markus Armbruster <armbru@redhat.com>
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit aed877c

Please sign in to comment.