qemu/tests/test-qmp-cmds.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "qapi/qmp/qdict.h"
   3#include "qapi/qmp/qjson.h"
   4#include "qapi/qmp/qnum.h"
   5#include "qapi/qmp/qstring.h"
   6#include "qapi/error.h"
   7#include "qapi/qobject-input-visitor.h"
   8#include "tests/test-qapi-types.h"
   9#include "tests/test-qapi-visit.h"
  10#include "test-qapi-commands.h"
  11#include "test-qapi-init-commands.h"
  12
  13static QmpCommandList qmp_commands;
  14
  15#if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD)
  16UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
  17{
  18    return NULL;
  19}
  20#endif
  21
  22UserDefThree *qmp_TestCmdReturnDefThree(Error **errp)
  23{
  24    return NULL;
  25}
  26
  27void qmp_user_def_cmd(Error **errp)
  28{
  29}
  30
  31void qmp_test_flags_command(Error **errp)
  32{
  33}
  34
  35void qmp_cmd_success_response(Error **errp)
  36{
  37}
  38
  39Empty2 *qmp_user_def_cmd0(Error **errp)
  40{
  41    return g_new0(Empty2, 1);
  42}
  43
  44void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
  45{
  46}
  47
  48void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
  49                       FeatureStruct2 *fs2, FeatureStruct3 *fs3,
  50                       FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
  51                       CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
  52                       Error **errp)
  53{
  54}
  55
  56void qmp_test_command_features1(Error **errp)
  57{
  58}
  59
  60void qmp_test_command_features3(Error **errp)
  61{
  62}
  63
  64void qmp_test_command_cond_features1(Error **errp)
  65{
  66}
  67
  68void qmp_test_command_cond_features2(Error **errp)
  69{
  70}
  71
  72void qmp_test_command_cond_features3(Error **errp)
  73{
  74}
  75
  76UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a,
  77                              bool has_udb1, UserDefOne *ud1b,
  78                              Error **errp)
  79{
  80    UserDefTwo *ret;
  81    UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne));
  82    UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));
  83
  84    ud1c->string = strdup(ud1a->string);
  85    ud1c->integer = ud1a->integer;
  86    ud1d->string = strdup(has_udb1 ? ud1b->string : "blah0");
  87    ud1d->integer = has_udb1 ? ud1b->integer : 0;
  88
  89    ret = g_new0(UserDefTwo, 1);
  90    ret->string0 = strdup("blah1");
  91    ret->dict1 = g_new0(UserDefTwoDict, 1);
  92    ret->dict1->string1 = strdup("blah2");
  93    ret->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
  94    ret->dict1->dict2->userdef = ud1c;
  95    ret->dict1->dict2->string = strdup("blah3");
  96    ret->dict1->dict3 = g_new0(UserDefTwoDictDict, 1);
  97    ret->dict1->has_dict3 = true;
  98    ret->dict1->dict3->userdef = ud1d;
  99    ret->dict1->dict3->string = strdup("blah4");
 100
 101    return ret;
 102}
 103
 104int64_t qmp_guest_get_time(int64_t a, bool has_b, int64_t b, Error **errp)
 105{
 106    return a + (has_b ? b : 0);
 107}
 108
 109QObject *qmp_guest_sync(QObject *arg, Error **errp)
 110{
 111    return arg;
 112}
 113
 114void qmp_boxed_struct(UserDefZero *arg, Error **errp)
 115{
 116}
 117
 118void qmp_boxed_union(UserDefListUnion *arg, Error **errp)
 119{
 120}
 121
 122void qmp_boxed_empty(Empty1 *arg, Error **errp)
 123{
 124}
 125
 126__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
 127                                              __org_qemu_x_StructList *b,
 128                                              __org_qemu_x_Union2 *c,
 129                                              __org_qemu_x_Alt *d,
 130                                              Error **errp)
 131{
 132    __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1);
 133
 134    ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
 135    ret->u.__org_qemu_x_branch.data = strdup("blah1");
 136
 137    /* Also test that 'wchar-t' was munged to 'q_wchar_t' */
 138    if (b && b->value && !b->value->has_q_wchar_t) {
 139        b->value->q_wchar_t = 1;
 140    }
 141    return ret;
 142}
 143
 144
 145static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...)
 146{
 147    va_list ap;
 148    QDict *req, *resp;
 149    QObject *ret;
 150
 151    va_start(ap, template);
 152    req = qdict_from_vjsonf_nofail(template, ap);
 153    va_end(ap);
 154
 155    resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
 156    g_assert(resp);
 157    ret = qdict_get(resp, "return");
 158    g_assert(ret);
 159    g_assert(qdict_size(resp) == 1);
 160
 161    qobject_ref(ret);
 162    qobject_unref(resp);
 163    qobject_unref(req);
 164    return ret;
 165}
 166
 167static void do_qmp_dispatch_error(bool allow_oob, ErrorClass cls,
 168                                  const char *template, ...)
 169{
 170    va_list ap;
 171    QDict *req, *resp;
 172    QDict *error;
 173
 174    va_start(ap, template);
 175    req = qdict_from_vjsonf_nofail(template, ap);
 176    va_end(ap);
 177
 178    resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
 179    g_assert(resp);
 180    error = qdict_get_qdict(resp, "error");
 181    g_assert(error);
 182    g_assert_cmpstr(qdict_get_try_str(error, "class"),
 183                    ==, QapiErrorClass_str(cls));
 184    g_assert(qdict_get_try_str(error, "desc"));
 185    g_assert(qdict_size(error) == 2);
 186    g_assert(qdict_size(resp) == 1);
 187
 188    qobject_unref(resp);
 189    qobject_unref(req);
 190}
 191
 192/* test commands with no input and no return value */
 193static void test_dispatch_cmd(void)
 194{
 195    QDict *ret;
 196
 197    ret = qobject_to(QDict,
 198                     do_qmp_dispatch(false,
 199                                     "{ 'execute': 'user_def_cmd' }"));
 200    assert(ret && qdict_size(ret) == 0);
 201    qobject_unref(ret);
 202}
 203
 204static void test_dispatch_cmd_oob(void)
 205{
 206    QDict *ret;
 207
 208    ret = qobject_to(QDict,
 209                     do_qmp_dispatch(true,
 210                                     "{ 'exec-oob': 'test-flags-command' }"));
 211    assert(ret && qdict_size(ret) == 0);
 212    qobject_unref(ret);
 213}
 214
 215/* test commands that return an error due to invalid parameters */
 216static void test_dispatch_cmd_failure(void)
 217{
 218    /* missing arguments */
 219    do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
 220                          "{ 'execute': 'user_def_cmd2' }");
 221
 222    /* extra arguments */
 223    do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
 224                          "{ 'execute': 'user_def_cmd',"
 225                          " 'arguments': { 'a': 66 } }");
 226}
 227
 228static void test_dispatch_cmd_success_response(void)
 229{
 230    QDict *req = qdict_new();
 231    QDict *resp;
 232
 233    qdict_put_str(req, "execute", "cmd-success-response");
 234    resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
 235    g_assert_null(resp);
 236    qobject_unref(req);
 237}
 238
 239/* test commands that involve both input parameters and return values */
 240static void test_dispatch_cmd_io(void)
 241{
 242    QDict *ret, *ret_dict, *ret_dict_dict, *ret_dict_dict_userdef;
 243    QDict *ret_dict_dict2, *ret_dict_dict2_userdef;
 244    QNum *ret3;
 245    int64_t val;
 246
 247    ret = qobject_to(QDict, do_qmp_dispatch(false,
 248        "{ 'execute': 'user_def_cmd2', 'arguments': {"
 249        " 'ud1a': { 'integer': 42, 'string': 'hello' },"
 250        " 'ud1b': { 'integer': 422, 'string': 'hello2' } } }"));
 251
 252    assert(!strcmp(qdict_get_str(ret, "string0"), "blah1"));
 253    ret_dict = qdict_get_qdict(ret, "dict1");
 254    assert(!strcmp(qdict_get_str(ret_dict, "string1"), "blah2"));
 255    ret_dict_dict = qdict_get_qdict(ret_dict, "dict2");
 256    ret_dict_dict_userdef = qdict_get_qdict(ret_dict_dict, "userdef");
 257    assert(qdict_get_int(ret_dict_dict_userdef, "integer") == 42);
 258    assert(!strcmp(qdict_get_str(ret_dict_dict_userdef, "string"), "hello"));
 259    assert(!strcmp(qdict_get_str(ret_dict_dict, "string"), "blah3"));
 260    ret_dict_dict2 = qdict_get_qdict(ret_dict, "dict3");
 261    ret_dict_dict2_userdef = qdict_get_qdict(ret_dict_dict2, "userdef");
 262    assert(qdict_get_int(ret_dict_dict2_userdef, "integer") == 422);
 263    assert(!strcmp(qdict_get_str(ret_dict_dict2_userdef, "string"), "hello2"));
 264    assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4"));
 265    qobject_unref(ret);
 266
 267    ret3 = qobject_to(QNum, do_qmp_dispatch(false,
 268        "{ 'execute': 'guest-get-time', 'arguments': { 'a': 66 } }"));
 269    g_assert(qnum_get_try_int(ret3, &val));
 270    g_assert_cmpint(val, ==, 66);
 271    qobject_unref(ret3);
 272}
 273
 274/* test generated dealloc functions for generated types */
 275static void test_dealloc_types(void)
 276{
 277    UserDefOne *ud1test, *ud1a, *ud1b;
 278    UserDefOneList *ud1list;
 279
 280    ud1test = g_malloc0(sizeof(UserDefOne));
 281    ud1test->integer = 42;
 282    ud1test->string = g_strdup("hi there 42");
 283
 284    qapi_free_UserDefOne(ud1test);
 285
 286    ud1a = g_malloc0(sizeof(UserDefOne));
 287    ud1a->integer = 43;
 288    ud1a->string = g_strdup("hi there 43");
 289
 290    ud1b = g_malloc0(sizeof(UserDefOne));
 291    ud1b->integer = 44;
 292    ud1b->string = g_strdup("hi there 44");
 293
 294    ud1list = g_malloc0(sizeof(UserDefOneList));
 295    ud1list->value = ud1a;
 296    ud1list->next = g_malloc0(sizeof(UserDefOneList));
 297    ud1list->next->value = ud1b;
 298
 299    qapi_free_UserDefOneList(ud1list);
 300}
 301
 302/* test generated deallocation on an object whose construction was prematurely
 303 * terminated due to an error */
 304static void test_dealloc_partial(void)
 305{
 306    static const char text[] = "don't leak me";
 307
 308    UserDefTwo *ud2 = NULL;
 309    Error *err = NULL;
 310
 311    /* create partial object */
 312    {
 313        QDict *ud2_dict;
 314        Visitor *v;
 315
 316        ud2_dict = qdict_new();
 317        qdict_put_str(ud2_dict, "string0", text);
 318
 319        v = qobject_input_visitor_new(QOBJECT(ud2_dict));
 320        visit_type_UserDefTwo(v, NULL, &ud2, &err);
 321        visit_free(v);
 322        qobject_unref(ud2_dict);
 323    }
 324
 325    /* verify that visit_type_XXX() cleans up properly on error */
 326    error_free_or_abort(&err);
 327    assert(!ud2);
 328
 329    /* Manually create a partial object, leaving ud2->dict1 at NULL */
 330    ud2 = g_new0(UserDefTwo, 1);
 331    ud2->string0 = g_strdup(text);
 332
 333    /* tear down partial object */
 334    qapi_free_UserDefTwo(ud2);
 335}
 336
 337
 338int main(int argc, char **argv)
 339{
 340    g_test_init(&argc, &argv, NULL);
 341
 342    g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
 343    g_test_add_func("/qmp/dispatch_cmd_oob", test_dispatch_cmd_oob);
 344    g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
 345    g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
 346    g_test_add_func("/qmp/dispatch_cmd_success_response",
 347                    test_dispatch_cmd_success_response);
 348    g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
 349    g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 350
 351    test_qmp_init_marshal(&qmp_commands);
 352    g_test_run();
 353
 354    return 0;
 355}
 356