1681c28a3SPeter Maydell #include "qemu/osdep.h" 262c39b30SMarc-André Lureau #include <locale.h> 362c39b30SMarc-André Lureau #include <glib/gstdio.h> 462c39b30SMarc-André Lureau #include <sys/socket.h> 562c39b30SMarc-André Lureau #include <sys/un.h> 662c39b30SMarc-André Lureau 7907b5105SMarc-André Lureau #include "../qtest/libqtest.h" 8*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h" 9*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h" 1062c39b30SMarc-André Lureau 1162c39b30SMarc-André Lureau typedef struct { 1262c39b30SMarc-André Lureau char *test_dir; 1362c39b30SMarc-André Lureau GMainLoop *loop; 1462c39b30SMarc-André Lureau int fd; 1562c39b30SMarc-André Lureau GPid pid; 1662c39b30SMarc-André Lureau } TestFixture; 1762c39b30SMarc-André Lureau 1862c39b30SMarc-André Lureau static int connect_qga(char *path) 1962c39b30SMarc-André Lureau { 2062c39b30SMarc-André Lureau int s, ret, len, i = 0; 2162c39b30SMarc-André Lureau struct sockaddr_un remote; 2262c39b30SMarc-André Lureau 2362c39b30SMarc-André Lureau s = socket(AF_UNIX, SOCK_STREAM, 0); 2462c39b30SMarc-André Lureau g_assert(s != -1); 2562c39b30SMarc-André Lureau 2662c39b30SMarc-André Lureau remote.sun_family = AF_UNIX; 2762c39b30SMarc-André Lureau do { 2862c39b30SMarc-André Lureau strcpy(remote.sun_path, path); 2962c39b30SMarc-André Lureau len = strlen(remote.sun_path) + sizeof(remote.sun_family); 3062c39b30SMarc-André Lureau ret = connect(s, (struct sockaddr *)&remote, len); 3162c39b30SMarc-André Lureau if (ret == -1) { 3262c39b30SMarc-André Lureau g_usleep(G_USEC_PER_SEC); 3362c39b30SMarc-André Lureau } 3462c39b30SMarc-André Lureau if (i++ == 10) { 355dc51100SPaolo Bonzini close(s); 3662c39b30SMarc-André Lureau return -1; 3762c39b30SMarc-André Lureau } 3862c39b30SMarc-André Lureau } while (ret == -1); 3962c39b30SMarc-André Lureau 4062c39b30SMarc-André Lureau return s; 4162c39b30SMarc-André Lureau } 4262c39b30SMarc-André Lureau 4362c39b30SMarc-André Lureau static void qga_watch(GPid pid, gint status, gpointer user_data) 4462c39b30SMarc-André Lureau { 4562c39b30SMarc-André Lureau TestFixture *fixture = user_data; 4662c39b30SMarc-André Lureau 4762c39b30SMarc-André Lureau g_assert_cmpint(status, ==, 0); 4862c39b30SMarc-André Lureau g_main_loop_quit(fixture->loop); 4962c39b30SMarc-André Lureau } 5062c39b30SMarc-André Lureau 5162c39b30SMarc-André Lureau static void 52c28afa76STomáš Golembiovský fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) 5362c39b30SMarc-André Lureau { 5462c39b30SMarc-André Lureau const gchar *extra_arg = data; 5562c39b30SMarc-André Lureau GError *error = NULL; 56bb6960a1SMarc-André Lureau g_autofree char *cwd = NULL; 57bb6960a1SMarc-André Lureau g_autofree char *path = NULL; 58bb6960a1SMarc-André Lureau g_autofree char *cmd = NULL; 59bb6960a1SMarc-André Lureau g_auto(GStrv) argv = NULL; 6062c39b30SMarc-André Lureau 6162c39b30SMarc-André Lureau fixture->loop = g_main_loop_new(NULL, FALSE); 6262c39b30SMarc-André Lureau 635b9f2781SBin Meng fixture->test_dir = g_strdup_printf("%s/qgatest.XXXXXX", g_get_tmp_dir()); 643c239aa7SBin Meng g_assert_nonnull(g_mkdtemp(fixture->test_dir)); 6562c39b30SMarc-André Lureau 6662c39b30SMarc-André Lureau path = g_build_filename(fixture->test_dir, "sock", NULL); 6762c39b30SMarc-André Lureau cwd = g_get_current_dir(); 68f15bff25SPaolo Bonzini cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s", 69f15bff25SPaolo Bonzini cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, 7062c39b30SMarc-André Lureau fixture->test_dir, path, 7162c39b30SMarc-André Lureau getenv("QTEST_LOG") ? "-v" : "", 7262c39b30SMarc-André Lureau extra_arg ?: ""); 7362c39b30SMarc-André Lureau g_shell_parse_argv(cmd, NULL, &argv, &error); 7462c39b30SMarc-André Lureau g_assert_no_error(error); 7562c39b30SMarc-André Lureau 76c28afa76STomáš Golembiovský g_spawn_async(fixture->test_dir, argv, envp, 7762c39b30SMarc-André Lureau G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, 7862c39b30SMarc-André Lureau NULL, NULL, &fixture->pid, &error); 7962c39b30SMarc-André Lureau g_assert_no_error(error); 8062c39b30SMarc-André Lureau 8162c39b30SMarc-André Lureau g_child_watch_add(fixture->pid, qga_watch, fixture); 8262c39b30SMarc-André Lureau 8362c39b30SMarc-André Lureau fixture->fd = connect_qga(path); 8462c39b30SMarc-André Lureau g_assert_cmpint(fixture->fd, !=, -1); 8562c39b30SMarc-André Lureau } 8662c39b30SMarc-André Lureau 8762c39b30SMarc-André Lureau static void 8862c39b30SMarc-André Lureau fixture_tear_down(TestFixture *fixture, gconstpointer data) 8962c39b30SMarc-André Lureau { 90bb6960a1SMarc-André Lureau g_autofree char *tmp = NULL; 9162c39b30SMarc-André Lureau 9262c39b30SMarc-André Lureau kill(fixture->pid, SIGTERM); 9362c39b30SMarc-André Lureau 9462c39b30SMarc-André Lureau g_main_loop_run(fixture->loop); 9562c39b30SMarc-André Lureau g_main_loop_unref(fixture->loop); 9662c39b30SMarc-André Lureau 9762c39b30SMarc-André Lureau g_spawn_close_pid(fixture->pid); 9862c39b30SMarc-André Lureau 9962c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "foo", NULL); 10062c39b30SMarc-André Lureau g_unlink(tmp); 10162c39b30SMarc-André Lureau g_free(tmp); 10262c39b30SMarc-André Lureau 10362c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "qga.state", NULL); 10462c39b30SMarc-André Lureau g_unlink(tmp); 10562c39b30SMarc-André Lureau g_free(tmp); 10662c39b30SMarc-André Lureau 10762c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "sock", NULL); 10862c39b30SMarc-André Lureau g_unlink(tmp); 10962c39b30SMarc-André Lureau 11062c39b30SMarc-André Lureau g_rmdir(fixture->test_dir); 11162c39b30SMarc-André Lureau g_free(fixture->test_dir); 11243d1da7cSAlex Chen close(fixture->fd); 11362c39b30SMarc-André Lureau } 11462c39b30SMarc-André Lureau 11562c39b30SMarc-André Lureau static void qmp_assertion_message_error(const char *domain, 11662c39b30SMarc-André Lureau const char *file, 11762c39b30SMarc-André Lureau int line, 11862c39b30SMarc-André Lureau const char *func, 11962c39b30SMarc-André Lureau const char *expr, 12062c39b30SMarc-André Lureau QDict *dict) 12162c39b30SMarc-André Lureau { 12262c39b30SMarc-André Lureau const char *class, *desc; 123bb6960a1SMarc-André Lureau g_autofree char *s = NULL; 12462c39b30SMarc-André Lureau QDict *error; 12562c39b30SMarc-André Lureau 12662c39b30SMarc-André Lureau error = qdict_get_qdict(dict, "error"); 12762c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 12862c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 12962c39b30SMarc-André Lureau 13062c39b30SMarc-André Lureau s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); 13162c39b30SMarc-André Lureau g_assertion_message(domain, file, line, func, s); 13262c39b30SMarc-André Lureau } 13362c39b30SMarc-André Lureau 13462c39b30SMarc-André Lureau #define qmp_assert_no_error(err) do { \ 13562c39b30SMarc-André Lureau if (qdict_haskey(err, "error")) { \ 13662c39b30SMarc-André Lureau qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__, \ 13762c39b30SMarc-André Lureau G_STRFUNC, #err, err); \ 13862c39b30SMarc-André Lureau } \ 13962c39b30SMarc-André Lureau } while (0) 14062c39b30SMarc-André Lureau 14162c39b30SMarc-André Lureau static void test_qga_sync_delimited(gconstpointer fix) 14262c39b30SMarc-André Lureau { 14362c39b30SMarc-André Lureau const TestFixture *fixture = fix; 1440f555602SPaolo Bonzini guint32 v, r = g_test_rand_int(); 14562c39b30SMarc-André Lureau unsigned char c; 146bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 14762c39b30SMarc-André Lureau 148e2f64a68SMarkus Armbruster qmp_fd_send_raw(fixture->fd, "\xff"); 149015715f5SMarkus Armbruster qmp_fd_send(fixture->fd, 150e2f64a68SMarkus Armbruster "{'execute': 'guest-sync-delimited'," 151015715f5SMarkus Armbruster " 'arguments': {'id': %u } }", 152015715f5SMarkus Armbruster r); 15362c39b30SMarc-André Lureau 1545229564bSEric Blake /* 1555229564bSEric Blake * Read and ignore garbage until resynchronized. 1565229564bSEric Blake * 1575229564bSEric Blake * Note that the full reset sequence would involve checking the 1585229564bSEric Blake * response of guest-sync-delimited and repeating the loop if 1595229564bSEric Blake * 'id' field of the response does not match the 'id' field of 1605229564bSEric Blake * the request. Testing this fully would require inserting 1615229564bSEric Blake * garbage in the response stream and is left as a future test 1625229564bSEric Blake * to implement. 1635229564bSEric Blake * 1645229564bSEric Blake * TODO: The server shouldn't emit so much garbage (among other 1655229564bSEric Blake * things, it loudly complains about the client's \xff being 1665229564bSEric Blake * invalid JSON, even though it is a documented part of the 1675229564bSEric Blake * handshake. 1685229564bSEric Blake */ 1695229564bSEric Blake do { 17062c39b30SMarc-André Lureau v = read(fixture->fd, &c, 1); 17162c39b30SMarc-André Lureau g_assert_cmpint(v, ==, 1); 1725229564bSEric Blake } while (c != 0xff); 17362c39b30SMarc-André Lureau 17462c39b30SMarc-André Lureau ret = qmp_fd_receive(fixture->fd); 17562c39b30SMarc-André Lureau g_assert_nonnull(ret); 17662c39b30SMarc-André Lureau qmp_assert_no_error(ret); 17762c39b30SMarc-André Lureau 17862c39b30SMarc-André Lureau v = qdict_get_int(ret, "return"); 17962c39b30SMarc-André Lureau g_assert_cmpint(r, ==, v); 18062c39b30SMarc-André Lureau } 18162c39b30SMarc-André Lureau 18262c39b30SMarc-André Lureau static void test_qga_sync(gconstpointer fix) 18362c39b30SMarc-André Lureau { 18462c39b30SMarc-André Lureau const TestFixture *fixture = fix; 1850f555602SPaolo Bonzini guint32 v, r = g_test_rand_int(); 186bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 18762c39b30SMarc-André Lureau 1885229564bSEric Blake /* 1895229564bSEric Blake * TODO guest-sync is inherently limited: we cannot distinguish 1905229564bSEric Blake * failure caused by reacting to garbage on the wire prior to this 1915229564bSEric Blake * command, from failure of this actual command. Clients are 1925229564bSEric Blake * supposed to be able to send a raw '\xff' byte to at least 1935229564bSEric Blake * re-synchronize the server's parser prior to this command, but 1945229564bSEric Blake * we are not in a position to test that here because (at least 1955229564bSEric Blake * for now) it causes the server to issue an error message about 1965229564bSEric Blake * invalid JSON. Testing of '\xff' handling is done in 1975229564bSEric Blake * guest-sync-delimited instead. 1985229564bSEric Blake */ 199015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 200015715f5SMarkus Armbruster "{'execute': 'guest-sync', 'arguments': {'id': %u } }", 201015715f5SMarkus Armbruster r); 20262c39b30SMarc-André Lureau 20362c39b30SMarc-André Lureau g_assert_nonnull(ret); 20462c39b30SMarc-André Lureau qmp_assert_no_error(ret); 20562c39b30SMarc-André Lureau 20662c39b30SMarc-André Lureau v = qdict_get_int(ret, "return"); 20762c39b30SMarc-André Lureau g_assert_cmpint(r, ==, v); 20862c39b30SMarc-André Lureau } 20962c39b30SMarc-André Lureau 21062c39b30SMarc-André Lureau static void test_qga_ping(gconstpointer fix) 21162c39b30SMarc-André Lureau { 21262c39b30SMarc-André Lureau const TestFixture *fixture = fix; 213bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 21462c39b30SMarc-André Lureau 21562c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); 21662c39b30SMarc-André Lureau g_assert_nonnull(ret); 21762c39b30SMarc-André Lureau qmp_assert_no_error(ret); 21862c39b30SMarc-André Lureau } 21962c39b30SMarc-André Lureau 2204eaca8deSMarc-André Lureau static void test_qga_id(gconstpointer fix) 221b5f84310SMarkus Armbruster { 222b5f84310SMarkus Armbruster const TestFixture *fixture = fix; 223bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 224b5f84310SMarkus Armbruster 225b5f84310SMarkus Armbruster ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}"); 226b5f84310SMarkus Armbruster g_assert_nonnull(ret); 2274eaca8deSMarc-André Lureau qmp_assert_no_error(ret); 2284eaca8deSMarc-André Lureau g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1); 229b5f84310SMarkus Armbruster } 230b5f84310SMarkus Armbruster 231d4d7ed73SMarkus Armbruster static void test_qga_invalid_oob(gconstpointer fix) 232d4d7ed73SMarkus Armbruster { 233d4d7ed73SMarkus Armbruster const TestFixture *fixture = fix; 234ebb4d82dSMarc-André Lureau QDict *ret; 235d4d7ed73SMarkus Armbruster 23600ecec15SMarkus Armbruster ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}"); 237d4d7ed73SMarkus Armbruster g_assert_nonnull(ret); 238d4d7ed73SMarkus Armbruster 2393bc1b8eeSMarkus Armbruster qmp_expect_error_and_unref(ret, "GenericError"); 240d4d7ed73SMarkus Armbruster } 241d4d7ed73SMarkus Armbruster 2424bdadd86SMarc-André Lureau static void test_qga_invalid_args(gconstpointer fix) 2434bdadd86SMarc-André Lureau { 2444bdadd86SMarc-André Lureau const TestFixture *fixture = fix; 245bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 246bb6960a1SMarc-André Lureau QDict *error; 2474bdadd86SMarc-André Lureau const gchar *class, *desc; 2484bdadd86SMarc-André Lureau 2494bdadd86SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', " 2504bdadd86SMarc-André Lureau "'arguments': {'foo': 42 }}"); 2514bdadd86SMarc-André Lureau g_assert_nonnull(ret); 2524bdadd86SMarc-André Lureau 2534bdadd86SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 2544bdadd86SMarc-André Lureau class = qdict_get_try_str(error, "class"); 2554bdadd86SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 2564bdadd86SMarc-André Lureau 2574bdadd86SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 258910f738bSMarkus Armbruster g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected"); 2594bdadd86SMarc-André Lureau } 2604bdadd86SMarc-André Lureau 26162c39b30SMarc-André Lureau static void test_qga_invalid_cmd(gconstpointer fix) 26262c39b30SMarc-André Lureau { 26362c39b30SMarc-André Lureau const TestFixture *fixture = fix; 264bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 265bb6960a1SMarc-André Lureau QDict *error; 26662c39b30SMarc-André Lureau const gchar *class, *desc; 26762c39b30SMarc-André Lureau 26862c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); 26962c39b30SMarc-André Lureau g_assert_nonnull(ret); 27062c39b30SMarc-André Lureau 27162c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 27262c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 27362c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 27462c39b30SMarc-André Lureau 27562c39b30SMarc-André Lureau g_assert_cmpstr(class, ==, "CommandNotFound"); 27662c39b30SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 27762c39b30SMarc-André Lureau } 27862c39b30SMarc-André Lureau 27962c39b30SMarc-André Lureau static void test_qga_info(gconstpointer fix) 28062c39b30SMarc-André Lureau { 28162c39b30SMarc-André Lureau const TestFixture *fixture = fix; 282bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 283bb6960a1SMarc-André Lureau QDict *val; 28462c39b30SMarc-André Lureau const gchar *version; 28562c39b30SMarc-André Lureau 28662c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); 28762c39b30SMarc-André Lureau g_assert_nonnull(ret); 28862c39b30SMarc-André Lureau qmp_assert_no_error(ret); 28962c39b30SMarc-André Lureau 29062c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 29162c39b30SMarc-André Lureau version = qdict_get_try_str(val, "version"); 29262c39b30SMarc-André Lureau g_assert_cmpstr(version, ==, QEMU_VERSION); 29362c39b30SMarc-André Lureau } 29462c39b30SMarc-André Lureau 29562c39b30SMarc-André Lureau static void test_qga_get_vcpus(gconstpointer fix) 29662c39b30SMarc-André Lureau { 29762c39b30SMarc-André Lureau const TestFixture *fixture = fix; 298bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 29962c39b30SMarc-André Lureau QList *list; 30062c39b30SMarc-André Lureau const QListEntry *entry; 30162c39b30SMarc-André Lureau 30262c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}"); 30362c39b30SMarc-André Lureau g_assert_nonnull(ret); 30462c39b30SMarc-André Lureau qmp_assert_no_error(ret); 30562c39b30SMarc-André Lureau 30662c39b30SMarc-André Lureau /* check there is at least a cpu */ 30762c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 30862c39b30SMarc-André Lureau entry = qlist_first(list); 3097dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); 3107dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); 31162c39b30SMarc-André Lureau } 31262c39b30SMarc-André Lureau 31362c39b30SMarc-André Lureau static void test_qga_get_fsinfo(gconstpointer fix) 31462c39b30SMarc-André Lureau { 31562c39b30SMarc-André Lureau const TestFixture *fixture = fix; 316bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 31762c39b30SMarc-André Lureau QList *list; 31862c39b30SMarc-André Lureau const QListEntry *entry; 31962c39b30SMarc-André Lureau 32062c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}"); 32162c39b30SMarc-André Lureau g_assert_nonnull(ret); 32262c39b30SMarc-André Lureau qmp_assert_no_error(ret); 32362c39b30SMarc-André Lureau 324b3e9e584SMichael Roth /* sanity-check the response if there are any filesystems */ 32562c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 32662c39b30SMarc-André Lureau entry = qlist_first(list); 327b3e9e584SMichael Roth if (entry) { 3287dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); 3297dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint")); 3307dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type")); 3317dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); 332b3e9e584SMichael Roth } 33362c39b30SMarc-André Lureau } 33462c39b30SMarc-André Lureau 33562c39b30SMarc-André Lureau static void test_qga_get_memory_block_info(gconstpointer fix) 33662c39b30SMarc-André Lureau { 33762c39b30SMarc-André Lureau const TestFixture *fixture = fix; 338bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 339bb6960a1SMarc-André Lureau QDict *val; 34062c39b30SMarc-André Lureau int64_t size; 34162c39b30SMarc-André Lureau 34262c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); 34362c39b30SMarc-André Lureau g_assert_nonnull(ret); 34462c39b30SMarc-André Lureau 34562c39b30SMarc-André Lureau /* some systems might not expose memory block info in sysfs */ 34662c39b30SMarc-André Lureau if (!qdict_haskey(ret, "error")) { 34762c39b30SMarc-André Lureau /* check there is at least some memory */ 34862c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 34962c39b30SMarc-André Lureau size = qdict_get_int(val, "size"); 35062c39b30SMarc-André Lureau g_assert_cmpint(size, >, 0); 35162c39b30SMarc-André Lureau } 35262c39b30SMarc-André Lureau } 35362c39b30SMarc-André Lureau 35462c39b30SMarc-André Lureau static void test_qga_get_memory_blocks(gconstpointer fix) 35562c39b30SMarc-André Lureau { 35662c39b30SMarc-André Lureau const TestFixture *fixture = fix; 357bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 35862c39b30SMarc-André Lureau QList *list; 35962c39b30SMarc-André Lureau const QListEntry *entry; 36062c39b30SMarc-André Lureau 36162c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}"); 36262c39b30SMarc-André Lureau g_assert_nonnull(ret); 36362c39b30SMarc-André Lureau 36462c39b30SMarc-André Lureau /* some systems might not expose memory block info in sysfs */ 36562c39b30SMarc-André Lureau if (!qdict_haskey(ret, "error")) { 36662c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 36762c39b30SMarc-André Lureau entry = qlist_first(list); 36862c39b30SMarc-André Lureau /* newer versions of qga may return empty list without error */ 36962c39b30SMarc-André Lureau if (entry) { 3707dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), 3717dc847ebSMax Reitz "phys-index")); 3727dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); 37362c39b30SMarc-André Lureau } 37462c39b30SMarc-André Lureau } 37562c39b30SMarc-André Lureau } 37662c39b30SMarc-André Lureau 37762c39b30SMarc-André Lureau static void test_qga_network_get_interfaces(gconstpointer fix) 37862c39b30SMarc-André Lureau { 37962c39b30SMarc-André Lureau const TestFixture *fixture = fix; 380bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 38162c39b30SMarc-André Lureau QList *list; 38262c39b30SMarc-André Lureau const QListEntry *entry; 38362c39b30SMarc-André Lureau 38462c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}"); 38562c39b30SMarc-André Lureau g_assert_nonnull(ret); 38662c39b30SMarc-André Lureau qmp_assert_no_error(ret); 38762c39b30SMarc-André Lureau 38862c39b30SMarc-André Lureau /* check there is at least an interface */ 38962c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 39062c39b30SMarc-André Lureau entry = qlist_first(list); 3917dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); 39262c39b30SMarc-André Lureau } 39362c39b30SMarc-André Lureau 39462c39b30SMarc-André Lureau static void test_qga_file_ops(gconstpointer fix) 39562c39b30SMarc-André Lureau { 39662c39b30SMarc-André Lureau const TestFixture *fixture = fix; 3974eaab85cSMarc-André Lureau const unsigned char helloworld[] = "Hello World!\n"; 39862c39b30SMarc-André Lureau const char *b64; 399015715f5SMarkus Armbruster gchar *path, *enc; 4004eaab85cSMarc-André Lureau unsigned char *dec; 40162c39b30SMarc-André Lureau QDict *ret, *val; 40262c39b30SMarc-André Lureau int64_t id, eof; 40362c39b30SMarc-André Lureau gsize count; 40462c39b30SMarc-André Lureau FILE *f; 40562c39b30SMarc-André Lureau char tmp[100]; 40662c39b30SMarc-André Lureau 40762c39b30SMarc-André Lureau /* open */ 40862c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 40962c39b30SMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); 41062c39b30SMarc-André Lureau g_assert_nonnull(ret); 41162c39b30SMarc-André Lureau qmp_assert_no_error(ret); 41262c39b30SMarc-André Lureau id = qdict_get_int(ret, "return"); 413cb3e7f08SMarc-André Lureau qobject_unref(ret); 41462c39b30SMarc-André Lureau 41562c39b30SMarc-André Lureau enc = g_base64_encode(helloworld, sizeof(helloworld)); 41662c39b30SMarc-André Lureau /* write */ 417015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 418015715f5SMarkus Armbruster "{'execute': 'guest-file-write'," 419015715f5SMarkus Armbruster " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }", 420015715f5SMarkus Armbruster id, enc); 42162c39b30SMarc-André Lureau g_assert_nonnull(ret); 42262c39b30SMarc-André Lureau qmp_assert_no_error(ret); 42362c39b30SMarc-André Lureau 42462c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 42562c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 42662c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 42762c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 42862c39b30SMarc-André Lureau g_assert_cmpint(eof, ==, 0); 429cb3e7f08SMarc-André Lureau qobject_unref(ret); 43062c39b30SMarc-André Lureau 43162c39b30SMarc-André Lureau /* flush */ 432015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 433015715f5SMarkus Armbruster "{'execute': 'guest-file-flush'," 43462c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 43562c39b30SMarc-André Lureau id); 436cb3e7f08SMarc-André Lureau qobject_unref(ret); 43762c39b30SMarc-André Lureau 43862c39b30SMarc-André Lureau /* close */ 439015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 440015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 44162c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 44262c39b30SMarc-André Lureau id); 443cb3e7f08SMarc-André Lureau qobject_unref(ret); 44462c39b30SMarc-André Lureau 44562c39b30SMarc-André Lureau /* check content */ 44662c39b30SMarc-André Lureau path = g_build_filename(fixture->test_dir, "foo", NULL); 44762c39b30SMarc-André Lureau f = fopen(path, "r"); 4481e271338SMarc-André Lureau g_free(path); 44962c39b30SMarc-André Lureau g_assert_nonnull(f); 45062c39b30SMarc-André Lureau count = fread(tmp, 1, sizeof(tmp), f); 45162c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 45262c39b30SMarc-André Lureau tmp[count] = 0; 45362c39b30SMarc-André Lureau g_assert_cmpstr(tmp, ==, (char *)helloworld); 45462c39b30SMarc-André Lureau fclose(f); 45562c39b30SMarc-André Lureau 45662c39b30SMarc-André Lureau /* open */ 45762c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 45862c39b30SMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'r' } }"); 45962c39b30SMarc-André Lureau g_assert_nonnull(ret); 46062c39b30SMarc-André Lureau qmp_assert_no_error(ret); 46162c39b30SMarc-André Lureau id = qdict_get_int(ret, "return"); 462cb3e7f08SMarc-André Lureau qobject_unref(ret); 46362c39b30SMarc-André Lureau 46462c39b30SMarc-André Lureau /* read */ 465015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 466015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 46762c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 46862c39b30SMarc-André Lureau id); 46962c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 47062c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 47162c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 47262c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 47362c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 47462c39b30SMarc-André Lureau g_assert(eof); 47562c39b30SMarc-André Lureau g_assert_cmpstr(b64, ==, enc); 47662c39b30SMarc-André Lureau 477cb3e7f08SMarc-André Lureau qobject_unref(ret); 47862c39b30SMarc-André Lureau g_free(enc); 47962c39b30SMarc-André Lureau 48062c39b30SMarc-André Lureau /* read eof */ 481015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 482015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 48362c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 48462c39b30SMarc-André Lureau id); 48562c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 48662c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 48762c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 48862c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 48962c39b30SMarc-André Lureau g_assert_cmpint(count, ==, 0); 49062c39b30SMarc-André Lureau g_assert(eof); 49162c39b30SMarc-André Lureau g_assert_cmpstr(b64, ==, ""); 492cb3e7f08SMarc-André Lureau qobject_unref(ret); 49362c39b30SMarc-André Lureau 49462c39b30SMarc-André Lureau /* seek */ 495015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 496015715f5SMarkus Armbruster "{'execute': 'guest-file-seek'," 49762c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 ", " 498015715f5SMarkus Armbruster " 'offset': %d, 'whence': %s } }", 4990b4b4938SEric Blake id, 6, "set"); 50062c39b30SMarc-André Lureau qmp_assert_no_error(ret); 50162c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 50262c39b30SMarc-André Lureau count = qdict_get_int(val, "position"); 50362c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 50462c39b30SMarc-André Lureau g_assert_cmpint(count, ==, 6); 50562c39b30SMarc-André Lureau g_assert(!eof); 506cb3e7f08SMarc-André Lureau qobject_unref(ret); 50762c39b30SMarc-André Lureau 50862c39b30SMarc-André Lureau /* partial read */ 509015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 510015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 51162c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 51262c39b30SMarc-André Lureau id); 51362c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 51462c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 51562c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 51662c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 51762c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld) - 6); 51862c39b30SMarc-André Lureau g_assert(eof); 51962c39b30SMarc-André Lureau dec = g_base64_decode(b64, &count); 52062c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld) - 6); 52162c39b30SMarc-André Lureau g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6); 52262c39b30SMarc-André Lureau g_free(dec); 52362c39b30SMarc-André Lureau 524cb3e7f08SMarc-André Lureau qobject_unref(ret); 52562c39b30SMarc-André Lureau 52662c39b30SMarc-André Lureau /* close */ 527015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 528015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 52962c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 53062c39b30SMarc-André Lureau id); 531cb3e7f08SMarc-André Lureau qobject_unref(ret); 53262c39b30SMarc-André Lureau } 53362c39b30SMarc-André Lureau 5344eaab85cSMarc-André Lureau static void test_qga_file_write_read(gconstpointer fix) 5354eaab85cSMarc-André Lureau { 5364eaab85cSMarc-André Lureau const TestFixture *fixture = fix; 5374eaab85cSMarc-André Lureau const unsigned char helloworld[] = "Hello World!\n"; 5384eaab85cSMarc-André Lureau const char *b64; 539015715f5SMarkus Armbruster gchar *enc; 5404eaab85cSMarc-André Lureau QDict *ret, *val; 5414eaab85cSMarc-André Lureau int64_t id, eof; 5424eaab85cSMarc-André Lureau gsize count; 5434eaab85cSMarc-André Lureau 5444eaab85cSMarc-André Lureau /* open */ 5454eaab85cSMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 5464eaab85cSMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); 5474eaab85cSMarc-André Lureau g_assert_nonnull(ret); 5484eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 5494eaab85cSMarc-André Lureau id = qdict_get_int(ret, "return"); 550cb3e7f08SMarc-André Lureau qobject_unref(ret); 5514eaab85cSMarc-André Lureau 5524eaab85cSMarc-André Lureau enc = g_base64_encode(helloworld, sizeof(helloworld)); 5534eaab85cSMarc-André Lureau /* write */ 554015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 555015715f5SMarkus Armbruster "{'execute': 'guest-file-write'," 5564eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "," 557015715f5SMarkus Armbruster " 'buf-b64': %s } }", id, enc); 5584eaab85cSMarc-André Lureau g_assert_nonnull(ret); 5594eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 5604eaab85cSMarc-André Lureau 5614eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 5624eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 5634eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 5644eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 5654eaab85cSMarc-André Lureau g_assert_cmpint(eof, ==, 0); 566cb3e7f08SMarc-André Lureau qobject_unref(ret); 5674eaab85cSMarc-André Lureau 5684eaab85cSMarc-André Lureau /* read (check implicit flush) */ 569015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 570015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 5714eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 5724eaab85cSMarc-André Lureau id); 5734eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 5744eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 5754eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 5764eaab85cSMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 5774eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, 0); 5784eaab85cSMarc-André Lureau g_assert(eof); 5794eaab85cSMarc-André Lureau g_assert_cmpstr(b64, ==, ""); 580cb3e7f08SMarc-André Lureau qobject_unref(ret); 5814eaab85cSMarc-André Lureau 5824eaab85cSMarc-André Lureau /* seek to 0 */ 583015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 584015715f5SMarkus Armbruster "{'execute': 'guest-file-seek'," 5854eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 ", " 586015715f5SMarkus Armbruster " 'offset': %d, 'whence': %s } }", 5870b4b4938SEric Blake id, 0, "set"); 5884eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 5894eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 5904eaab85cSMarc-André Lureau count = qdict_get_int(val, "position"); 5914eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 5924eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, 0); 5934eaab85cSMarc-André Lureau g_assert(!eof); 594cb3e7f08SMarc-André Lureau qobject_unref(ret); 5954eaab85cSMarc-André Lureau 5964eaab85cSMarc-André Lureau /* read */ 597015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 598015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 5994eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 6004eaab85cSMarc-André Lureau id); 6014eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 6024eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 6034eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 6044eaab85cSMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 6054eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 6064eaab85cSMarc-André Lureau g_assert(eof); 6074eaab85cSMarc-André Lureau g_assert_cmpstr(b64, ==, enc); 608cb3e7f08SMarc-André Lureau qobject_unref(ret); 6094eaab85cSMarc-André Lureau g_free(enc); 6104eaab85cSMarc-André Lureau 6114eaab85cSMarc-André Lureau /* close */ 612015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 613015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 6144eaab85cSMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 6154eaab85cSMarc-André Lureau id); 616cb3e7f08SMarc-André Lureau qobject_unref(ret); 6174eaab85cSMarc-André Lureau } 6184eaab85cSMarc-André Lureau 61962c39b30SMarc-André Lureau static void test_qga_get_time(gconstpointer fix) 62062c39b30SMarc-André Lureau { 62162c39b30SMarc-André Lureau const TestFixture *fixture = fix; 622bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 62362c39b30SMarc-André Lureau int64_t time; 62462c39b30SMarc-André Lureau 62562c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); 62662c39b30SMarc-André Lureau g_assert_nonnull(ret); 62762c39b30SMarc-André Lureau qmp_assert_no_error(ret); 62862c39b30SMarc-André Lureau 62962c39b30SMarc-André Lureau time = qdict_get_int(ret, "return"); 63062c39b30SMarc-André Lureau g_assert_cmpint(time, >, 0); 63162c39b30SMarc-André Lureau } 63262c39b30SMarc-André Lureau 633ebf70554SThomas Huth static void test_qga_blockedrpcs(gconstpointer data) 63462c39b30SMarc-André Lureau { 63562c39b30SMarc-André Lureau TestFixture fix; 63662c39b30SMarc-André Lureau QDict *ret, *error; 63762c39b30SMarc-André Lureau const gchar *class, *desc; 63862c39b30SMarc-André Lureau 639c28afa76STomáš Golembiovský fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL); 64062c39b30SMarc-André Lureau 641ebf70554SThomas Huth /* check blocked RPCs */ 64262c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); 64362c39b30SMarc-André Lureau g_assert_nonnull(ret); 64462c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 64562c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 64662c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 6472546be1cSMichal Privoznik g_assert_cmpstr(class, ==, "CommandNotFound"); 64862c39b30SMarc-André Lureau g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); 649cb3e7f08SMarc-André Lureau qobject_unref(ret); 65062c39b30SMarc-André Lureau 65162c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); 65262c39b30SMarc-André Lureau g_assert_nonnull(ret); 65362c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 65462c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 65562c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 6562546be1cSMichal Privoznik g_assert_cmpstr(class, ==, "CommandNotFound"); 65762c39b30SMarc-André Lureau g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); 658cb3e7f08SMarc-André Lureau qobject_unref(ret); 65962c39b30SMarc-André Lureau 66062c39b30SMarc-André Lureau /* check something work */ 66162c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); 66262c39b30SMarc-André Lureau qmp_assert_no_error(ret); 663cb3e7f08SMarc-André Lureau qobject_unref(ret); 66462c39b30SMarc-André Lureau 66562c39b30SMarc-André Lureau fixture_tear_down(&fix, NULL); 66662c39b30SMarc-André Lureau } 66762c39b30SMarc-André Lureau 668fcd1ab3aSKonstantin Kostiuk static void test_qga_allowedrpcs(gconstpointer data) 669fcd1ab3aSKonstantin Kostiuk { 670fcd1ab3aSKonstantin Kostiuk TestFixture fix; 671fcd1ab3aSKonstantin Kostiuk QDict *ret, *error; 672fcd1ab3aSKonstantin Kostiuk const gchar *class, *desc; 673fcd1ab3aSKonstantin Kostiuk 674fcd1ab3aSKonstantin Kostiuk fixture_setup(&fix, "-a guest-ping,guest-get-time", NULL); 675fcd1ab3aSKonstantin Kostiuk 676fcd1ab3aSKonstantin Kostiuk /* check allowed RPCs */ 677fcd1ab3aSKonstantin Kostiuk ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); 678fcd1ab3aSKonstantin Kostiuk qmp_assert_no_error(ret); 679fcd1ab3aSKonstantin Kostiuk qobject_unref(ret); 680fcd1ab3aSKonstantin Kostiuk 681fcd1ab3aSKonstantin Kostiuk ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); 682fcd1ab3aSKonstantin Kostiuk qmp_assert_no_error(ret); 683fcd1ab3aSKonstantin Kostiuk qobject_unref(ret); 684fcd1ab3aSKonstantin Kostiuk 685fcd1ab3aSKonstantin Kostiuk /* check something else */ 686fcd1ab3aSKonstantin Kostiuk ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); 687fcd1ab3aSKonstantin Kostiuk g_assert_nonnull(ret); 688fcd1ab3aSKonstantin Kostiuk error = qdict_get_qdict(ret, "error"); 689fcd1ab3aSKonstantin Kostiuk class = qdict_get_try_str(error, "class"); 690fcd1ab3aSKonstantin Kostiuk desc = qdict_get_try_str(error, "desc"); 691fcd1ab3aSKonstantin Kostiuk g_assert_cmpstr(class, ==, "CommandNotFound"); 692fcd1ab3aSKonstantin Kostiuk g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); 693fcd1ab3aSKonstantin Kostiuk qobject_unref(ret); 694fcd1ab3aSKonstantin Kostiuk 695fcd1ab3aSKonstantin Kostiuk fixture_tear_down(&fix, NULL); 696fcd1ab3aSKonstantin Kostiuk } 697fcd1ab3aSKonstantin Kostiuk 69862c39b30SMarc-André Lureau static void test_qga_config(gconstpointer data) 69962c39b30SMarc-André Lureau { 70062c39b30SMarc-André Lureau GError *error = NULL; 701bb6960a1SMarc-André Lureau g_autofree char *out = NULL; 702bb6960a1SMarc-André Lureau g_autofree char *err = NULL; 703bb6960a1SMarc-André Lureau g_autofree char *cwd = NULL; 704bb6960a1SMarc-André Lureau g_autofree char *cmd = NULL; 705bb6960a1SMarc-André Lureau g_auto(GStrv) argv = NULL; 706bb6960a1SMarc-André Lureau g_auto(GStrv) strv = NULL; 707bb6960a1SMarc-André Lureau g_autoptr(GKeyFile) kf = NULL; 708bb6960a1SMarc-André Lureau char *str; 70962c39b30SMarc-André Lureau char *env[2]; 7101741b945SMarc-André Lureau int status; 71162c39b30SMarc-André Lureau gsize n; 71262c39b30SMarc-André Lureau 71362c39b30SMarc-André Lureau cwd = g_get_current_dir(); 714f15bff25SPaolo Bonzini cmd = g_strdup_printf("%s%cqga%cqemu-ga -D", 715f15bff25SPaolo Bonzini cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR); 71662c39b30SMarc-André Lureau g_shell_parse_argv(cmd, NULL, &argv, &error); 71762c39b30SMarc-André Lureau g_assert_no_error(error); 71862c39b30SMarc-André Lureau 7191741b945SMarc-André Lureau env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config", 7201741b945SMarc-André Lureau G_DIR_SEPARATOR, G_DIR_SEPARATOR); 72162c39b30SMarc-André Lureau env[1] = NULL; 72262c39b30SMarc-André Lureau g_spawn_sync(NULL, argv, env, 0, 72362c39b30SMarc-André Lureau NULL, NULL, &out, &err, &status, &error); 7241e271338SMarc-André Lureau 72562c39b30SMarc-André Lureau g_assert_no_error(error); 72662c39b30SMarc-André Lureau g_assert_cmpstr(err, ==, ""); 72762c39b30SMarc-André Lureau g_assert_cmpint(status, ==, 0); 72862c39b30SMarc-André Lureau 72962c39b30SMarc-André Lureau kf = g_key_file_new(); 73062c39b30SMarc-André Lureau g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error); 73162c39b30SMarc-André Lureau g_assert_no_error(error); 73262c39b30SMarc-André Lureau 73362c39b30SMarc-André Lureau str = g_key_file_get_start_group(kf); 73462c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "general"); 73562c39b30SMarc-André Lureau g_free(str); 73662c39b30SMarc-André Lureau 73762c39b30SMarc-André Lureau g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error)); 73862c39b30SMarc-André Lureau g_assert_no_error(error); 73962c39b30SMarc-André Lureau 74062c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "method", &error); 74162c39b30SMarc-André Lureau g_assert_no_error(error); 74262c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "virtio-serial"); 74362c39b30SMarc-André Lureau g_free(str); 74462c39b30SMarc-André Lureau 74562c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "path", &error); 74662c39b30SMarc-André Lureau g_assert_no_error(error); 74762c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0"); 74862c39b30SMarc-André Lureau g_free(str); 74962c39b30SMarc-André Lureau 75062c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "pidfile", &error); 75162c39b30SMarc-André Lureau g_assert_no_error(error); 75262c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid"); 75362c39b30SMarc-André Lureau g_free(str); 75462c39b30SMarc-André Lureau 75562c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "statedir", &error); 75662c39b30SMarc-André Lureau g_assert_no_error(error); 75762c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/var/state"); 75862c39b30SMarc-André Lureau g_free(str); 75962c39b30SMarc-André Lureau 76062c39b30SMarc-André Lureau g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error)); 76162c39b30SMarc-André Lureau g_assert_no_error(error); 76262c39b30SMarc-André Lureau 763582a098eSThomas Huth strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error); 76462c39b30SMarc-André Lureau g_assert_cmpint(n, ==, 2); 76562c39b30SMarc-André Lureau g_assert_true(g_strv_contains((const char * const *)strv, 76662c39b30SMarc-André Lureau "guest-ping")); 76762c39b30SMarc-André Lureau g_assert_true(g_strv_contains((const char * const *)strv, 76862c39b30SMarc-André Lureau "guest-get-time")); 76962c39b30SMarc-André Lureau g_assert_no_error(error); 77062c39b30SMarc-André Lureau 77162c39b30SMarc-André Lureau g_free(env[0]); 77262c39b30SMarc-André Lureau } 77362c39b30SMarc-André Lureau 77462c39b30SMarc-André Lureau static void test_qga_fsfreeze_status(gconstpointer fix) 77562c39b30SMarc-André Lureau { 77662c39b30SMarc-André Lureau const TestFixture *fixture = fix; 777bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 77862c39b30SMarc-André Lureau const gchar *status; 77962c39b30SMarc-André Lureau 78062c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); 78162c39b30SMarc-André Lureau g_assert_nonnull(ret); 78262c39b30SMarc-André Lureau qmp_assert_no_error(ret); 78362c39b30SMarc-André Lureau 78462c39b30SMarc-André Lureau status = qdict_get_try_str(ret, "return"); 78562c39b30SMarc-André Lureau g_assert_cmpstr(status, ==, "thawed"); 78662c39b30SMarc-André Lureau } 78762c39b30SMarc-André Lureau 788c7d74f27SDaniel Xu static QDict *wait_for_guest_exec_completion(int fd, int64_t pid) 7893dab9fa1SMarc-André Lureau { 790c7d74f27SDaniel Xu QDict *ret = NULL; 791c7d74f27SDaniel Xu int64_t now; 7923dab9fa1SMarc-André Lureau bool exited; 793c7d74f27SDaniel Xu QDict *val; 7943dab9fa1SMarc-André Lureau 7953dab9fa1SMarc-André Lureau now = g_get_monotonic_time(); 7961792d7d0SEric Blake do { 797c7d74f27SDaniel Xu ret = qmp_fd(fd, 798015715f5SMarkus Armbruster "{'execute': 'guest-exec-status'," 799015715f5SMarkus Armbruster " 'arguments': { 'pid': %" PRId64 " } }", pid); 8003dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 8013dab9fa1SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 8023dab9fa1SMarc-André Lureau exited = qdict_get_bool(val, "exited"); 8033dab9fa1SMarc-André Lureau if (!exited) { 804cb3e7f08SMarc-André Lureau qobject_unref(ret); 8053dab9fa1SMarc-André Lureau } 8063dab9fa1SMarc-André Lureau } while (!exited && 8073dab9fa1SMarc-André Lureau g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND); 8083dab9fa1SMarc-André Lureau g_assert(exited); 8093dab9fa1SMarc-André Lureau 810c7d74f27SDaniel Xu return ret; 811c7d74f27SDaniel Xu } 812c7d74f27SDaniel Xu 813c7d74f27SDaniel Xu static void test_qga_guest_exec(gconstpointer fix) 814c7d74f27SDaniel Xu { 815c7d74f27SDaniel Xu const TestFixture *fixture = fix; 816c7d74f27SDaniel Xu g_autoptr(QDict) ret = NULL; 817c7d74f27SDaniel Xu QDict *val; 818c7d74f27SDaniel Xu const gchar *out; 819c7d74f27SDaniel Xu g_autofree guchar *decoded = NULL; 820c7d74f27SDaniel Xu int64_t pid, exitcode; 821c7d74f27SDaniel Xu gsize len; 822c7d74f27SDaniel Xu 823c7d74f27SDaniel Xu /* exec 'echo foo bar' */ 824c7d74f27SDaniel Xu ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 8258c72e19bSSamuel Tardieu " 'path': 'echo', 'arg': [ '-n', '\" test_str \"' ]," 826c7d74f27SDaniel Xu " 'capture-output': true } }"); 827c7d74f27SDaniel Xu g_assert_nonnull(ret); 828c7d74f27SDaniel Xu qmp_assert_no_error(ret); 829c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 830c7d74f27SDaniel Xu pid = qdict_get_int(val, "pid"); 831c7d74f27SDaniel Xu g_assert_cmpint(pid, >, 0); 832c7d74f27SDaniel Xu qobject_unref(ret); 833c7d74f27SDaniel Xu 834c7d74f27SDaniel Xu ret = wait_for_guest_exec_completion(fixture->fd, pid); 835c7d74f27SDaniel Xu 8363dab9fa1SMarc-André Lureau /* check stdout */ 837c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 8383dab9fa1SMarc-André Lureau exitcode = qdict_get_int(val, "exitcode"); 8393dab9fa1SMarc-André Lureau g_assert_cmpint(exitcode, ==, 0); 8403dab9fa1SMarc-André Lureau out = qdict_get_str(val, "out-data"); 8413dab9fa1SMarc-André Lureau decoded = g_base64_decode(out, &len); 8423dab9fa1SMarc-André Lureau g_assert_cmpint(len, ==, 12); 8433dab9fa1SMarc-André Lureau g_assert_cmpstr((char *)decoded, ==, "\" test_str \""); 8443dab9fa1SMarc-André Lureau } 8453dab9fa1SMarc-André Lureau 846c7d74f27SDaniel Xu #if defined(G_OS_WIN32) 847c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix) 848c7d74f27SDaniel Xu { 849c7d74f27SDaniel Xu } 850c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix) 851c7d74f27SDaniel Xu { 852c7d74f27SDaniel Xu const TestFixture *fixture = fix; 853c7d74f27SDaniel Xu g_autoptr(QDict) ret = NULL; 854c7d74f27SDaniel Xu QDict *val; 855c7d74f27SDaniel Xu const gchar *class, *desc; 856c7d74f27SDaniel Xu g_autofree guchar *decoded = NULL; 857c7d74f27SDaniel Xu 858c7d74f27SDaniel Xu /* exec 'echo foo bar' */ 859c7d74f27SDaniel Xu ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 860c7d74f27SDaniel Xu " 'path': 'echo'," 861c7d74f27SDaniel Xu " 'arg': [ 'execution never reaches here' ]," 862c7d74f27SDaniel Xu " 'capture-output': 'merged' } }"); 863c7d74f27SDaniel Xu 864c7d74f27SDaniel Xu g_assert_nonnull(ret); 865c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "error"); 866c7d74f27SDaniel Xu g_assert_nonnull(val); 867c7d74f27SDaniel Xu class = qdict_get_str(val, "class"); 868c7d74f27SDaniel Xu desc = qdict_get_str(val, "desc"); 869c7d74f27SDaniel Xu g_assert_cmpstr(class, ==, "GenericError"); 870c7d74f27SDaniel Xu g_assert_cmpint(strlen(desc), >, 0); 871c7d74f27SDaniel Xu } 872c7d74f27SDaniel Xu #else 873c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix) 874c7d74f27SDaniel Xu { 875c7d74f27SDaniel Xu const TestFixture *fixture = fix; 876c7d74f27SDaniel Xu g_autoptr(QDict) ret = NULL; 877c7d74f27SDaniel Xu QDict *val; 878c7d74f27SDaniel Xu const gchar *out, *err; 879c7d74f27SDaniel Xu g_autofree guchar *out_decoded = NULL; 880c7d74f27SDaniel Xu g_autofree guchar *err_decoded = NULL; 881c7d74f27SDaniel Xu int64_t pid, exitcode; 882c7d74f27SDaniel Xu gsize len; 883c7d74f27SDaniel Xu 884c7d74f27SDaniel Xu /* exec 'echo foo bar' */ 885c7d74f27SDaniel Xu ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 8868c72e19bSSamuel Tardieu " 'path': 'bash'," 887c7d74f27SDaniel Xu " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ]," 888c7d74f27SDaniel Xu " 'capture-output': 'separated' } }"); 889c7d74f27SDaniel Xu g_assert_nonnull(ret); 890c7d74f27SDaniel Xu qmp_assert_no_error(ret); 891c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 892c7d74f27SDaniel Xu pid = qdict_get_int(val, "pid"); 893c7d74f27SDaniel Xu g_assert_cmpint(pid, >, 0); 894c7d74f27SDaniel Xu qobject_unref(ret); 895c7d74f27SDaniel Xu 896c7d74f27SDaniel Xu ret = wait_for_guest_exec_completion(fixture->fd, pid); 897c7d74f27SDaniel Xu 898c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 899c7d74f27SDaniel Xu exitcode = qdict_get_int(val, "exitcode"); 900c7d74f27SDaniel Xu g_assert_cmpint(exitcode, ==, 0); 901c7d74f27SDaniel Xu 902c7d74f27SDaniel Xu /* check stdout */ 903c7d74f27SDaniel Xu out = qdict_get_str(val, "out-data"); 904c7d74f27SDaniel Xu out_decoded = g_base64_decode(out, &len); 905c7d74f27SDaniel Xu g_assert_cmpint(len, ==, 14); 906c7d74f27SDaniel Xu g_assert_cmpstr((char *)out_decoded, ==, "stdout\nstdout\n"); 907c7d74f27SDaniel Xu 908c7d74f27SDaniel Xu /* check stderr */ 909c7d74f27SDaniel Xu err = qdict_get_try_str(val, "err-data"); 910c7d74f27SDaniel Xu err_decoded = g_base64_decode(err, &len); 911c7d74f27SDaniel Xu g_assert_cmpint(len, ==, 14); 912c7d74f27SDaniel Xu g_assert_cmpstr((char *)err_decoded, ==, "stderr\nstderr\n"); 913c7d74f27SDaniel Xu } 914c7d74f27SDaniel Xu 915c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix) 916c7d74f27SDaniel Xu { 917c7d74f27SDaniel Xu const TestFixture *fixture = fix; 918c7d74f27SDaniel Xu g_autoptr(QDict) ret = NULL; 919c7d74f27SDaniel Xu QDict *val; 920c7d74f27SDaniel Xu const gchar *out, *err; 921c7d74f27SDaniel Xu g_autofree guchar *decoded = NULL; 922c7d74f27SDaniel Xu int64_t pid, exitcode; 923c7d74f27SDaniel Xu gsize len; 924c7d74f27SDaniel Xu 925c7d74f27SDaniel Xu /* exec 'echo foo bar' */ 926c7d74f27SDaniel Xu ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 9278c72e19bSSamuel Tardieu " 'path': 'bash'," 928c7d74f27SDaniel Xu " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ]," 929c7d74f27SDaniel Xu " 'capture-output': 'merged' } }"); 930c7d74f27SDaniel Xu g_assert_nonnull(ret); 931c7d74f27SDaniel Xu qmp_assert_no_error(ret); 932c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 933c7d74f27SDaniel Xu pid = qdict_get_int(val, "pid"); 934c7d74f27SDaniel Xu g_assert_cmpint(pid, >, 0); 935c7d74f27SDaniel Xu qobject_unref(ret); 936c7d74f27SDaniel Xu 937c7d74f27SDaniel Xu ret = wait_for_guest_exec_completion(fixture->fd, pid); 938c7d74f27SDaniel Xu 939c7d74f27SDaniel Xu val = qdict_get_qdict(ret, "return"); 940c7d74f27SDaniel Xu exitcode = qdict_get_int(val, "exitcode"); 941c7d74f27SDaniel Xu g_assert_cmpint(exitcode, ==, 0); 942c7d74f27SDaniel Xu 943c7d74f27SDaniel Xu /* check stdout */ 944c7d74f27SDaniel Xu out = qdict_get_str(val, "out-data"); 945c7d74f27SDaniel Xu decoded = g_base64_decode(out, &len); 946c7d74f27SDaniel Xu g_assert_cmpint(len, ==, 28); 947c7d74f27SDaniel Xu g_assert_cmpstr((char *)decoded, ==, "stdout\nstderr\nstdout\nstderr\n"); 948c7d74f27SDaniel Xu 949c7d74f27SDaniel Xu /* check stderr */ 950c7d74f27SDaniel Xu err = qdict_get_try_str(val, "err-data"); 951c7d74f27SDaniel Xu g_assert_null(err); 952c7d74f27SDaniel Xu } 953c7d74f27SDaniel Xu #endif 954c7d74f27SDaniel Xu 9553dab9fa1SMarc-André Lureau static void test_qga_guest_exec_invalid(gconstpointer fix) 9563dab9fa1SMarc-André Lureau { 9573dab9fa1SMarc-André Lureau const TestFixture *fixture = fix; 958bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 959bb6960a1SMarc-André Lureau QDict *error; 9603dab9fa1SMarc-André Lureau const gchar *class, *desc; 9613dab9fa1SMarc-André Lureau 9623dab9fa1SMarc-André Lureau /* invalid command */ 9633dab9fa1SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 9643dab9fa1SMarc-André Lureau " 'path': '/bin/invalid-cmd42' } }"); 9653dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 9663dab9fa1SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 9673dab9fa1SMarc-André Lureau g_assert_nonnull(error); 9683dab9fa1SMarc-André Lureau class = qdict_get_str(error, "class"); 9693dab9fa1SMarc-André Lureau desc = qdict_get_str(error, "desc"); 9703dab9fa1SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 9713dab9fa1SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 972cb3e7f08SMarc-André Lureau qobject_unref(ret); 9733dab9fa1SMarc-André Lureau 9743dab9fa1SMarc-André Lureau /* invalid pid */ 9753dab9fa1SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status'," 9763dab9fa1SMarc-André Lureau " 'arguments': { 'pid': 0 } }"); 9773dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 9783dab9fa1SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 9793dab9fa1SMarc-André Lureau g_assert_nonnull(error); 9803dab9fa1SMarc-André Lureau class = qdict_get_str(error, "class"); 9813dab9fa1SMarc-André Lureau desc = qdict_get_str(error, "desc"); 9823dab9fa1SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 9833dab9fa1SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 9843dab9fa1SMarc-André Lureau } 9853dab9fa1SMarc-André Lureau 986509b97fdSTomáš Golembiovský static void test_qga_guest_get_host_name(gconstpointer fix) 987509b97fdSTomáš Golembiovský { 988509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 989bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 990bb6960a1SMarc-André Lureau QDict *val; 991509b97fdSTomáš Golembiovský 992509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}"); 993509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 994509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 995509b97fdSTomáš Golembiovský 996509b97fdSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 997509b97fdSTomáš Golembiovský g_assert(qdict_haskey(val, "host-name")); 998509b97fdSTomáš Golembiovský } 999509b97fdSTomáš Golembiovský 1000509b97fdSTomáš Golembiovský static void test_qga_guest_get_timezone(gconstpointer fix) 1001509b97fdSTomáš Golembiovský { 1002509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 1003bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 1004bb6960a1SMarc-André Lureau QDict *val; 1005509b97fdSTomáš Golembiovský 1006509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}"); 1007509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 1008509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 1009509b97fdSTomáš Golembiovský 1010509b97fdSTomáš Golembiovský /* Make sure there's at least offset */ 1011509b97fdSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 1012509b97fdSTomáš Golembiovský g_assert(qdict_haskey(val, "offset")); 1013509b97fdSTomáš Golembiovský } 1014509b97fdSTomáš Golembiovský 1015509b97fdSTomáš Golembiovský static void test_qga_guest_get_users(gconstpointer fix) 1016509b97fdSTomáš Golembiovský { 1017509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 1018bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 1019509b97fdSTomáš Golembiovský QList *val; 1020509b97fdSTomáš Golembiovský 1021509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}"); 1022509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 1023509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 1024509b97fdSTomáš Golembiovský 1025509b97fdSTomáš Golembiovský /* There is not much to test here */ 1026509b97fdSTomáš Golembiovský val = qdict_get_qlist(ret, "return"); 1027509b97fdSTomáš Golembiovský g_assert_nonnull(val); 1028509b97fdSTomáš Golembiovský } 1029509b97fdSTomáš Golembiovský 1030339ca68bSTomáš Golembiovský static void test_qga_guest_get_osinfo(gconstpointer data) 1031339ca68bSTomáš Golembiovský { 1032339ca68bSTomáš Golembiovský TestFixture fixture; 1033339ca68bSTomáš Golembiovský const gchar *str; 1034bb6960a1SMarc-André Lureau g_autoptr(QDict) ret = NULL; 1035a85d0926SMarc-André Lureau char *env[2]; 1036a85d0926SMarc-André Lureau QDict *val; 1037339ca68bSTomáš Golembiovský 1038339ca68bSTomáš Golembiovský env[0] = g_strdup_printf( 1039a85d0926SMarc-André Lureau "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release", 1040a85d0926SMarc-André Lureau g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); 1041339ca68bSTomáš Golembiovský env[1] = NULL; 1042339ca68bSTomáš Golembiovský fixture_setup(&fixture, NULL, env); 1043339ca68bSTomáš Golembiovský 1044339ca68bSTomáš Golembiovský ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}"); 1045339ca68bSTomáš Golembiovský g_assert_nonnull(ret); 1046339ca68bSTomáš Golembiovský qmp_assert_no_error(ret); 1047339ca68bSTomáš Golembiovský 1048339ca68bSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 1049339ca68bSTomáš Golembiovský 1050339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "id"); 1051339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1052339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "qemu-ga-test"); 1053339ca68bSTomáš Golembiovský 1054339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "name"); 1055339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1056339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "QEMU-GA"); 1057339ca68bSTomáš Golembiovský 1058339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "pretty-name"); 1059339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1060339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "QEMU Guest Agent test"); 1061339ca68bSTomáš Golembiovský 1062339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "version"); 1063339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1064339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "Test 1"); 1065339ca68bSTomáš Golembiovský 1066339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "version-id"); 1067339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1068339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "1"); 1069339ca68bSTomáš Golembiovský 1070339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "variant"); 1071339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1072339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc."); 1073339ca68bSTomáš Golembiovský 1074339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "variant-id"); 1075339ca68bSTomáš Golembiovský g_assert_nonnull(str); 1076339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "unit-test"); 1077339ca68bSTomáš Golembiovský 1078339ca68bSTomáš Golembiovský g_free(env[0]); 1079339ca68bSTomáš Golembiovský fixture_tear_down(&fixture, NULL); 1080339ca68bSTomáš Golembiovský } 1081339ca68bSTomáš Golembiovský 108262c39b30SMarc-André Lureau int main(int argc, char **argv) 108362c39b30SMarc-André Lureau { 108462c39b30SMarc-André Lureau TestFixture fix; 108562c39b30SMarc-André Lureau int ret; 108662c39b30SMarc-André Lureau 1087a7bd942cSMarc-André Lureau #ifdef QEMU_SANITIZE_THREAD 1088a7bd942cSMarc-André Lureau { 1089a7bd942cSMarc-André Lureau g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116"); 1090a7bd942cSMarc-André Lureau return 0; 1091a7bd942cSMarc-André Lureau } 1092a7bd942cSMarc-André Lureau #endif 1093a7bd942cSMarc-André Lureau 109462c39b30SMarc-André Lureau setlocale (LC_ALL, ""); 109562c39b30SMarc-André Lureau g_test_init(&argc, &argv, NULL); 1096c28afa76STomáš Golembiovský fixture_setup(&fix, NULL, NULL); 109762c39b30SMarc-André Lureau 109862c39b30SMarc-André Lureau g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited); 109962c39b30SMarc-André Lureau g_test_add_data_func("/qga/sync", &fix, test_qga_sync); 110062c39b30SMarc-André Lureau g_test_add_data_func("/qga/ping", &fix, test_qga_ping); 110162c39b30SMarc-André Lureau g_test_add_data_func("/qga/info", &fix, test_qga_info); 110262c39b30SMarc-André Lureau g_test_add_data_func("/qga/network-get-interfaces", &fix, 110362c39b30SMarc-André Lureau test_qga_network_get_interfaces); 1104ec72c0e2SBruce Rogers if (!access("/sys/devices/system/cpu/cpu0", F_OK)) { 110562c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus); 1106ec72c0e2SBruce Rogers } 110762c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo); 110862c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-memory-block-info", &fix, 110962c39b30SMarc-André Lureau test_qga_get_memory_block_info); 111062c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-memory-blocks", &fix, 111162c39b30SMarc-André Lureau test_qga_get_memory_blocks); 111262c39b30SMarc-André Lureau g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops); 11134eaab85cSMarc-André Lureau g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read); 111462c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); 11154eaca8deSMarc-André Lureau g_test_add_data_func("/qga/id", &fix, test_qga_id); 1116d4d7ed73SMarkus Armbruster g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob); 111762c39b30SMarc-André Lureau g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); 11184bdadd86SMarc-André Lureau g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args); 111962c39b30SMarc-André Lureau g_test_add_data_func("/qga/fsfreeze-status", &fix, 112062c39b30SMarc-André Lureau test_qga_fsfreeze_status); 112162c39b30SMarc-André Lureau 1122ebf70554SThomas Huth g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs); 1123fcd1ab3aSKonstantin Kostiuk g_test_add_data_func("/qga/allowedrpcs", NULL, test_qga_allowedrpcs); 112462c39b30SMarc-André Lureau g_test_add_data_func("/qga/config", NULL, test_qga_config); 11253dab9fa1SMarc-André Lureau g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec); 1126c7d74f27SDaniel Xu g_test_add_data_func("/qga/guest-exec-separated", &fix, 1127c7d74f27SDaniel Xu test_qga_guest_exec_separated); 1128c7d74f27SDaniel Xu g_test_add_data_func("/qga/guest-exec-merged", &fix, 1129c7d74f27SDaniel Xu test_qga_guest_exec_merged); 11303dab9fa1SMarc-André Lureau g_test_add_data_func("/qga/guest-exec-invalid", &fix, 11313dab9fa1SMarc-André Lureau test_qga_guest_exec_invalid); 1132339ca68bSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-osinfo", &fix, 1133339ca68bSTomáš Golembiovský test_qga_guest_get_osinfo); 1134509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-host-name", &fix, 1135509b97fdSTomáš Golembiovský test_qga_guest_get_host_name); 1136509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-timezone", &fix, 1137509b97fdSTomáš Golembiovský test_qga_guest_get_timezone); 1138509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-users", &fix, 1139509b97fdSTomáš Golembiovský test_qga_guest_get_users); 114062c39b30SMarc-André Lureau 114162c39b30SMarc-André Lureau ret = g_test_run(); 114262c39b30SMarc-André Lureau 114362c39b30SMarc-André Lureau fixture_tear_down(&fix, NULL); 114462c39b30SMarc-André Lureau 114562c39b30SMarc-André Lureau return ret; 114662c39b30SMarc-André Lureau } 1147