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, gchar **envp)
  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, envp,
  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("\xff{'execute': 'guest-sync-delimited',"
 150                          " 'arguments': {'id': %u } }", r);
 151    qmp_fd_send(fixture->fd, cmd);
 152    g_free(cmd);
 153
 154    /*
 155     * Read and ignore garbage until resynchronized.
 156     *
 157     * Note that the full reset sequence would involve checking the
 158     * response of guest-sync-delimited and repeating the loop if
 159     * 'id' field of the response does not match the 'id' field of
 160     * the request. Testing this fully would require inserting
 161     * garbage in the response stream and is left as a future test
 162     * to implement.
 163     *
 164     * TODO: The server shouldn't emit so much garbage (among other
 165     * things, it loudly complains about the client's \xff being
 166     * invalid JSON, even though it is a documented part of the
 167     * handshake.
 168     */
 169    do {
 170        v = read(fixture->fd, &c, 1);
 171        g_assert_cmpint(v, ==, 1);
 172    } while (c != 0xff);
 173
 174    ret = qmp_fd_receive(fixture->fd);
 175    g_assert_nonnull(ret);
 176    qmp_assert_no_error(ret);
 177
 178    v = qdict_get_int(ret, "return");
 179    g_assert_cmpint(r, ==, v);
 180
 181    QDECREF(ret);
 182}
 183
 184static void test_qga_sync(gconstpointer fix)
 185{
 186    const TestFixture *fixture = fix;
 187    guint32 v, r = g_random_int();
 188    QDict *ret;
 189    gchar *cmd;
 190
 191    /*
 192     * TODO guest-sync is inherently limited: we cannot distinguish
 193     * failure caused by reacting to garbage on the wire prior to this
 194     * command, from failure of this actual command. Clients are
 195     * supposed to be able to send a raw '\xff' byte to at least
 196     * re-synchronize the server's parser prior to this command, but
 197     * we are not in a position to test that here because (at least
 198     * for now) it causes the server to issue an error message about
 199     * invalid JSON. Testing of '\xff' handling is done in
 200     * guest-sync-delimited instead.
 201     */
 202    cmd = g_strdup_printf("{'execute': 'guest-sync',"
 203                          " 'arguments': {'id': %u } }", r);
 204    ret = qmp_fd(fixture->fd, cmd);
 205    g_free(cmd);
 206
 207    g_assert_nonnull(ret);
 208    qmp_assert_no_error(ret);
 209
 210    v = qdict_get_int(ret, "return");
 211    g_assert_cmpint(r, ==, v);
 212
 213    QDECREF(ret);
 214}
 215
 216static void test_qga_ping(gconstpointer fix)
 217{
 218    const TestFixture *fixture = fix;
 219    QDict *ret;
 220
 221    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
 222    g_assert_nonnull(ret);
 223    qmp_assert_no_error(ret);
 224
 225    QDECREF(ret);
 226}
 227
 228static void test_qga_invalid_args(gconstpointer fix)
 229{
 230    const TestFixture *fixture = fix;
 231    QDict *ret, *error;
 232    const gchar *class, *desc;
 233
 234    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
 235                 "'arguments': {'foo': 42 }}");
 236    g_assert_nonnull(ret);
 237
 238    error = qdict_get_qdict(ret, "error");
 239    class = qdict_get_try_str(error, "class");
 240    desc = qdict_get_try_str(error, "desc");
 241
 242    g_assert_cmpstr(class, ==, "GenericError");
 243    g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
 244
 245    QDECREF(ret);
 246}
 247
 248static void test_qga_invalid_cmd(gconstpointer fix)
 249{
 250    const TestFixture *fixture = fix;
 251    QDict *ret, *error;
 252    const gchar *class, *desc;
 253
 254    ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
 255    g_assert_nonnull(ret);
 256
 257    error = qdict_get_qdict(ret, "error");
 258    class = qdict_get_try_str(error, "class");
 259    desc = qdict_get_try_str(error, "desc");
 260
 261    g_assert_cmpstr(class, ==, "CommandNotFound");
 262    g_assert_cmpint(strlen(desc), >, 0);
 263
 264    QDECREF(ret);
 265}
 266
 267static void test_qga_info(gconstpointer fix)
 268{
 269    const TestFixture *fixture = fix;
 270    QDict *ret, *val;
 271    const gchar *version;
 272
 273    ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
 274    g_assert_nonnull(ret);
 275    qmp_assert_no_error(ret);
 276
 277    val = qdict_get_qdict(ret, "return");
 278    version = qdict_get_try_str(val, "version");
 279    g_assert_cmpstr(version, ==, QEMU_VERSION);
 280
 281    QDECREF(ret);
 282}
 283
 284static void test_qga_get_vcpus(gconstpointer fix)
 285{
 286    const TestFixture *fixture = fix;
 287    QDict *ret;
 288    QList *list;
 289    const QListEntry *entry;
 290
 291    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
 292    g_assert_nonnull(ret);
 293    qmp_assert_no_error(ret);
 294
 295    /* check there is at least a cpu */
 296    list = qdict_get_qlist(ret, "return");
 297    entry = qlist_first(list);
 298    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
 299    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id"));
 300
 301    QDECREF(ret);
 302}
 303
 304static void test_qga_get_fsinfo(gconstpointer fix)
 305{
 306    const TestFixture *fixture = fix;
 307    QDict *ret;
 308    QList *list;
 309    const QListEntry *entry;
 310
 311    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
 312    g_assert_nonnull(ret);
 313    qmp_assert_no_error(ret);
 314
 315    /* sanity-check the response if there are any filesystems */
 316    list = qdict_get_qlist(ret, "return");
 317    entry = qlist_first(list);
 318    if (entry) {
 319        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
 320        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint"));
 321        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type"));
 322        g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk"));
 323    }
 324
 325    QDECREF(ret);
 326}
 327
 328static void test_qga_get_memory_block_info(gconstpointer fix)
 329{
 330    const TestFixture *fixture = fix;
 331    QDict *ret, *val;
 332    int64_t size;
 333
 334    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
 335    g_assert_nonnull(ret);
 336
 337    /* some systems might not expose memory block info in sysfs */
 338    if (!qdict_haskey(ret, "error")) {
 339        /* check there is at least some memory */
 340        val = qdict_get_qdict(ret, "return");
 341        size = qdict_get_int(val, "size");
 342        g_assert_cmpint(size, >, 0);
 343    }
 344
 345    QDECREF(ret);
 346}
 347
 348static void test_qga_get_memory_blocks(gconstpointer fix)
 349{
 350    const TestFixture *fixture = fix;
 351    QDict *ret;
 352    QList *list;
 353    const QListEntry *entry;
 354
 355    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
 356    g_assert_nonnull(ret);
 357
 358    /* some systems might not expose memory block info in sysfs */
 359    if (!qdict_haskey(ret, "error")) {
 360        list = qdict_get_qlist(ret, "return");
 361        entry = qlist_first(list);
 362        /* newer versions of qga may return empty list without error */
 363        if (entry) {
 364            g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index"));
 365            g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
 366        }
 367    }
 368
 369    QDECREF(ret);
 370}
 371
 372static void test_qga_network_get_interfaces(gconstpointer fix)
 373{
 374    const TestFixture *fixture = fix;
 375    QDict *ret;
 376    QList *list;
 377    const QListEntry *entry;
 378
 379    ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
 380    g_assert_nonnull(ret);
 381    qmp_assert_no_error(ret);
 382
 383    /* check there is at least an interface */
 384    list = qdict_get_qlist(ret, "return");
 385    entry = qlist_first(list);
 386    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
 387
 388    QDECREF(ret);
 389}
 390
 391static void test_qga_file_ops(gconstpointer fix)
 392{
 393    const TestFixture *fixture = fix;
 394    const unsigned char helloworld[] = "Hello World!\n";
 395    const char *b64;
 396    gchar *cmd, *path, *enc;
 397    unsigned char *dec;
 398    QDict *ret, *val;
 399    int64_t id, eof;
 400    gsize count;
 401    FILE *f;
 402    char tmp[100];
 403
 404    /* open */
 405    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 406                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
 407    g_assert_nonnull(ret);
 408    qmp_assert_no_error(ret);
 409    id = qdict_get_int(ret, "return");
 410    QDECREF(ret);
 411
 412    enc = g_base64_encode(helloworld, sizeof(helloworld));
 413    /* write */
 414    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
 415                          " 'arguments': { 'handle': %" PRId64 ","
 416                          " 'buf-b64': '%s' } }", id, enc);
 417    ret = qmp_fd(fixture->fd, cmd);
 418    g_assert_nonnull(ret);
 419    qmp_assert_no_error(ret);
 420
 421    val = qdict_get_qdict(ret, "return");
 422    count = qdict_get_int(val, "count");
 423    eof = qdict_get_bool(val, "eof");
 424    g_assert_cmpint(count, ==, sizeof(helloworld));
 425    g_assert_cmpint(eof, ==, 0);
 426    QDECREF(ret);
 427    g_free(cmd);
 428
 429    /* flush */
 430    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
 431                          " 'arguments': {'handle': %" PRId64 "} }",
 432                          id);
 433    ret = qmp_fd(fixture->fd, cmd);
 434    QDECREF(ret);
 435    g_free(cmd);
 436
 437    /* close */
 438    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 439                          " 'arguments': {'handle': %" PRId64 "} }",
 440                          id);
 441    ret = qmp_fd(fixture->fd, cmd);
 442    QDECREF(ret);
 443    g_free(cmd);
 444
 445    /* check content */
 446    path = g_build_filename(fixture->test_dir, "foo", NULL);
 447    f = fopen(path, "r");
 448    g_free(path);
 449    g_assert_nonnull(f);
 450    count = fread(tmp, 1, sizeof(tmp), f);
 451    g_assert_cmpint(count, ==, sizeof(helloworld));
 452    tmp[count] = 0;
 453    g_assert_cmpstr(tmp, ==, (char *)helloworld);
 454    fclose(f);
 455
 456    /* open */
 457    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 458                 " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
 459    g_assert_nonnull(ret);
 460    qmp_assert_no_error(ret);
 461    id = qdict_get_int(ret, "return");
 462    QDECREF(ret);
 463
 464    /* read */
 465    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 466                          " 'arguments': { 'handle': %" PRId64 "} }",
 467                          id);
 468    ret = qmp_fd(fixture->fd, cmd);
 469    val = qdict_get_qdict(ret, "return");
 470    count = qdict_get_int(val, "count");
 471    eof = qdict_get_bool(val, "eof");
 472    b64 = qdict_get_str(val, "buf-b64");
 473    g_assert_cmpint(count, ==, sizeof(helloworld));
 474    g_assert(eof);
 475    g_assert_cmpstr(b64, ==, enc);
 476
 477    QDECREF(ret);
 478    g_free(cmd);
 479    g_free(enc);
 480
 481    /* read eof */
 482    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 483                          " 'arguments': { 'handle': %" PRId64 "} }",
 484                          id);
 485    ret = qmp_fd(fixture->fd, cmd);
 486    val = qdict_get_qdict(ret, "return");
 487    count = qdict_get_int(val, "count");
 488    eof = qdict_get_bool(val, "eof");
 489    b64 = qdict_get_str(val, "buf-b64");
 490    g_assert_cmpint(count, ==, 0);
 491    g_assert(eof);
 492    g_assert_cmpstr(b64, ==, "");
 493    QDECREF(ret);
 494    g_free(cmd);
 495
 496    /* seek */
 497    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
 498                          " 'arguments': { 'handle': %" PRId64 ", "
 499                          " 'offset': %d, 'whence': '%s' } }",
 500                          id, 6, "set");
 501    ret = qmp_fd(fixture->fd, cmd);
 502    qmp_assert_no_error(ret);
 503    val = qdict_get_qdict(ret, "return");
 504    count = qdict_get_int(val, "position");
 505    eof = qdict_get_bool(val, "eof");
 506    g_assert_cmpint(count, ==, 6);
 507    g_assert(!eof);
 508    QDECREF(ret);
 509    g_free(cmd);
 510
 511    /* partial read */
 512    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 513                          " 'arguments': { 'handle': %" PRId64 "} }",
 514                          id);
 515    ret = qmp_fd(fixture->fd, cmd);
 516    val = qdict_get_qdict(ret, "return");
 517    count = qdict_get_int(val, "count");
 518    eof = qdict_get_bool(val, "eof");
 519    b64 = qdict_get_str(val, "buf-b64");
 520    g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
 521    g_assert(eof);
 522    dec = g_base64_decode(b64, &count);
 523    g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
 524    g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6);
 525    g_free(dec);
 526
 527    QDECREF(ret);
 528    g_free(cmd);
 529
 530    /* close */
 531    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 532                          " 'arguments': {'handle': %" PRId64 "} }",
 533                          id);
 534    ret = qmp_fd(fixture->fd, cmd);
 535    QDECREF(ret);
 536    g_free(cmd);
 537}
 538
 539static void test_qga_file_write_read(gconstpointer fix)
 540{
 541    const TestFixture *fixture = fix;
 542    const unsigned char helloworld[] = "Hello World!\n";
 543    const char *b64;
 544    gchar *cmd, *enc;
 545    QDict *ret, *val;
 546    int64_t id, eof;
 547    gsize count;
 548
 549    /* open */
 550    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
 551                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
 552    g_assert_nonnull(ret);
 553    qmp_assert_no_error(ret);
 554    id = qdict_get_int(ret, "return");
 555    QDECREF(ret);
 556
 557    enc = g_base64_encode(helloworld, sizeof(helloworld));
 558    /* write */
 559    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
 560                          " 'arguments': { 'handle': %" PRId64 ","
 561                          " 'buf-b64': '%s' } }", id, enc);
 562    ret = qmp_fd(fixture->fd, cmd);
 563    g_assert_nonnull(ret);
 564    qmp_assert_no_error(ret);
 565
 566    val = qdict_get_qdict(ret, "return");
 567    count = qdict_get_int(val, "count");
 568    eof = qdict_get_bool(val, "eof");
 569    g_assert_cmpint(count, ==, sizeof(helloworld));
 570    g_assert_cmpint(eof, ==, 0);
 571    QDECREF(ret);
 572    g_free(cmd);
 573
 574    /* read (check implicit flush) */
 575    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 576                          " 'arguments': { 'handle': %" PRId64 "} }",
 577                          id);
 578    ret = qmp_fd(fixture->fd, cmd);
 579    val = qdict_get_qdict(ret, "return");
 580    count = qdict_get_int(val, "count");
 581    eof = qdict_get_bool(val, "eof");
 582    b64 = qdict_get_str(val, "buf-b64");
 583    g_assert_cmpint(count, ==, 0);
 584    g_assert(eof);
 585    g_assert_cmpstr(b64, ==, "");
 586    QDECREF(ret);
 587    g_free(cmd);
 588
 589    /* seek to 0 */
 590    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
 591                          " 'arguments': { 'handle': %" PRId64 ", "
 592                          " 'offset': %d, 'whence': '%s' } }",
 593                          id, 0, "set");
 594    ret = qmp_fd(fixture->fd, cmd);
 595    qmp_assert_no_error(ret);
 596    val = qdict_get_qdict(ret, "return");
 597    count = qdict_get_int(val, "position");
 598    eof = qdict_get_bool(val, "eof");
 599    g_assert_cmpint(count, ==, 0);
 600    g_assert(!eof);
 601    QDECREF(ret);
 602    g_free(cmd);
 603
 604    /* read */
 605    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
 606                          " 'arguments': { 'handle': %" PRId64 "} }",
 607                          id);
 608    ret = qmp_fd(fixture->fd, cmd);
 609    val = qdict_get_qdict(ret, "return");
 610    count = qdict_get_int(val, "count");
 611    eof = qdict_get_bool(val, "eof");
 612    b64 = qdict_get_str(val, "buf-b64");
 613    g_assert_cmpint(count, ==, sizeof(helloworld));
 614    g_assert(eof);
 615    g_assert_cmpstr(b64, ==, enc);
 616    QDECREF(ret);
 617    g_free(cmd);
 618    g_free(enc);
 619
 620    /* close */
 621    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
 622                          " 'arguments': {'handle': %" PRId64 "} }",
 623                          id);
 624    ret = qmp_fd(fixture->fd, cmd);
 625    QDECREF(ret);
 626    g_free(cmd);
 627}
 628
 629static void test_qga_get_time(gconstpointer fix)
 630{
 631    const TestFixture *fixture = fix;
 632    QDict *ret;
 633    int64_t time;
 634
 635    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
 636    g_assert_nonnull(ret);
 637    qmp_assert_no_error(ret);
 638
 639    time = qdict_get_int(ret, "return");
 640    g_assert_cmpint(time, >, 0);
 641
 642    QDECREF(ret);
 643}
 644
 645static void test_qga_blacklist(gconstpointer data)
 646{
 647    TestFixture fix;
 648    QDict *ret, *error;
 649    const gchar *class, *desc;
 650
 651    fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL);
 652
 653    /* check blacklist */
 654    ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
 655    g_assert_nonnull(ret);
 656    error = qdict_get_qdict(ret, "error");
 657    class = qdict_get_try_str(error, "class");
 658    desc = qdict_get_try_str(error, "desc");
 659    g_assert_cmpstr(class, ==, "GenericError");
 660    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
 661    QDECREF(ret);
 662
 663    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
 664    g_assert_nonnull(ret);
 665    error = qdict_get_qdict(ret, "error");
 666    class = qdict_get_try_str(error, "class");
 667    desc = qdict_get_try_str(error, "desc");
 668    g_assert_cmpstr(class, ==, "GenericError");
 669    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
 670    QDECREF(ret);
 671
 672    /* check something work */
 673    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
 674    qmp_assert_no_error(ret);
 675    QDECREF(ret);
 676
 677    fixture_tear_down(&fix, NULL);
 678}
 679
 680static void test_qga_config(gconstpointer data)
 681{
 682    GError *error = NULL;
 683    char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL;
 684    char *env[2];
 685    int status;
 686    gsize n;
 687    GKeyFile *kf;
 688
 689    cwd = g_get_current_dir();
 690    cmd = g_strdup_printf("%s%cqemu-ga -D",
 691                          cwd, G_DIR_SEPARATOR);
 692    g_free(cwd);
 693    g_shell_parse_argv(cmd, NULL, &argv, &error);
 694    g_free(cmd);
 695    g_assert_no_error(error);
 696
 697    env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
 698                             G_DIR_SEPARATOR, G_DIR_SEPARATOR);
 699    env[1] = NULL;
 700    g_spawn_sync(NULL, argv, env, 0,
 701                 NULL, NULL, &out, &err, &status, &error);
 702    g_strfreev(argv);
 703
 704    g_assert_no_error(error);
 705    g_assert_cmpstr(err, ==, "");
 706    g_assert_cmpint(status, ==, 0);
 707
 708    kf = g_key_file_new();
 709    g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
 710    g_assert_no_error(error);
 711
 712    str = g_key_file_get_start_group(kf);
 713    g_assert_cmpstr(str, ==, "general");
 714    g_free(str);
 715
 716    g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error));
 717    g_assert_no_error(error);
 718
 719    str = g_key_file_get_string(kf, "general", "method", &error);
 720    g_assert_no_error(error);
 721    g_assert_cmpstr(str, ==, "virtio-serial");
 722    g_free(str);
 723
 724    str = g_key_file_get_string(kf, "general", "path", &error);
 725    g_assert_no_error(error);
 726    g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
 727    g_free(str);
 728
 729    str = g_key_file_get_string(kf, "general", "pidfile", &error);
 730    g_assert_no_error(error);
 731    g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
 732    g_free(str);
 733
 734    str = g_key_file_get_string(kf, "general", "statedir", &error);
 735    g_assert_no_error(error);
 736    g_assert_cmpstr(str, ==, "/var/state");
 737    g_free(str);
 738
 739    g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error));
 740    g_assert_no_error(error);
 741
 742    strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error);
 743    g_assert_cmpint(n, ==, 2);
 744#if GLIB_CHECK_VERSION(2, 44, 0)
 745    g_assert_true(g_strv_contains((const char * const *)strv,
 746                                  "guest-ping"));
 747    g_assert_true(g_strv_contains((const char * const *)strv,
 748                                  "guest-get-time"));
 749#endif
 750    g_assert_no_error(error);
 751    g_strfreev(strv);
 752
 753    g_free(out);
 754    g_free(err);
 755    g_free(env[0]);
 756    g_key_file_free(kf);
 757}
 758
 759static void test_qga_fsfreeze_status(gconstpointer fix)
 760{
 761    const TestFixture *fixture = fix;
 762    QDict *ret;
 763    const gchar *status;
 764
 765    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
 766    g_assert_nonnull(ret);
 767    qmp_assert_no_error(ret);
 768
 769    status = qdict_get_try_str(ret, "return");
 770    g_assert_cmpstr(status, ==, "thawed");
 771
 772    QDECREF(ret);
 773}
 774
 775static void test_qga_guest_exec(gconstpointer fix)
 776{
 777    const TestFixture *fixture = fix;
 778    QDict *ret, *val;
 779    const gchar *out;
 780    guchar *decoded;
 781    int64_t pid, now, exitcode;
 782    gsize len;
 783    bool exited;
 784    char *cmd;
 785
 786    /* exec 'echo foo bar' */
 787    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
 788                 " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ],"
 789                 " 'capture-output': true } }");
 790    g_assert_nonnull(ret);
 791    qmp_assert_no_error(ret);
 792    val = qdict_get_qdict(ret, "return");
 793    pid = qdict_get_int(val, "pid");
 794    g_assert_cmpint(pid, >, 0);
 795    QDECREF(ret);
 796
 797    /* wait for completion */
 798    now = g_get_monotonic_time();
 799    cmd = g_strdup_printf("{'execute': 'guest-exec-status',"
 800                          " 'arguments': { 'pid': %" PRId64 " } }", pid);
 801    do {
 802        ret = qmp_fd(fixture->fd, cmd);
 803        g_assert_nonnull(ret);
 804        val = qdict_get_qdict(ret, "return");
 805        exited = qdict_get_bool(val, "exited");
 806        if (!exited) {
 807            QDECREF(ret);
 808        }
 809    } while (!exited &&
 810             g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
 811    g_assert(exited);
 812    g_free(cmd);
 813
 814    /* check stdout */
 815    exitcode = qdict_get_int(val, "exitcode");
 816    g_assert_cmpint(exitcode, ==, 0);
 817    out = qdict_get_str(val, "out-data");
 818    decoded = g_base64_decode(out, &len);
 819    g_assert_cmpint(len, ==, 12);
 820    g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
 821    g_free(decoded);
 822    QDECREF(ret);
 823}
 824
 825static void test_qga_guest_exec_invalid(gconstpointer fix)
 826{
 827    const TestFixture *fixture = fix;
 828    QDict *ret, *error;
 829    const gchar *class, *desc;
 830
 831    /* invalid command */
 832    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
 833                 " 'path': '/bin/invalid-cmd42' } }");
 834    g_assert_nonnull(ret);
 835    error = qdict_get_qdict(ret, "error");
 836    g_assert_nonnull(error);
 837    class = qdict_get_str(error, "class");
 838    desc = qdict_get_str(error, "desc");
 839    g_assert_cmpstr(class, ==, "GenericError");
 840    g_assert_cmpint(strlen(desc), >, 0);
 841    QDECREF(ret);
 842
 843    /* invalid pid */
 844    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
 845                 " 'arguments': { 'pid': 0 } }");
 846    g_assert_nonnull(ret);
 847    error = qdict_get_qdict(ret, "error");
 848    g_assert_nonnull(error);
 849    class = qdict_get_str(error, "class");
 850    desc = qdict_get_str(error, "desc");
 851    g_assert_cmpstr(class, ==, "GenericError");
 852    g_assert_cmpint(strlen(desc), >, 0);
 853    QDECREF(ret);
 854}
 855
 856static void test_qga_guest_get_osinfo(gconstpointer data)
 857{
 858    TestFixture fixture;
 859    const gchar *str;
 860    gchar *cwd, *env[2];
 861    QDict *ret, *val;
 862
 863    cwd = g_get_current_dir();
 864    env[0] = g_strdup_printf(
 865        "QGA_OS_RELEASE=%s%ctests%cdata%ctest-qga-os-release",
 866        cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
 867    env[1] = NULL;
 868    g_free(cwd);
 869    fixture_setup(&fixture, NULL, env);
 870
 871    ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
 872    g_assert_nonnull(ret);
 873    qmp_assert_no_error(ret);
 874
 875    val = qdict_get_qdict(ret, "return");
 876
 877    str = qdict_get_try_str(val, "id");
 878    g_assert_nonnull(str);
 879    g_assert_cmpstr(str, ==, "qemu-ga-test");
 880
 881    str = qdict_get_try_str(val, "name");
 882    g_assert_nonnull(str);
 883    g_assert_cmpstr(str, ==, "QEMU-GA");
 884
 885    str = qdict_get_try_str(val, "pretty-name");
 886    g_assert_nonnull(str);
 887    g_assert_cmpstr(str, ==, "QEMU Guest Agent test");
 888
 889    str = qdict_get_try_str(val, "version");
 890    g_assert_nonnull(str);
 891    g_assert_cmpstr(str, ==, "Test 1");
 892
 893    str = qdict_get_try_str(val, "version-id");
 894    g_assert_nonnull(str);
 895    g_assert_cmpstr(str, ==, "1");
 896
 897    str = qdict_get_try_str(val, "variant");
 898    g_assert_nonnull(str);
 899    g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc.");
 900
 901    str = qdict_get_try_str(val, "variant-id");
 902    g_assert_nonnull(str);
 903    g_assert_cmpstr(str, ==, "unit-test");
 904
 905    QDECREF(ret);
 906    g_free(env[0]);
 907    fixture_tear_down(&fixture, NULL);
 908}
 909
 910int main(int argc, char **argv)
 911{
 912    TestFixture fix;
 913    int ret;
 914
 915    setlocale (LC_ALL, "");
 916    g_test_init(&argc, &argv, NULL);
 917    fixture_setup(&fix, NULL, NULL);
 918
 919    g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
 920    g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
 921    g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
 922    g_test_add_data_func("/qga/info", &fix, test_qga_info);
 923    g_test_add_data_func("/qga/network-get-interfaces", &fix,
 924                         test_qga_network_get_interfaces);
 925    if (!access("/sys/devices/system/cpu/cpu0", F_OK)) {
 926        g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
 927    }
 928    g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
 929    g_test_add_data_func("/qga/get-memory-block-info", &fix,
 930                         test_qga_get_memory_block_info);
 931    g_test_add_data_func("/qga/get-memory-blocks", &fix,
 932                         test_qga_get_memory_blocks);
 933    g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
 934    g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
 935    g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
 936    g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
 937    g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args);
 938    g_test_add_data_func("/qga/fsfreeze-status", &fix,
 939                         test_qga_fsfreeze_status);
 940
 941    g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist);
 942    g_test_add_data_func("/qga/config", NULL, test_qga_config);
 943    g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
 944    g_test_add_data_func("/qga/guest-exec-invalid", &fix,
 945                         test_qga_guest_exec_invalid);
 946    g_test_add_data_func("/qga/guest-get-osinfo", &fix,
 947                         test_qga_guest_get_osinfo);
 948
 949    ret = g_test_run();
 950
 951    fixture_tear_down(&fix, NULL);
 952
 953    return ret;
 954}
 955