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