qemu/tests/test-qga.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include <locale.h>
   3#include <glib/gstdio.h>
   4#include <sys/socket.h>
   5#include <sys/un.h>
   6
   7#include "libqtest.h"
   8
   9typedef struct {
  10    char *test_dir;
  11    GMainLoop *loop;
  12    int fd;
  13    GPid pid;
  14} TestFixture;
  15
  16static int connect_qga(char *path)
  17{
  18    int s, ret, len, i = 0;
  19    struct sockaddr_un remote;
  20
  21    s = socket(AF_UNIX, SOCK_STREAM, 0);
  22    g_assert(s != -1);
  23
  24    remote.sun_family = AF_UNIX;
  25    do {
  26        strcpy(remote.sun_path, path);
  27        len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  28        ret = connect(s, (struct sockaddr *)&remote, len);
  29        if (ret == -1) {
  30            g_usleep(G_USEC_PER_SEC);
  31        }
  32        if (i++ == 10) {
  33            return -1;
  34        }
  35    } while (ret == -1);
  36
  37    return s;
  38}
  39
  40static void qga_watch(GPid pid, gint status, gpointer user_data)
  41{
  42    TestFixture *fixture = user_data;
  43
  44    g_assert_cmpint(status, ==, 0);
  45    g_main_loop_quit(fixture->loop);
  46}
  47
  48static void
  49fixture_setup(TestFixture *fixture, gconstpointer data)
  50{
  51    const gchar *extra_arg = data;
  52    GError *error = NULL;
  53    gchar *cwd, *path, *cmd, **argv = NULL;
  54
  55    fixture->loop = g_main_loop_new(NULL, FALSE);
  56
  57    fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
  58    g_assert_nonnull(mkdtemp(fixture->test_dir));
  59
  60    path = g_build_filename(fixture->test_dir, "sock", NULL);
  61    cwd = g_get_current_dir();
  62    cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s",
  63                          cwd, G_DIR_SEPARATOR,
  64                          fixture->test_dir, path,
  65                          getenv("QTEST_LOG") ? "-v" : "",
  66                          extra_arg ?: "");
  67    g_shell_parse_argv(cmd, NULL, &argv, &error);
  68    g_assert_no_error(error);
  69
  70    g_spawn_async(fixture->test_dir, argv, NULL,
  71                  G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
  72                  NULL, NULL, &fixture->pid, &error);
  73    g_assert_no_error(error);
  74
  75    g_child_watch_add(fixture->pid, qga_watch, fixture);
  76
  77    fixture->fd = connect_qga(path);
  78    g_assert_cmpint(fixture->fd, !=, -1);
  79
  80    g_strfreev(argv);
  81    g_free(cmd);
  82    g_free(cwd);
  83    g_free(path);
  84}
  85
  86static void
  87fixture_tear_down(TestFixture *fixture, gconstpointer data)
  88{
  89    gchar *tmp;
  90
  91    kill(fixture->pid, SIGTERM);
  92
  93    g_main_loop_run(fixture->loop);
  94    g_main_loop_unref(fixture->loop);
  95
  96    g_spawn_close_pid(fixture->pid);
  97
  98    tmp = g_build_filename(fixture->test_dir, "foo", NULL);
  99    g_unlink(tmp);
 100    g_free(tmp);
 101
 102    tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
 103    g_unlink(tmp);
 104    g_free(tmp);
 105
 106    tmp = g_build_filename(fixture->test_dir, "sock", NULL);
 107    g_unlink(tmp);
 108    g_free(tmp);
 109
 110    g_rmdir(fixture->test_dir);
 111    g_free(fixture->test_dir);
 112}
 113
 114static void qmp_assertion_message_error(const char     *domain,
 115                                        const char     *file,
 116                                        int             line,
 117                                        const char     *func,
 118                                        const char     *expr,
 119                                        QDict          *dict)
 120{
 121    const char *class, *desc;
 122    char *s;
 123    QDict *error;
 124
 125    error = qdict_get_qdict(dict, "error");
 126    class = qdict_get_try_str(error, "class");
 127    desc = qdict_get_try_str(error, "desc");
 128
 129    s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
 130    g_assertion_message(domain, file, line, func, s);
 131    g_free(s);
 132}
 133
 134#define qmp_assert_no_error(err) do {                                   \
 135    if (qdict_haskey(err, "error")) {                                   \
 136        qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
 137                                    G_STRFUNC, #err, err);              \
 138    }                                                                   \
 139} while (0)
 140
 141static void test_qga_sync_delimited(gconstpointer fix)
 142{
 143    const TestFixture *fixture = fix;
 144    guint32 v, r = g_random_int();
 145    unsigned char c;
 146    QDict *ret;
 147    gchar *cmd;
 148
 149    cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited',"
 150                          " 'arguments': {'id': %u } }", 0xff, r);
 151    qmp_fd_send(fixture->fd, cmd);
 152    g_free(cmd);
 153
 154    v = read(fixture->fd, &c, 1);
 155    g_assert_cmpint(v, ==, 1);
 156    g_assert_cmpint(c, ==, 0xff);
 157
 158    ret = qmp_fd_receive(fixture->fd);
 159    g_assert_nonnull(ret);
 160    qmp_assert_no_error(ret);
 161
 162    v = qdict_get_int(ret, "return");
 163    g_assert_cmpint(r, ==, v);
 164
 165    QDECREF(ret);
 166}
 167
 168static void test_qga_sync(gconstpointer fix)
 169{
 170    const TestFixture *fixture = fix;
 171    guint32 v, r = g_random_int();
 172    QDict *ret;
 173    gchar *cmd;
 174
 175    cmd = g_strdup_printf("%c{'execute': 'guest-sync',"
 176                          " 'arguments': {'id': %u } }", 0xff, r);
 177    ret = qmp_fd(fixture->fd, cmd);
 178    g_free(cmd);
 179
 180    g_assert_nonnull(ret);
 181    qmp_assert_no_error(ret);
 182
 183    v = qdict_get_int(ret, "return");
 184    g_assert_cmpint(r, ==, v);
 185
 186    QDECREF(ret);
 187}
 188
 189static void test_qga_ping(gconstpointer fix)
 190{
 191    const TestFixture *fixture = fix;
 192    QDict *ret;
 193
 194    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
 195    g_assert_nonnull(ret);
 196    qmp_assert_no_error(ret);
 197
 198    QDECREF(ret);
 199}
 200
 201static void test_qga_invalid_cmd(gconstpointer fix)
 202{
 203    const TestFixture *fixture = fix;
 204    QDict *ret, *error;
 205    const gchar *class, *desc;
 206
 207    ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
 208    g_assert_nonnull(ret);
 209
 210    error = qdict_get_qdict(ret, "error");
 211    class = qdict_get_try_str(error, "class");
 212    desc = qdict_get_try_str(error, "desc");
 213
 214    g_assert_cmpstr(class, ==, "CommandNotFound");
 215    g_assert_cmpint(strlen(desc), >, 0);
 216
 217    QDECREF(ret);
 218}
 219
 220static void test_qga_info(gconstpointer fix)
 221{
 222    const TestFixture *fixture = fix;
 223    QDict *ret, *val;
 224    const gchar *version;
 225
 226    ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
 227    g_assert_nonnull(ret);
 228    qmp_assert_no_error(ret);
 229
 230    val = qdict_get_qdict(ret, "return");
 231    version = qdict_get_try_str(val, "version");
 232    g_assert_cmpstr(version, ==, QEMU_VERSION);
 233
 234    QDECREF(ret);
 235}
 236
 237static void test_qga_get_vcpus(gconstpointer fix)
 238{
 239    const TestFixture *fixture = fix;
 240    QDict *ret;
 241    QList *list;
 242    const QListEntry *entry;
 243
 244    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
 245    g_assert_nonnull(ret);
 246    qmp_assert_no_error(ret);
 247
 248    /* check there is at least a cpu */
 249    list = qdict_get_qlist(ret, "return");
 250    entry = qlist_first(list);
 251    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
 252    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id"));
 253
 254    QDECREF(ret);
 255}
 256
 257static void test_qga_get_fsinfo(gconstpointer fix)
 258{
 259    const TestFixture *fixture = fix;
 260    QDict *ret;
 261    QList *list;
 262    const QListEntry *entry;
 263
 264    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
 265    g_assert_nonnull(ret);
 266    qmp_assert_no_error(ret);
 267
 268    /* sanity-check the response if there are any filesystems */
 269    list = qdict_get_qlist(ret, "return");
 270    entry = qlist_first(list);
 271    if (entry) {
 272        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
 273        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint"));
 274        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type"));
 275        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk"));
 276    }
 277
 278    QDECREF(ret);
 279}
 280
 281static void test_qga_get_memory_block_info(gconstpointer fix)
 282{
 283    const TestFixture *fixture = fix;
 284    QDict *ret, *val;
 285    int64_t size;
 286
 287    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
 288    g_assert_nonnull(ret);
 289
 290    /* some systems might not expose memory block info in sysfs */
 291    if (!qdict_haskey(ret, "error")) {
 292        /* check there is at least some memory */
 293        val = qdict_get_qdict(ret, "return");
 294        size = qdict_get_int(val, "size");
 295        g_assert_cmpint(size, >, 0);
 296    }
 297
 298    QDECREF(ret);
 299}
 300
 301static void test_qga_get_memory_blocks(gconstpointer fix)
 302{
 303    const TestFixture *fixture = fix;
 304    QDict *ret;
 305    QList *list;
 306    const QListEntry *entry;
 307
 308    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
 309    g_assert_nonnull(ret);
 310
 311    /* some systems might not expose memory block info in sysfs */
 312    if (!qdict_haskey(ret, "error")) {
 313        list = qdict_get_qlist(ret, "return");
 314        entry = qlist_first(list);
 315        /* newer versions of qga may return empty list without error */
 316        if (entry) {
 317            g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index"));
 318            g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
 319        }
 320    }
 321
 322    QDECREF(ret);
 323}
 324
 325static void test_qga_network_get_interfaces(gconstpointer fix)
 326{
 327    const TestFixture *fixture = fix;
 328    QDict *ret;
 329    QList *list;
 330    const QListEntry *entry;
 331
 332    ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
 333    g_assert_nonnull(ret);
 334    qmp_assert_no_error(ret);
 335
 336    /* check there is at least an interface */
 337    list = qdict_get_qlist(ret, "return");
 338    entry = qlist_first(list);
 339    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
 340
 341    QDECREF(ret);
 342}
 343
 344static void test_qga_file_ops(gconstpointer fix)
 345{
 346    const TestFixture *fixture = fix;
 347    const unsigned char helloworld[] = "Hello World!\n";
 348    const char *b64;
 349    gchar *cmd, *path, *enc;
 350    unsigned char *dec;
 351    QDict *ret, *val;
 352    int64_t id, eof;
 353    gsize count;
 354    FILE *f;
 355    char tmp[100];
 356
 357    /* open */
 358    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 359                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
 360    g_assert_nonnull(ret);
 361    qmp_assert_no_error(ret);
 362    id = qdict_get_int(ret, "return");
 363    QDECREF(ret);
 364
 365    enc = g_base64_encode(helloworld, sizeof(helloworld));
 366    /* write */
 367    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
 368                          " 'arguments': { 'handle': %" PRId64 ","
 369                          " 'buf-b64': '%s' } }", id, enc);
 370    ret = qmp_fd(fixture->fd, cmd);
 371    g_assert_nonnull(ret);
 372    qmp_assert_no_error(ret);
 373
 374    val = qdict_get_qdict(ret, "return");
 375    count = qdict_get_int(val, "count");
 376    eof = qdict_get_bool(val, "eof");
 377    g_assert_cmpint(count, ==, sizeof(helloworld));
 378    g_assert_cmpint(eof, ==, 0);
 379    QDECREF(ret);
 380    g_free(cmd);
 381
 382    /* flush */
 383    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
 384                          " 'arguments': {'handle': %" PRId64 "} }",
 385                          id);
 386    ret = qmp_fd(fixture->fd, cmd);
 387    QDECREF(ret);
 388    g_free(cmd);
 389
 390    /* close */
 391    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 392                          " 'arguments': {'handle': %" PRId64 "} }",
 393                          id);
 394    ret = qmp_fd(fixture->fd, cmd);
 395    QDECREF(ret);
 396    g_free(cmd);
 397
 398    /* check content */
 399    path = g_build_filename(fixture->test_dir, "foo", NULL);
 400    f = fopen(path, "r");
 401    g_assert_nonnull(f);
 402    count = fread(tmp, 1, sizeof(tmp), f);
 403    g_assert_cmpint(count, ==, sizeof(helloworld));
 404    tmp[count] = 0;
 405    g_assert_cmpstr(tmp, ==, (char *)helloworld);
 406    fclose(f);
 407
 408    /* open */
 409    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 410                 " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
 411    g_assert_nonnull(ret);
 412    qmp_assert_no_error(ret);
 413    id = qdict_get_int(ret, "return");
 414    QDECREF(ret);
 415
 416    /* read */
 417    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 418                          " 'arguments': { 'handle': %" PRId64 "} }",
 419                          id);
 420    ret = qmp_fd(fixture->fd, cmd);
 421    val = qdict_get_qdict(ret, "return");
 422    count = qdict_get_int(val, "count");
 423    eof = qdict_get_bool(val, "eof");
 424    b64 = qdict_get_str(val, "buf-b64");
 425    g_assert_cmpint(count, ==, sizeof(helloworld));
 426    g_assert(eof);
 427    g_assert_cmpstr(b64, ==, enc);
 428
 429    QDECREF(ret);
 430    g_free(cmd);
 431    g_free(enc);
 432
 433    /* read eof */
 434    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 435                          " 'arguments': { 'handle': %" PRId64 "} }",
 436                          id);
 437    ret = qmp_fd(fixture->fd, cmd);
 438    val = qdict_get_qdict(ret, "return");
 439    count = qdict_get_int(val, "count");
 440    eof = qdict_get_bool(val, "eof");
 441    b64 = qdict_get_str(val, "buf-b64");
 442    g_assert_cmpint(count, ==, 0);
 443    g_assert(eof);
 444    g_assert_cmpstr(b64, ==, "");
 445    QDECREF(ret);
 446    g_free(cmd);
 447
 448    /* seek */
 449    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
 450                          " 'arguments': { 'handle': %" PRId64 ", "
 451                          " 'offset': %d, 'whence': '%s' } }",
 452                          id, 6, "set");
 453    ret = qmp_fd(fixture->fd, cmd);
 454    qmp_assert_no_error(ret);
 455    val = qdict_get_qdict(ret, "return");
 456    count = qdict_get_int(val, "position");
 457    eof = qdict_get_bool(val, "eof");
 458    g_assert_cmpint(count, ==, 6);
 459    g_assert(!eof);
 460    QDECREF(ret);
 461    g_free(cmd);
 462
 463    /* partial read */
 464    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 465                          " 'arguments': { 'handle': %" PRId64 "} }",
 466                          id);
 467    ret = qmp_fd(fixture->fd, cmd);
 468    val = qdict_get_qdict(ret, "return");
 469    count = qdict_get_int(val, "count");
 470    eof = qdict_get_bool(val, "eof");
 471    b64 = qdict_get_str(val, "buf-b64");
 472    g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
 473    g_assert(eof);
 474    dec = g_base64_decode(b64, &count);
 475    g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
 476    g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6);
 477    g_free(dec);
 478
 479    QDECREF(ret);
 480    g_free(cmd);
 481
 482    /* close */
 483    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 484                          " 'arguments': {'handle': %" PRId64 "} }",
 485                          id);
 486    ret = qmp_fd(fixture->fd, cmd);
 487    QDECREF(ret);
 488    g_free(cmd);
 489}
 490
 491static void test_qga_file_write_read(gconstpointer fix)
 492{
 493    const TestFixture *fixture = fix;
 494    const unsigned char helloworld[] = "Hello World!\n";
 495    const char *b64;
 496    gchar *cmd, *enc;
 497    QDict *ret, *val;
 498    int64_t id, eof;
 499    gsize count;
 500
 501    /* open */
 502    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 503                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
 504    g_assert_nonnull(ret);
 505    qmp_assert_no_error(ret);
 506    id = qdict_get_int(ret, "return");
 507    QDECREF(ret);
 508
 509    enc = g_base64_encode(helloworld, sizeof(helloworld));
 510    /* write */
 511    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
 512                          " 'arguments': { 'handle': %" PRId64 ","
 513                          " 'buf-b64': '%s' } }", id, enc);
 514    ret = qmp_fd(fixture->fd, cmd);
 515    g_assert_nonnull(ret);
 516    qmp_assert_no_error(ret);
 517
 518    val = qdict_get_qdict(ret, "return");
 519    count = qdict_get_int(val, "count");
 520    eof = qdict_get_bool(val, "eof");
 521    g_assert_cmpint(count, ==, sizeof(helloworld));
 522    g_assert_cmpint(eof, ==, 0);
 523    QDECREF(ret);
 524    g_free(cmd);
 525
 526    /* read (check implicit flush) */
 527    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 528                          " 'arguments': { 'handle': %" PRId64 "} }",
 529                          id);
 530    ret = qmp_fd(fixture->fd, cmd);
 531    val = qdict_get_qdict(ret, "return");
 532    count = qdict_get_int(val, "count");
 533    eof = qdict_get_bool(val, "eof");
 534    b64 = qdict_get_str(val, "buf-b64");
 535    g_assert_cmpint(count, ==, 0);
 536    g_assert(eof);
 537    g_assert_cmpstr(b64, ==, "");
 538    QDECREF(ret);
 539    g_free(cmd);
 540
 541    /* seek to 0 */
 542    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
 543                          " 'arguments': { 'handle': %" PRId64 ", "
 544                          " 'offset': %d, 'whence': '%s' } }",
 545                          id, 0, "set");
 546    ret = qmp_fd(fixture->fd, cmd);
 547    qmp_assert_no_error(ret);
 548    val = qdict_get_qdict(ret, "return");
 549    count = qdict_get_int(val, "position");
 550    eof = qdict_get_bool(val, "eof");
 551    g_assert_cmpint(count, ==, 0);
 552    g_assert(!eof);
 553    QDECREF(ret);
 554    g_free(cmd);
 555
 556    /* read */
 557    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 558                          " 'arguments': { 'handle': %" PRId64 "} }",
 559                          id);
 560    ret = qmp_fd(fixture->fd, cmd);
 561    val = qdict_get_qdict(ret, "return");
 562    count = qdict_get_int(val, "count");
 563    eof = qdict_get_bool(val, "eof");
 564    b64 = qdict_get_str(val, "buf-b64");
 565    g_assert_cmpint(count, ==, sizeof(helloworld));
 566    g_assert(eof);
 567    g_assert_cmpstr(b64, ==, enc);
 568    QDECREF(ret);
 569    g_free(cmd);
 570    g_free(enc);
 571
 572    /* close */
 573    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 574                          " 'arguments': {'handle': %" PRId64 "} }",
 575                          id);
 576    ret = qmp_fd(fixture->fd, cmd);
 577    QDECREF(ret);
 578    g_free(cmd);
 579}
 580
 581static void test_qga_get_time(gconstpointer fix)
 582{
 583    const TestFixture *fixture = fix;
 584    QDict *ret;
 585    int64_t time;
 586
 587    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
 588    g_assert_nonnull(ret);
 589    qmp_assert_no_error(ret);
 590
 591    time = qdict_get_int(ret, "return");
 592    g_assert_cmpint(time, >, 0);
 593
 594    QDECREF(ret);
 595}
 596
 597static void test_qga_set_time(gconstpointer fix)
 598{
 599    const TestFixture *fixture = fix;
 600    QDict *ret;
 601    int64_t current, time;
 602    gchar *cmd;
 603
 604    /* get current time */
 605    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
 606    g_assert_nonnull(ret);
 607    qmp_assert_no_error(ret);
 608    current = qdict_get_int(ret, "return");
 609    g_assert_cmpint(current, >, 0);
 610    QDECREF(ret);
 611
 612    /* set some old time */
 613    ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time',"
 614                 " 'arguments': { 'time': 1000 } }");
 615    g_assert_nonnull(ret);
 616    qmp_assert_no_error(ret);
 617    QDECREF(ret);
 618
 619    /* check old time */
 620    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
 621    g_assert_nonnull(ret);
 622    qmp_assert_no_error(ret);
 623    time = qdict_get_int(ret, "return");
 624    g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10);
 625    QDECREF(ret);
 626
 627    /* set back current time */
 628    cmd = g_strdup_printf("{'execute': 'guest-set-time',"
 629                          " 'arguments': { 'time': %" PRId64 " } }",
 630                          current + time * 1000);
 631    ret = qmp_fd(fixture->fd, cmd);
 632    g_free(cmd);
 633    g_assert_nonnull(ret);
 634    qmp_assert_no_error(ret);
 635    QDECREF(ret);
 636}
 637
 638static void test_qga_fstrim(gconstpointer fix)
 639{
 640    const TestFixture *fixture = fix;
 641    QDict *ret;
 642    QList *list;
 643    const QListEntry *entry;
 644
 645    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim',"
 646                 " arguments: { minimum: 4194304 } }");
 647    g_assert_nonnull(ret);
 648    qmp_assert_no_error(ret);
 649    list = qdict_get_qlist(ret, "return");
 650    entry = qlist_first(list);
 651    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths"));
 652
 653    QDECREF(ret);
 654}
 655
 656static void test_qga_blacklist(gconstpointer data)
 657{
 658    TestFixture fix;
 659    QDict *ret, *error;
 660    const gchar *class, *desc;
 661
 662    fixture_setup(&fix, "-b guest-ping,guest-get-time");
 663
 664    /* check blacklist */
 665    ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
 666    g_assert_nonnull(ret);
 667    error = qdict_get_qdict(ret, "error");
 668    class = qdict_get_try_str(error, "class");
 669    desc = qdict_get_try_str(error, "desc");
 670    g_assert_cmpstr(class, ==, "GenericError");
 671    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
 672    QDECREF(ret);
 673
 674    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
 675    g_assert_nonnull(ret);
 676    error = qdict_get_qdict(ret, "error");
 677    class = qdict_get_try_str(error, "class");
 678    desc = qdict_get_try_str(error, "desc");
 679    g_assert_cmpstr(class, ==, "GenericError");
 680    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
 681    QDECREF(ret);
 682
 683    /* check something work */
 684    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
 685    qmp_assert_no_error(ret);
 686    QDECREF(ret);
 687
 688    fixture_tear_down(&fix, NULL);
 689}
 690
 691static void test_qga_config(gconstpointer data)
 692{
 693    GError *error = NULL;
 694    char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL;
 695    char *env[2];
 696    int status;
 697    gsize n;
 698    GKeyFile *kf;
 699
 700    cwd = g_get_current_dir();
 701    cmd = g_strdup_printf("%s%cqemu-ga -D",
 702                          cwd, G_DIR_SEPARATOR);
 703    g_shell_parse_argv(cmd, NULL, &argv, &error);
 704    g_assert_no_error(error);
 705
 706    env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
 707                             G_DIR_SEPARATOR, G_DIR_SEPARATOR);
 708    env[1] = NULL;
 709    g_spawn_sync(NULL, argv, env, 0,
 710                 NULL, NULL, &out, &err, &status, &error);
 711    g_assert_no_error(error);
 712    g_assert_cmpstr(err, ==, "");
 713    g_assert_cmpint(status, ==, 0);
 714
 715    kf = g_key_file_new();
 716    g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
 717    g_assert_no_error(error);
 718
 719    str = g_key_file_get_start_group(kf);
 720    g_assert_cmpstr(str, ==, "general");
 721    g_free(str);
 722
 723    g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error));
 724    g_assert_no_error(error);
 725
 726    str = g_key_file_get_string(kf, "general", "method", &error);
 727    g_assert_no_error(error);
 728    g_assert_cmpstr(str, ==, "virtio-serial");
 729    g_free(str);
 730
 731    str = g_key_file_get_string(kf, "general", "path", &error);
 732    g_assert_no_error(error);
 733    g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
 734    g_free(str);
 735
 736    str = g_key_file_get_string(kf, "general", "pidfile", &error);
 737    g_assert_no_error(error);
 738    g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
 739    g_free(str);
 740
 741    str = g_key_file_get_string(kf, "general", "statedir", &error);
 742    g_assert_no_error(error);
 743    g_assert_cmpstr(str, ==, "/var/state");
 744    g_free(str);
 745
 746    g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error));
 747    g_assert_no_error(error);
 748
 749    strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error);
 750    g_assert_cmpint(n, ==, 2);
 751#if GLIB_CHECK_VERSION(2, 44, 0)
 752    g_assert_true(g_strv_contains((const char * const *)strv,
 753                                  "guest-ping"));
 754    g_assert_true(g_strv_contains((const char * const *)strv,
 755                                  "guest-get-time"));
 756#endif
 757    g_assert_no_error(error);
 758    g_strfreev(strv);
 759
 760    g_free(out);
 761    g_free(err);
 762    g_free(env[0]);
 763    g_key_file_free(kf);
 764}
 765
 766static void test_qga_fsfreeze_status(gconstpointer fix)
 767{
 768    const TestFixture *fixture = fix;
 769    QDict *ret;
 770    const gchar *status;
 771
 772    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
 773    g_assert_nonnull(ret);
 774    qmp_assert_no_error(ret);
 775
 776    status = qdict_get_try_str(ret, "return");
 777    g_assert_cmpstr(status, ==, "thawed");
 778
 779    QDECREF(ret);
 780}
 781
 782static void test_qga_fsfreeze_and_thaw(gconstpointer fix)
 783{
 784    const TestFixture *fixture = fix;
 785    QDict *ret;
 786    const gchar *status;
 787
 788    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}");
 789    g_assert_nonnull(ret);
 790    qmp_assert_no_error(ret);
 791    QDECREF(ret);
 792
 793    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
 794    g_assert_nonnull(ret);
 795    qmp_assert_no_error(ret);
 796    status = qdict_get_try_str(ret, "return");
 797    g_assert_cmpstr(status, ==, "frozen");
 798    QDECREF(ret);
 799
 800    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}");
 801    g_assert_nonnull(ret);
 802    qmp_assert_no_error(ret);
 803    QDECREF(ret);
 804}
 805
 806static void test_qga_guest_exec(gconstpointer fix)
 807{
 808    const TestFixture *fixture = fix;
 809    QDict *ret, *val;
 810    const gchar *out;
 811    guchar *decoded;
 812    int64_t pid, now, exitcode;
 813    gsize len;
 814    bool exited;
 815
 816    /* exec 'echo foo bar' */
 817    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
 818                 " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ],"
 819                 " 'capture-output': true } }");
 820    g_assert_nonnull(ret);
 821    qmp_assert_no_error(ret);
 822    val = qdict_get_qdict(ret, "return");
 823    pid = qdict_get_int(val, "pid");
 824    g_assert_cmpint(pid, >, 0);
 825    QDECREF(ret);
 826
 827    /* wait for completion */
 828    now = g_get_monotonic_time();
 829    do {
 830        ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
 831                     " 'arguments': { 'pid': %" PRId64 "  } }", pid);
 832        g_assert_nonnull(ret);
 833        val = qdict_get_qdict(ret, "return");
 834        exited = qdict_get_bool(val, "exited");
 835        if (!exited) {
 836            QDECREF(ret);
 837        }
 838    } while (!exited &&
 839             g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
 840    g_assert(exited);
 841
 842    /* check stdout */
 843    exitcode = qdict_get_int(val, "exitcode");
 844    g_assert_cmpint(exitcode, ==, 0);
 845    out = qdict_get_str(val, "out-data");
 846    decoded = g_base64_decode(out, &len);
 847    g_assert_cmpint(len, ==, 12);
 848    g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
 849    g_free(decoded);
 850    QDECREF(ret);
 851}
 852
 853static void test_qga_guest_exec_invalid(gconstpointer fix)
 854{
 855    const TestFixture *fixture = fix;
 856    QDict *ret, *error;
 857    const gchar *class, *desc;
 858
 859    /* invalid command */
 860    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
 861                 " 'path': '/bin/invalid-cmd42' } }");
 862    g_assert_nonnull(ret);
 863    error = qdict_get_qdict(ret, "error");
 864    g_assert_nonnull(error);
 865    class = qdict_get_str(error, "class");
 866    desc = qdict_get_str(error, "desc");
 867    g_assert_cmpstr(class, ==, "GenericError");
 868    g_assert_cmpint(strlen(desc), >, 0);
 869    QDECREF(ret);
 870
 871    /* invalid pid */
 872    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
 873                 " 'arguments': { 'pid': 0 } }");
 874    g_assert_nonnull(ret);
 875    error = qdict_get_qdict(ret, "error");
 876    g_assert_nonnull(error);
 877    class = qdict_get_str(error, "class");
 878    desc = qdict_get_str(error, "desc");
 879    g_assert_cmpstr(class, ==, "GenericError");
 880    g_assert_cmpint(strlen(desc), >, 0);
 881    QDECREF(ret);
 882}
 883
 884int main(int argc, char **argv)
 885{
 886    TestFixture fix;
 887    int ret;
 888
 889    setlocale (LC_ALL, "");
 890    g_test_init(&argc, &argv, NULL);
 891    fixture_setup(&fix, NULL);
 892
 893    g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
 894    g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
 895    g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
 896    g_test_add_data_func("/qga/info", &fix, test_qga_info);
 897    g_test_add_data_func("/qga/network-get-interfaces", &fix,
 898                         test_qga_network_get_interfaces);
 899    g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
 900    g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
 901    g_test_add_data_func("/qga/get-memory-block-info", &fix,
 902                         test_qga_get_memory_block_info);
 903    g_test_add_data_func("/qga/get-memory-blocks", &fix,
 904                         test_qga_get_memory_blocks);
 905    g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
 906    g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
 907    g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
 908    g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
 909    g_test_add_data_func("/qga/fsfreeze-status", &fix,
 910                         test_qga_fsfreeze_status);
 911
 912    g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist);
 913    g_test_add_data_func("/qga/config", NULL, test_qga_config);
 914    g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
 915    g_test_add_data_func("/qga/guest-exec-invalid", &fix,
 916                         test_qga_guest_exec_invalid);
 917
 918    if (g_getenv("QGA_TEST_SIDE_EFFECTING")) {
 919        g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix,
 920                             test_qga_fsfreeze_and_thaw);
 921        g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time);
 922        g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim);
 923    }
 924
 925    ret = g_test_run();
 926
 927    fixture_tear_down(&fix, NULL);
 928
 929    return ret;
 930}
 931