qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-qmp-cmds.c (12573B)


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