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