 048abb7b20
			
		
	
	
		048abb7b20
		
	
	
	
	
		
			
			The split between tests/test-qobject-input-visitor.c and tests/test-qobject-input-strict.c now makes less sense than ever. The next commit will take care of that. Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-Id: <1488544368-30622-20-git-send-email-armbru@redhat.com>
		
			
				
	
	
		
			140 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * QMP protocol test cases
 | |
|  *
 | |
|  * Copyright (c) 2017 Red Hat Inc.
 | |
|  *
 | |
|  * Authors:
 | |
|  *  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.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "libqtest.h"
 | |
| #include "qapi-visit.h"
 | |
| #include "qapi/error.h"
 | |
| #include "qapi/qobject-input-visitor.h"
 | |
| #include "qapi/visitor.h"
 | |
| 
 | |
| const char common_args[] = "-nodefaults -machine none";
 | |
| 
 | |
| static const char *get_error_class(QDict *resp)
 | |
| {
 | |
|     QDict *error = qdict_get_qdict(resp, "error");
 | |
|     const char *desc = qdict_get_try_str(error, "desc");
 | |
| 
 | |
|     g_assert(desc);
 | |
|     return error ? qdict_get_try_str(error, "class") : NULL;
 | |
| }
 | |
| 
 | |
| static void test_version(QObject *version)
 | |
| {
 | |
|     Visitor *v;
 | |
|     VersionInfo *vinfo;
 | |
| 
 | |
|     g_assert(version);
 | |
|     v = qobject_input_visitor_new(version);
 | |
|     visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
 | |
|     qapi_free_VersionInfo(vinfo);
 | |
|     visit_free(v);
 | |
| }
 | |
| 
 | |
| static void test_malformed(void)
 | |
| {
 | |
|     QDict *resp;
 | |
| 
 | |
|     /* Not even a dictionary */
 | |
|     resp = qmp("null");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* No "execute" key */
 | |
|     resp = qmp("{}");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* "execute" isn't a string */
 | |
|     resp = qmp("{ 'execute': true }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* "arguments" isn't a dictionary */
 | |
|     resp = qmp("{ 'execute': 'no-such-cmd', 'arguments': [] }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* extra key */
 | |
|     resp = qmp("{ 'execute': 'no-such-cmd', 'extra': true }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     QDECREF(resp);
 | |
| }
 | |
| 
 | |
| static void test_qmp_protocol(void)
 | |
| {
 | |
|     QDict *resp, *q, *ret;
 | |
|     QList *capabilities;
 | |
| 
 | |
|     global_qtest = qtest_init_without_qmp_handshake(common_args);
 | |
| 
 | |
|     /* Test greeting */
 | |
|     resp = qmp_receive();
 | |
|     q = qdict_get_qdict(resp, "QMP");
 | |
|     g_assert(q);
 | |
|     test_version(qdict_get(q, "version"));
 | |
|     capabilities = qdict_get_qlist(q, "capabilities");
 | |
|     g_assert(capabilities && qlist_empty(capabilities));
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test valid command before handshake */
 | |
|     resp = qmp("{ 'execute': 'query-version' }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test malformed commands before handshake */
 | |
|     test_malformed();
 | |
| 
 | |
|     /* Test handshake */
 | |
|     resp = qmp("{ 'execute': 'qmp_capabilities' }");
 | |
|     ret = qdict_get_qdict(resp, "return");
 | |
|     g_assert(ret && !qdict_size(ret));
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test repeated handshake */
 | |
|     resp = qmp("{ 'execute': 'qmp_capabilities' }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test valid command */
 | |
|     resp = qmp("{ 'execute': 'query-version' }");
 | |
|     test_version(qdict_get(resp, "return"));
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test malformed commands */
 | |
|     test_malformed();
 | |
| 
 | |
|     /* Test 'id' */
 | |
|     resp = qmp("{ 'execute': 'query-name', 'id': 'cookie#1' }");
 | |
|     ret = qdict_get_qdict(resp, "return");
 | |
|     g_assert(ret);
 | |
|     g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     /* Test command failure with 'id' */
 | |
|     resp = qmp("{ 'execute': 'human-monitor-command', 'id': 2 }");
 | |
|     g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
 | |
|     g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
 | |
|     QDECREF(resp);
 | |
| 
 | |
|     qtest_end();
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
|     g_test_init(&argc, &argv, NULL);
 | |
| 
 | |
|     qtest_add_func("qmp/protocol", test_qmp_protocol);
 | |
| 
 | |
|     return g_test_run();
 | |
| }
 |