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" 8452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 947e6b297SMarkus Armbruster #include "qapi/qmp/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) { 3562c39b30SMarc-André Lureau return -1; 3662c39b30SMarc-André Lureau } 3762c39b30SMarc-André Lureau } while (ret == -1); 3862c39b30SMarc-André Lureau 3962c39b30SMarc-André Lureau return s; 4062c39b30SMarc-André Lureau } 4162c39b30SMarc-André Lureau 4262c39b30SMarc-André Lureau static void qga_watch(GPid pid, gint status, gpointer user_data) 4362c39b30SMarc-André Lureau { 4462c39b30SMarc-André Lureau TestFixture *fixture = user_data; 4562c39b30SMarc-André Lureau 4662c39b30SMarc-André Lureau g_assert_cmpint(status, ==, 0); 4762c39b30SMarc-André Lureau g_main_loop_quit(fixture->loop); 4862c39b30SMarc-André Lureau } 4962c39b30SMarc-André Lureau 5062c39b30SMarc-André Lureau static void 51c28afa76STomáš Golembiovský fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) 5262c39b30SMarc-André Lureau { 5362c39b30SMarc-André Lureau const gchar *extra_arg = data; 5462c39b30SMarc-André Lureau GError *error = NULL; 5562c39b30SMarc-André Lureau gchar *cwd, *path, *cmd, **argv = NULL; 5662c39b30SMarc-André Lureau 5762c39b30SMarc-André Lureau fixture->loop = g_main_loop_new(NULL, FALSE); 5862c39b30SMarc-André Lureau 5962c39b30SMarc-André Lureau fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX"); 6062c39b30SMarc-André Lureau g_assert_nonnull(mkdtemp(fixture->test_dir)); 6162c39b30SMarc-André Lureau 6262c39b30SMarc-André Lureau path = g_build_filename(fixture->test_dir, "sock", NULL); 6362c39b30SMarc-André Lureau cwd = g_get_current_dir(); 64f15bff25SPaolo Bonzini cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s", 65f15bff25SPaolo Bonzini cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, 6662c39b30SMarc-André Lureau fixture->test_dir, path, 6762c39b30SMarc-André Lureau getenv("QTEST_LOG") ? "-v" : "", 6862c39b30SMarc-André Lureau extra_arg ?: ""); 6962c39b30SMarc-André Lureau g_shell_parse_argv(cmd, NULL, &argv, &error); 7062c39b30SMarc-André Lureau g_assert_no_error(error); 7162c39b30SMarc-André Lureau 72c28afa76STomáš Golembiovský g_spawn_async(fixture->test_dir, argv, envp, 7362c39b30SMarc-André Lureau G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, 7462c39b30SMarc-André Lureau NULL, NULL, &fixture->pid, &error); 7562c39b30SMarc-André Lureau g_assert_no_error(error); 7662c39b30SMarc-André Lureau 7762c39b30SMarc-André Lureau g_child_watch_add(fixture->pid, qga_watch, fixture); 7862c39b30SMarc-André Lureau 7962c39b30SMarc-André Lureau fixture->fd = connect_qga(path); 8062c39b30SMarc-André Lureau g_assert_cmpint(fixture->fd, !=, -1); 8162c39b30SMarc-André Lureau 8262c39b30SMarc-André Lureau g_strfreev(argv); 8362c39b30SMarc-André Lureau g_free(cmd); 8462c39b30SMarc-André Lureau g_free(cwd); 8562c39b30SMarc-André Lureau g_free(path); 8662c39b30SMarc-André Lureau } 8762c39b30SMarc-André Lureau 8862c39b30SMarc-André Lureau static void 8962c39b30SMarc-André Lureau fixture_tear_down(TestFixture *fixture, gconstpointer data) 9062c39b30SMarc-André Lureau { 9162c39b30SMarc-André Lureau gchar *tmp; 9262c39b30SMarc-André Lureau 9362c39b30SMarc-André Lureau kill(fixture->pid, SIGTERM); 9462c39b30SMarc-André Lureau 9562c39b30SMarc-André Lureau g_main_loop_run(fixture->loop); 9662c39b30SMarc-André Lureau g_main_loop_unref(fixture->loop); 9762c39b30SMarc-André Lureau 9862c39b30SMarc-André Lureau g_spawn_close_pid(fixture->pid); 9962c39b30SMarc-André Lureau 10062c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "foo", NULL); 10162c39b30SMarc-André Lureau g_unlink(tmp); 10262c39b30SMarc-André Lureau g_free(tmp); 10362c39b30SMarc-André Lureau 10462c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "qga.state", NULL); 10562c39b30SMarc-André Lureau g_unlink(tmp); 10662c39b30SMarc-André Lureau g_free(tmp); 10762c39b30SMarc-André Lureau 10862c39b30SMarc-André Lureau tmp = g_build_filename(fixture->test_dir, "sock", NULL); 10962c39b30SMarc-André Lureau g_unlink(tmp); 11062c39b30SMarc-André Lureau g_free(tmp); 11162c39b30SMarc-André Lureau 11262c39b30SMarc-André Lureau g_rmdir(fixture->test_dir); 11362c39b30SMarc-André Lureau g_free(fixture->test_dir); 11443d1da7cSAlex Chen close(fixture->fd); 11562c39b30SMarc-André Lureau } 11662c39b30SMarc-André Lureau 11762c39b30SMarc-André Lureau static void qmp_assertion_message_error(const char *domain, 11862c39b30SMarc-André Lureau const char *file, 11962c39b30SMarc-André Lureau int line, 12062c39b30SMarc-André Lureau const char *func, 12162c39b30SMarc-André Lureau const char *expr, 12262c39b30SMarc-André Lureau QDict *dict) 12362c39b30SMarc-André Lureau { 12462c39b30SMarc-André Lureau const char *class, *desc; 12562c39b30SMarc-André Lureau char *s; 12662c39b30SMarc-André Lureau QDict *error; 12762c39b30SMarc-André Lureau 12862c39b30SMarc-André Lureau error = qdict_get_qdict(dict, "error"); 12962c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 13062c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 13162c39b30SMarc-André Lureau 13262c39b30SMarc-André Lureau s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); 13362c39b30SMarc-André Lureau g_assertion_message(domain, file, line, func, s); 13462c39b30SMarc-André Lureau g_free(s); 13562c39b30SMarc-André Lureau } 13662c39b30SMarc-André Lureau 13762c39b30SMarc-André Lureau #define qmp_assert_no_error(err) do { \ 13862c39b30SMarc-André Lureau if (qdict_haskey(err, "error")) { \ 13962c39b30SMarc-André Lureau qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__, \ 14062c39b30SMarc-André Lureau G_STRFUNC, #err, err); \ 14162c39b30SMarc-André Lureau } \ 14262c39b30SMarc-André Lureau } while (0) 14362c39b30SMarc-André Lureau 14462c39b30SMarc-André Lureau static void test_qga_sync_delimited(gconstpointer fix) 14562c39b30SMarc-André Lureau { 14662c39b30SMarc-André Lureau const TestFixture *fixture = fix; 1470f555602SPaolo Bonzini guint32 v, r = g_test_rand_int(); 14862c39b30SMarc-André Lureau unsigned char c; 14962c39b30SMarc-André Lureau QDict *ret; 15062c39b30SMarc-André Lureau 151e2f64a68SMarkus Armbruster qmp_fd_send_raw(fixture->fd, "\xff"); 152015715f5SMarkus Armbruster qmp_fd_send(fixture->fd, 153e2f64a68SMarkus Armbruster "{'execute': 'guest-sync-delimited'," 154015715f5SMarkus Armbruster " 'arguments': {'id': %u } }", 155015715f5SMarkus Armbruster r); 15662c39b30SMarc-André Lureau 1575229564bSEric Blake /* 1585229564bSEric Blake * Read and ignore garbage until resynchronized. 1595229564bSEric Blake * 1605229564bSEric Blake * Note that the full reset sequence would involve checking the 1615229564bSEric Blake * response of guest-sync-delimited and repeating the loop if 1625229564bSEric Blake * 'id' field of the response does not match the 'id' field of 1635229564bSEric Blake * the request. Testing this fully would require inserting 1645229564bSEric Blake * garbage in the response stream and is left as a future test 1655229564bSEric Blake * to implement. 1665229564bSEric Blake * 1675229564bSEric Blake * TODO: The server shouldn't emit so much garbage (among other 1685229564bSEric Blake * things, it loudly complains about the client's \xff being 1695229564bSEric Blake * invalid JSON, even though it is a documented part of the 1705229564bSEric Blake * handshake. 1715229564bSEric Blake */ 1725229564bSEric Blake do { 17362c39b30SMarc-André Lureau v = read(fixture->fd, &c, 1); 17462c39b30SMarc-André Lureau g_assert_cmpint(v, ==, 1); 1755229564bSEric Blake } while (c != 0xff); 17662c39b30SMarc-André Lureau 17762c39b30SMarc-André Lureau ret = qmp_fd_receive(fixture->fd); 17862c39b30SMarc-André Lureau g_assert_nonnull(ret); 17962c39b30SMarc-André Lureau qmp_assert_no_error(ret); 18062c39b30SMarc-André Lureau 18162c39b30SMarc-André Lureau v = qdict_get_int(ret, "return"); 18262c39b30SMarc-André Lureau g_assert_cmpint(r, ==, v); 18362c39b30SMarc-André Lureau 184cb3e7f08SMarc-André Lureau qobject_unref(ret); 18562c39b30SMarc-André Lureau } 18662c39b30SMarc-André Lureau 18762c39b30SMarc-André Lureau static void test_qga_sync(gconstpointer fix) 18862c39b30SMarc-André Lureau { 18962c39b30SMarc-André Lureau const TestFixture *fixture = fix; 1900f555602SPaolo Bonzini guint32 v, r = g_test_rand_int(); 19162c39b30SMarc-André Lureau QDict *ret; 19262c39b30SMarc-André Lureau 1935229564bSEric Blake /* 1945229564bSEric Blake * TODO guest-sync is inherently limited: we cannot distinguish 1955229564bSEric Blake * failure caused by reacting to garbage on the wire prior to this 1965229564bSEric Blake * command, from failure of this actual command. Clients are 1975229564bSEric Blake * supposed to be able to send a raw '\xff' byte to at least 1985229564bSEric Blake * re-synchronize the server's parser prior to this command, but 1995229564bSEric Blake * we are not in a position to test that here because (at least 2005229564bSEric Blake * for now) it causes the server to issue an error message about 2015229564bSEric Blake * invalid JSON. Testing of '\xff' handling is done in 2025229564bSEric Blake * guest-sync-delimited instead. 2035229564bSEric Blake */ 204015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 205015715f5SMarkus Armbruster "{'execute': 'guest-sync', 'arguments': {'id': %u } }", 206015715f5SMarkus Armbruster r); 20762c39b30SMarc-André Lureau 20862c39b30SMarc-André Lureau g_assert_nonnull(ret); 20962c39b30SMarc-André Lureau qmp_assert_no_error(ret); 21062c39b30SMarc-André Lureau 21162c39b30SMarc-André Lureau v = qdict_get_int(ret, "return"); 21262c39b30SMarc-André Lureau g_assert_cmpint(r, ==, v); 21362c39b30SMarc-André Lureau 214cb3e7f08SMarc-André Lureau qobject_unref(ret); 21562c39b30SMarc-André Lureau } 21662c39b30SMarc-André Lureau 21762c39b30SMarc-André Lureau static void test_qga_ping(gconstpointer fix) 21862c39b30SMarc-André Lureau { 21962c39b30SMarc-André Lureau const TestFixture *fixture = fix; 22062c39b30SMarc-André Lureau QDict *ret; 22162c39b30SMarc-André Lureau 22262c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); 22362c39b30SMarc-André Lureau g_assert_nonnull(ret); 22462c39b30SMarc-André Lureau qmp_assert_no_error(ret); 22562c39b30SMarc-André Lureau 226cb3e7f08SMarc-André Lureau qobject_unref(ret); 22762c39b30SMarc-André Lureau } 22862c39b30SMarc-André Lureau 2294eaca8deSMarc-André Lureau static void test_qga_id(gconstpointer fix) 230b5f84310SMarkus Armbruster { 231b5f84310SMarkus Armbruster const TestFixture *fixture = fix; 2324eaca8deSMarc-André Lureau QDict *ret; 233b5f84310SMarkus Armbruster 234b5f84310SMarkus Armbruster ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}"); 235b5f84310SMarkus Armbruster g_assert_nonnull(ret); 2364eaca8deSMarc-André Lureau qmp_assert_no_error(ret); 2374eaca8deSMarc-André Lureau g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1); 238b5f84310SMarkus Armbruster 239b5f84310SMarkus Armbruster qobject_unref(ret); 240b5f84310SMarkus Armbruster } 241b5f84310SMarkus Armbruster 242d4d7ed73SMarkus Armbruster static void test_qga_invalid_oob(gconstpointer fix) 243d4d7ed73SMarkus Armbruster { 244d4d7ed73SMarkus Armbruster const TestFixture *fixture = fix; 245ebb4d82dSMarc-André Lureau QDict *ret; 246d4d7ed73SMarkus Armbruster 24700ecec15SMarkus Armbruster ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}"); 248d4d7ed73SMarkus Armbruster g_assert_nonnull(ret); 249d4d7ed73SMarkus Armbruster 2503bc1b8eeSMarkus Armbruster qmp_expect_error_and_unref(ret, "GenericError"); 251d4d7ed73SMarkus Armbruster } 252d4d7ed73SMarkus Armbruster 2534bdadd86SMarc-André Lureau static void test_qga_invalid_args(gconstpointer fix) 2544bdadd86SMarc-André Lureau { 2554bdadd86SMarc-André Lureau const TestFixture *fixture = fix; 2564bdadd86SMarc-André Lureau QDict *ret, *error; 2574bdadd86SMarc-André Lureau const gchar *class, *desc; 2584bdadd86SMarc-André Lureau 2594bdadd86SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', " 2604bdadd86SMarc-André Lureau "'arguments': {'foo': 42 }}"); 2614bdadd86SMarc-André Lureau g_assert_nonnull(ret); 2624bdadd86SMarc-André Lureau 2634bdadd86SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 2644bdadd86SMarc-André Lureau class = qdict_get_try_str(error, "class"); 2654bdadd86SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 2664bdadd86SMarc-André Lureau 2674bdadd86SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 268910f738bSMarkus Armbruster g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected"); 2694bdadd86SMarc-André Lureau 270cb3e7f08SMarc-André Lureau qobject_unref(ret); 2714bdadd86SMarc-André Lureau } 2724bdadd86SMarc-André Lureau 27362c39b30SMarc-André Lureau static void test_qga_invalid_cmd(gconstpointer fix) 27462c39b30SMarc-André Lureau { 27562c39b30SMarc-André Lureau const TestFixture *fixture = fix; 27662c39b30SMarc-André Lureau QDict *ret, *error; 27762c39b30SMarc-André Lureau const gchar *class, *desc; 27862c39b30SMarc-André Lureau 27962c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); 28062c39b30SMarc-André Lureau g_assert_nonnull(ret); 28162c39b30SMarc-André Lureau 28262c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 28362c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 28462c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 28562c39b30SMarc-André Lureau 28662c39b30SMarc-André Lureau g_assert_cmpstr(class, ==, "CommandNotFound"); 28762c39b30SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 28862c39b30SMarc-André Lureau 289cb3e7f08SMarc-André Lureau qobject_unref(ret); 29062c39b30SMarc-André Lureau } 29162c39b30SMarc-André Lureau 29262c39b30SMarc-André Lureau static void test_qga_info(gconstpointer fix) 29362c39b30SMarc-André Lureau { 29462c39b30SMarc-André Lureau const TestFixture *fixture = fix; 29562c39b30SMarc-André Lureau QDict *ret, *val; 29662c39b30SMarc-André Lureau const gchar *version; 29762c39b30SMarc-André Lureau 29862c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); 29962c39b30SMarc-André Lureau g_assert_nonnull(ret); 30062c39b30SMarc-André Lureau qmp_assert_no_error(ret); 30162c39b30SMarc-André Lureau 30262c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 30362c39b30SMarc-André Lureau version = qdict_get_try_str(val, "version"); 30462c39b30SMarc-André Lureau g_assert_cmpstr(version, ==, QEMU_VERSION); 30562c39b30SMarc-André Lureau 306cb3e7f08SMarc-André Lureau qobject_unref(ret); 30762c39b30SMarc-André Lureau } 30862c39b30SMarc-André Lureau 30962c39b30SMarc-André Lureau static void test_qga_get_vcpus(gconstpointer fix) 31062c39b30SMarc-André Lureau { 31162c39b30SMarc-André Lureau const TestFixture *fixture = fix; 31262c39b30SMarc-André Lureau QDict *ret; 31362c39b30SMarc-André Lureau QList *list; 31462c39b30SMarc-André Lureau const QListEntry *entry; 31562c39b30SMarc-André Lureau 31662c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}"); 31762c39b30SMarc-André Lureau g_assert_nonnull(ret); 31862c39b30SMarc-André Lureau qmp_assert_no_error(ret); 31962c39b30SMarc-André Lureau 32062c39b30SMarc-André Lureau /* check there is at least a cpu */ 32162c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 32262c39b30SMarc-André Lureau entry = qlist_first(list); 3237dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); 3247dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); 32562c39b30SMarc-André Lureau 326cb3e7f08SMarc-André Lureau qobject_unref(ret); 32762c39b30SMarc-André Lureau } 32862c39b30SMarc-André Lureau 32962c39b30SMarc-André Lureau static void test_qga_get_fsinfo(gconstpointer fix) 33062c39b30SMarc-André Lureau { 33162c39b30SMarc-André Lureau const TestFixture *fixture = fix; 33262c39b30SMarc-André Lureau QDict *ret; 33362c39b30SMarc-André Lureau QList *list; 33462c39b30SMarc-André Lureau const QListEntry *entry; 33562c39b30SMarc-André Lureau 33662c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}"); 33762c39b30SMarc-André Lureau g_assert_nonnull(ret); 33862c39b30SMarc-André Lureau qmp_assert_no_error(ret); 33962c39b30SMarc-André Lureau 340b3e9e584SMichael Roth /* sanity-check the response if there are any filesystems */ 34162c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 34262c39b30SMarc-André Lureau entry = qlist_first(list); 343b3e9e584SMichael Roth if (entry) { 3447dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); 3457dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint")); 3467dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type")); 3477dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); 348b3e9e584SMichael Roth } 34962c39b30SMarc-André Lureau 350cb3e7f08SMarc-André Lureau qobject_unref(ret); 35162c39b30SMarc-André Lureau } 35262c39b30SMarc-André Lureau 35362c39b30SMarc-André Lureau static void test_qga_get_memory_block_info(gconstpointer fix) 35462c39b30SMarc-André Lureau { 35562c39b30SMarc-André Lureau const TestFixture *fixture = fix; 35662c39b30SMarc-André Lureau QDict *ret, *val; 35762c39b30SMarc-André Lureau int64_t size; 35862c39b30SMarc-André Lureau 35962c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); 36062c39b30SMarc-André Lureau g_assert_nonnull(ret); 36162c39b30SMarc-André Lureau 36262c39b30SMarc-André Lureau /* some systems might not expose memory block info in sysfs */ 36362c39b30SMarc-André Lureau if (!qdict_haskey(ret, "error")) { 36462c39b30SMarc-André Lureau /* check there is at least some memory */ 36562c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 36662c39b30SMarc-André Lureau size = qdict_get_int(val, "size"); 36762c39b30SMarc-André Lureau g_assert_cmpint(size, >, 0); 36862c39b30SMarc-André Lureau } 36962c39b30SMarc-André Lureau 370cb3e7f08SMarc-André Lureau qobject_unref(ret); 37162c39b30SMarc-André Lureau } 37262c39b30SMarc-André Lureau 37362c39b30SMarc-André Lureau static void test_qga_get_memory_blocks(gconstpointer fix) 37462c39b30SMarc-André Lureau { 37562c39b30SMarc-André Lureau const TestFixture *fixture = fix; 37662c39b30SMarc-André Lureau QDict *ret; 37762c39b30SMarc-André Lureau QList *list; 37862c39b30SMarc-André Lureau const QListEntry *entry; 37962c39b30SMarc-André Lureau 38062c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}"); 38162c39b30SMarc-André Lureau g_assert_nonnull(ret); 38262c39b30SMarc-André Lureau 38362c39b30SMarc-André Lureau /* some systems might not expose memory block info in sysfs */ 38462c39b30SMarc-André Lureau if (!qdict_haskey(ret, "error")) { 38562c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 38662c39b30SMarc-André Lureau entry = qlist_first(list); 38762c39b30SMarc-André Lureau /* newer versions of qga may return empty list without error */ 38862c39b30SMarc-André Lureau if (entry) { 3897dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), 3907dc847ebSMax Reitz "phys-index")); 3917dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); 39262c39b30SMarc-André Lureau } 39362c39b30SMarc-André Lureau } 39462c39b30SMarc-André Lureau 395cb3e7f08SMarc-André Lureau qobject_unref(ret); 39662c39b30SMarc-André Lureau } 39762c39b30SMarc-André Lureau 39862c39b30SMarc-André Lureau static void test_qga_network_get_interfaces(gconstpointer fix) 39962c39b30SMarc-André Lureau { 40062c39b30SMarc-André Lureau const TestFixture *fixture = fix; 40162c39b30SMarc-André Lureau QDict *ret; 40262c39b30SMarc-André Lureau QList *list; 40362c39b30SMarc-André Lureau const QListEntry *entry; 40462c39b30SMarc-André Lureau 40562c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}"); 40662c39b30SMarc-André Lureau g_assert_nonnull(ret); 40762c39b30SMarc-André Lureau qmp_assert_no_error(ret); 40862c39b30SMarc-André Lureau 40962c39b30SMarc-André Lureau /* check there is at least an interface */ 41062c39b30SMarc-André Lureau list = qdict_get_qlist(ret, "return"); 41162c39b30SMarc-André Lureau entry = qlist_first(list); 4127dc847ebSMax Reitz g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); 41362c39b30SMarc-André Lureau 414cb3e7f08SMarc-André Lureau qobject_unref(ret); 41562c39b30SMarc-André Lureau } 41662c39b30SMarc-André Lureau 41762c39b30SMarc-André Lureau static void test_qga_file_ops(gconstpointer fix) 41862c39b30SMarc-André Lureau { 41962c39b30SMarc-André Lureau const TestFixture *fixture = fix; 4204eaab85cSMarc-André Lureau const unsigned char helloworld[] = "Hello World!\n"; 42162c39b30SMarc-André Lureau const char *b64; 422015715f5SMarkus Armbruster gchar *path, *enc; 4234eaab85cSMarc-André Lureau unsigned char *dec; 42462c39b30SMarc-André Lureau QDict *ret, *val; 42562c39b30SMarc-André Lureau int64_t id, eof; 42662c39b30SMarc-André Lureau gsize count; 42762c39b30SMarc-André Lureau FILE *f; 42862c39b30SMarc-André Lureau char tmp[100]; 42962c39b30SMarc-André Lureau 43062c39b30SMarc-André Lureau /* open */ 43162c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 43262c39b30SMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); 43362c39b30SMarc-André Lureau g_assert_nonnull(ret); 43462c39b30SMarc-André Lureau qmp_assert_no_error(ret); 43562c39b30SMarc-André Lureau id = qdict_get_int(ret, "return"); 436cb3e7f08SMarc-André Lureau qobject_unref(ret); 43762c39b30SMarc-André Lureau 43862c39b30SMarc-André Lureau enc = g_base64_encode(helloworld, sizeof(helloworld)); 43962c39b30SMarc-André Lureau /* write */ 440015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 441015715f5SMarkus Armbruster "{'execute': 'guest-file-write'," 442015715f5SMarkus Armbruster " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }", 443015715f5SMarkus Armbruster id, enc); 44462c39b30SMarc-André Lureau g_assert_nonnull(ret); 44562c39b30SMarc-André Lureau qmp_assert_no_error(ret); 44662c39b30SMarc-André Lureau 44762c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 44862c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 44962c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 45062c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 45162c39b30SMarc-André Lureau g_assert_cmpint(eof, ==, 0); 452cb3e7f08SMarc-André Lureau qobject_unref(ret); 45362c39b30SMarc-André Lureau 45462c39b30SMarc-André Lureau /* flush */ 455015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 456015715f5SMarkus Armbruster "{'execute': 'guest-file-flush'," 45762c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 45862c39b30SMarc-André Lureau id); 459cb3e7f08SMarc-André Lureau qobject_unref(ret); 46062c39b30SMarc-André Lureau 46162c39b30SMarc-André Lureau /* close */ 462015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 463015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 46462c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 46562c39b30SMarc-André Lureau id); 466cb3e7f08SMarc-André Lureau qobject_unref(ret); 46762c39b30SMarc-André Lureau 46862c39b30SMarc-André Lureau /* check content */ 46962c39b30SMarc-André Lureau path = g_build_filename(fixture->test_dir, "foo", NULL); 47062c39b30SMarc-André Lureau f = fopen(path, "r"); 4711e271338SMarc-André Lureau g_free(path); 47262c39b30SMarc-André Lureau g_assert_nonnull(f); 47362c39b30SMarc-André Lureau count = fread(tmp, 1, sizeof(tmp), f); 47462c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 47562c39b30SMarc-André Lureau tmp[count] = 0; 47662c39b30SMarc-André Lureau g_assert_cmpstr(tmp, ==, (char *)helloworld); 47762c39b30SMarc-André Lureau fclose(f); 47862c39b30SMarc-André Lureau 47962c39b30SMarc-André Lureau /* open */ 48062c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 48162c39b30SMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'r' } }"); 48262c39b30SMarc-André Lureau g_assert_nonnull(ret); 48362c39b30SMarc-André Lureau qmp_assert_no_error(ret); 48462c39b30SMarc-André Lureau id = qdict_get_int(ret, "return"); 485cb3e7f08SMarc-André Lureau qobject_unref(ret); 48662c39b30SMarc-André Lureau 48762c39b30SMarc-André Lureau /* read */ 488015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 489015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 49062c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 49162c39b30SMarc-André Lureau id); 49262c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 49362c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 49462c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 49562c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 49662c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 49762c39b30SMarc-André Lureau g_assert(eof); 49862c39b30SMarc-André Lureau g_assert_cmpstr(b64, ==, enc); 49962c39b30SMarc-André Lureau 500cb3e7f08SMarc-André Lureau qobject_unref(ret); 50162c39b30SMarc-André Lureau g_free(enc); 50262c39b30SMarc-André Lureau 50362c39b30SMarc-André Lureau /* read eof */ 504015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 505015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 50662c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 50762c39b30SMarc-André Lureau id); 50862c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 50962c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 51062c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 51162c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 51262c39b30SMarc-André Lureau g_assert_cmpint(count, ==, 0); 51362c39b30SMarc-André Lureau g_assert(eof); 51462c39b30SMarc-André Lureau g_assert_cmpstr(b64, ==, ""); 515cb3e7f08SMarc-André Lureau qobject_unref(ret); 51662c39b30SMarc-André Lureau 51762c39b30SMarc-André Lureau /* seek */ 518015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 519015715f5SMarkus Armbruster "{'execute': 'guest-file-seek'," 52062c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 ", " 521015715f5SMarkus Armbruster " 'offset': %d, 'whence': %s } }", 5220b4b4938SEric Blake id, 6, "set"); 52362c39b30SMarc-André Lureau qmp_assert_no_error(ret); 52462c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 52562c39b30SMarc-André Lureau count = qdict_get_int(val, "position"); 52662c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 52762c39b30SMarc-André Lureau g_assert_cmpint(count, ==, 6); 52862c39b30SMarc-André Lureau g_assert(!eof); 529cb3e7f08SMarc-André Lureau qobject_unref(ret); 53062c39b30SMarc-André Lureau 53162c39b30SMarc-André Lureau /* partial read */ 532015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 533015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 53462c39b30SMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 53562c39b30SMarc-André Lureau id); 53662c39b30SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 53762c39b30SMarc-André Lureau count = qdict_get_int(val, "count"); 53862c39b30SMarc-André Lureau eof = qdict_get_bool(val, "eof"); 53962c39b30SMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 54062c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld) - 6); 54162c39b30SMarc-André Lureau g_assert(eof); 54262c39b30SMarc-André Lureau dec = g_base64_decode(b64, &count); 54362c39b30SMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld) - 6); 54462c39b30SMarc-André Lureau g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6); 54562c39b30SMarc-André Lureau g_free(dec); 54662c39b30SMarc-André Lureau 547cb3e7f08SMarc-André Lureau qobject_unref(ret); 54862c39b30SMarc-André Lureau 54962c39b30SMarc-André Lureau /* close */ 550015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 551015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 55262c39b30SMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 55362c39b30SMarc-André Lureau id); 554cb3e7f08SMarc-André Lureau qobject_unref(ret); 55562c39b30SMarc-André Lureau } 55662c39b30SMarc-André Lureau 5574eaab85cSMarc-André Lureau static void test_qga_file_write_read(gconstpointer fix) 5584eaab85cSMarc-André Lureau { 5594eaab85cSMarc-André Lureau const TestFixture *fixture = fix; 5604eaab85cSMarc-André Lureau const unsigned char helloworld[] = "Hello World!\n"; 5614eaab85cSMarc-André Lureau const char *b64; 562015715f5SMarkus Armbruster gchar *enc; 5634eaab85cSMarc-André Lureau QDict *ret, *val; 5644eaab85cSMarc-André Lureau int64_t id, eof; 5654eaab85cSMarc-André Lureau gsize count; 5664eaab85cSMarc-André Lureau 5674eaab85cSMarc-André Lureau /* open */ 5684eaab85cSMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," 5694eaab85cSMarc-André Lureau " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); 5704eaab85cSMarc-André Lureau g_assert_nonnull(ret); 5714eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 5724eaab85cSMarc-André Lureau id = qdict_get_int(ret, "return"); 573cb3e7f08SMarc-André Lureau qobject_unref(ret); 5744eaab85cSMarc-André Lureau 5754eaab85cSMarc-André Lureau enc = g_base64_encode(helloworld, sizeof(helloworld)); 5764eaab85cSMarc-André Lureau /* write */ 577015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 578015715f5SMarkus Armbruster "{'execute': 'guest-file-write'," 5794eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "," 580015715f5SMarkus Armbruster " 'buf-b64': %s } }", id, enc); 5814eaab85cSMarc-André Lureau g_assert_nonnull(ret); 5824eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 5834eaab85cSMarc-André Lureau 5844eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 5854eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 5864eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 5874eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 5884eaab85cSMarc-André Lureau g_assert_cmpint(eof, ==, 0); 589cb3e7f08SMarc-André Lureau qobject_unref(ret); 5904eaab85cSMarc-André Lureau 5914eaab85cSMarc-André Lureau /* read (check implicit flush) */ 592015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 593015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 5944eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 5954eaab85cSMarc-André Lureau id); 5964eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 5974eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 5984eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 5994eaab85cSMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 6004eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, 0); 6014eaab85cSMarc-André Lureau g_assert(eof); 6024eaab85cSMarc-André Lureau g_assert_cmpstr(b64, ==, ""); 603cb3e7f08SMarc-André Lureau qobject_unref(ret); 6044eaab85cSMarc-André Lureau 6054eaab85cSMarc-André Lureau /* seek to 0 */ 606015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 607015715f5SMarkus Armbruster "{'execute': 'guest-file-seek'," 6084eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 ", " 609015715f5SMarkus Armbruster " 'offset': %d, 'whence': %s } }", 6100b4b4938SEric Blake id, 0, "set"); 6114eaab85cSMarc-André Lureau qmp_assert_no_error(ret); 6124eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 6134eaab85cSMarc-André Lureau count = qdict_get_int(val, "position"); 6144eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 6154eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, 0); 6164eaab85cSMarc-André Lureau g_assert(!eof); 617cb3e7f08SMarc-André Lureau qobject_unref(ret); 6184eaab85cSMarc-André Lureau 6194eaab85cSMarc-André Lureau /* read */ 620015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 621015715f5SMarkus Armbruster "{'execute': 'guest-file-read'," 6224eaab85cSMarc-André Lureau " 'arguments': { 'handle': %" PRId64 "} }", 6234eaab85cSMarc-André Lureau id); 6244eaab85cSMarc-André Lureau val = qdict_get_qdict(ret, "return"); 6254eaab85cSMarc-André Lureau count = qdict_get_int(val, "count"); 6264eaab85cSMarc-André Lureau eof = qdict_get_bool(val, "eof"); 6274eaab85cSMarc-André Lureau b64 = qdict_get_str(val, "buf-b64"); 6284eaab85cSMarc-André Lureau g_assert_cmpint(count, ==, sizeof(helloworld)); 6294eaab85cSMarc-André Lureau g_assert(eof); 6304eaab85cSMarc-André Lureau g_assert_cmpstr(b64, ==, enc); 631cb3e7f08SMarc-André Lureau qobject_unref(ret); 6324eaab85cSMarc-André Lureau g_free(enc); 6334eaab85cSMarc-André Lureau 6344eaab85cSMarc-André Lureau /* close */ 635015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 636015715f5SMarkus Armbruster "{'execute': 'guest-file-close'," 6374eaab85cSMarc-André Lureau " 'arguments': {'handle': %" PRId64 "} }", 6384eaab85cSMarc-André Lureau id); 639cb3e7f08SMarc-André Lureau qobject_unref(ret); 6404eaab85cSMarc-André Lureau } 6414eaab85cSMarc-André Lureau 64262c39b30SMarc-André Lureau static void test_qga_get_time(gconstpointer fix) 64362c39b30SMarc-André Lureau { 64462c39b30SMarc-André Lureau const TestFixture *fixture = fix; 64562c39b30SMarc-André Lureau QDict *ret; 64662c39b30SMarc-André Lureau int64_t time; 64762c39b30SMarc-André Lureau 64862c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); 64962c39b30SMarc-André Lureau g_assert_nonnull(ret); 65062c39b30SMarc-André Lureau qmp_assert_no_error(ret); 65162c39b30SMarc-André Lureau 65262c39b30SMarc-André Lureau time = qdict_get_int(ret, "return"); 65362c39b30SMarc-André Lureau g_assert_cmpint(time, >, 0); 65462c39b30SMarc-André Lureau 655cb3e7f08SMarc-André Lureau qobject_unref(ret); 65662c39b30SMarc-André Lureau } 65762c39b30SMarc-André Lureau 65862c39b30SMarc-André Lureau static void test_qga_blacklist(gconstpointer data) 65962c39b30SMarc-André Lureau { 66062c39b30SMarc-André Lureau TestFixture fix; 66162c39b30SMarc-André Lureau QDict *ret, *error; 66262c39b30SMarc-André Lureau const gchar *class, *desc; 66362c39b30SMarc-André Lureau 664c28afa76STomáš Golembiovský fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL); 66562c39b30SMarc-André Lureau 66662c39b30SMarc-André Lureau /* check blacklist */ 66762c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); 66862c39b30SMarc-André Lureau g_assert_nonnull(ret); 66962c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 67062c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 67162c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 6722546be1cSMichal Privoznik g_assert_cmpstr(class, ==, "CommandNotFound"); 67362c39b30SMarc-André Lureau g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); 674cb3e7f08SMarc-André Lureau qobject_unref(ret); 67562c39b30SMarc-André Lureau 67662c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); 67762c39b30SMarc-André Lureau g_assert_nonnull(ret); 67862c39b30SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 67962c39b30SMarc-André Lureau class = qdict_get_try_str(error, "class"); 68062c39b30SMarc-André Lureau desc = qdict_get_try_str(error, "desc"); 6812546be1cSMichal Privoznik g_assert_cmpstr(class, ==, "CommandNotFound"); 68262c39b30SMarc-André Lureau g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); 683cb3e7f08SMarc-André Lureau qobject_unref(ret); 68462c39b30SMarc-André Lureau 68562c39b30SMarc-André Lureau /* check something work */ 68662c39b30SMarc-André Lureau ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); 68762c39b30SMarc-André Lureau qmp_assert_no_error(ret); 688cb3e7f08SMarc-André Lureau qobject_unref(ret); 68962c39b30SMarc-André Lureau 69062c39b30SMarc-André Lureau fixture_tear_down(&fix, NULL); 69162c39b30SMarc-André Lureau } 69262c39b30SMarc-André Lureau 69362c39b30SMarc-André Lureau static void test_qga_config(gconstpointer data) 69462c39b30SMarc-André Lureau { 69562c39b30SMarc-André Lureau GError *error = NULL; 6961741b945SMarc-André Lureau char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL; 69762c39b30SMarc-André Lureau char *env[2]; 6981741b945SMarc-André Lureau int status; 69962c39b30SMarc-André Lureau gsize n; 70062c39b30SMarc-André Lureau GKeyFile *kf; 70162c39b30SMarc-André Lureau 70262c39b30SMarc-André Lureau cwd = g_get_current_dir(); 703f15bff25SPaolo Bonzini cmd = g_strdup_printf("%s%cqga%cqemu-ga -D", 704f15bff25SPaolo Bonzini cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR); 7051e271338SMarc-André Lureau g_free(cwd); 70662c39b30SMarc-André Lureau g_shell_parse_argv(cmd, NULL, &argv, &error); 7071e271338SMarc-André Lureau g_free(cmd); 70862c39b30SMarc-André Lureau g_assert_no_error(error); 70962c39b30SMarc-André Lureau 7101741b945SMarc-André Lureau env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config", 7111741b945SMarc-André Lureau G_DIR_SEPARATOR, G_DIR_SEPARATOR); 71262c39b30SMarc-André Lureau env[1] = NULL; 71362c39b30SMarc-André Lureau g_spawn_sync(NULL, argv, env, 0, 71462c39b30SMarc-André Lureau NULL, NULL, &out, &err, &status, &error); 7151e271338SMarc-André Lureau g_strfreev(argv); 7161e271338SMarc-André Lureau 71762c39b30SMarc-André Lureau g_assert_no_error(error); 71862c39b30SMarc-André Lureau g_assert_cmpstr(err, ==, ""); 71962c39b30SMarc-André Lureau g_assert_cmpint(status, ==, 0); 72062c39b30SMarc-André Lureau 72162c39b30SMarc-André Lureau kf = g_key_file_new(); 72262c39b30SMarc-André Lureau g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error); 72362c39b30SMarc-André Lureau g_assert_no_error(error); 72462c39b30SMarc-André Lureau 72562c39b30SMarc-André Lureau str = g_key_file_get_start_group(kf); 72662c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "general"); 72762c39b30SMarc-André Lureau g_free(str); 72862c39b30SMarc-André Lureau 72962c39b30SMarc-André Lureau g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error)); 73062c39b30SMarc-André Lureau g_assert_no_error(error); 73162c39b30SMarc-André Lureau 73262c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "method", &error); 73362c39b30SMarc-André Lureau g_assert_no_error(error); 73462c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "virtio-serial"); 73562c39b30SMarc-André Lureau g_free(str); 73662c39b30SMarc-André Lureau 73762c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "path", &error); 73862c39b30SMarc-André Lureau g_assert_no_error(error); 73962c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0"); 74062c39b30SMarc-André Lureau g_free(str); 74162c39b30SMarc-André Lureau 74262c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "pidfile", &error); 74362c39b30SMarc-André Lureau g_assert_no_error(error); 74462c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid"); 74562c39b30SMarc-André Lureau g_free(str); 74662c39b30SMarc-André Lureau 74762c39b30SMarc-André Lureau str = g_key_file_get_string(kf, "general", "statedir", &error); 74862c39b30SMarc-André Lureau g_assert_no_error(error); 74962c39b30SMarc-André Lureau g_assert_cmpstr(str, ==, "/var/state"); 75062c39b30SMarc-André Lureau g_free(str); 75162c39b30SMarc-André Lureau 75262c39b30SMarc-André Lureau g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error)); 75362c39b30SMarc-André Lureau g_assert_no_error(error); 75462c39b30SMarc-André Lureau 75562c39b30SMarc-André Lureau strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error); 75662c39b30SMarc-André Lureau g_assert_cmpint(n, ==, 2); 75762c39b30SMarc-André Lureau g_assert_true(g_strv_contains((const char * const *)strv, 75862c39b30SMarc-André Lureau "guest-ping")); 75962c39b30SMarc-André Lureau g_assert_true(g_strv_contains((const char * const *)strv, 76062c39b30SMarc-André Lureau "guest-get-time")); 76162c39b30SMarc-André Lureau g_assert_no_error(error); 76262c39b30SMarc-André Lureau g_strfreev(strv); 76362c39b30SMarc-André Lureau 76462c39b30SMarc-André Lureau g_free(out); 76562c39b30SMarc-André Lureau g_free(err); 76662c39b30SMarc-André Lureau g_free(env[0]); 76762c39b30SMarc-André Lureau g_key_file_free(kf); 76862c39b30SMarc-André Lureau } 76962c39b30SMarc-André Lureau 77062c39b30SMarc-André Lureau static void test_qga_fsfreeze_status(gconstpointer fix) 77162c39b30SMarc-André Lureau { 77262c39b30SMarc-André Lureau const TestFixture *fixture = fix; 77362c39b30SMarc-André Lureau QDict *ret; 77462c39b30SMarc-André Lureau const gchar *status; 77562c39b30SMarc-André Lureau 77662c39b30SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); 77762c39b30SMarc-André Lureau g_assert_nonnull(ret); 77862c39b30SMarc-André Lureau qmp_assert_no_error(ret); 77962c39b30SMarc-André Lureau 78062c39b30SMarc-André Lureau status = qdict_get_try_str(ret, "return"); 78162c39b30SMarc-André Lureau g_assert_cmpstr(status, ==, "thawed"); 78262c39b30SMarc-André Lureau 783cb3e7f08SMarc-André Lureau qobject_unref(ret); 78462c39b30SMarc-André Lureau } 78562c39b30SMarc-André Lureau 7863dab9fa1SMarc-André Lureau static void test_qga_guest_exec(gconstpointer fix) 7873dab9fa1SMarc-André Lureau { 7883dab9fa1SMarc-André Lureau const TestFixture *fixture = fix; 7893dab9fa1SMarc-André Lureau QDict *ret, *val; 7903dab9fa1SMarc-André Lureau const gchar *out; 7913dab9fa1SMarc-André Lureau guchar *decoded; 7923dab9fa1SMarc-André Lureau int64_t pid, now, exitcode; 7933dab9fa1SMarc-André Lureau gsize len; 7943dab9fa1SMarc-André Lureau bool exited; 7953dab9fa1SMarc-André Lureau 7963dab9fa1SMarc-André Lureau /* exec 'echo foo bar' */ 7973dab9fa1SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 7983dab9fa1SMarc-André Lureau " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ]," 7993dab9fa1SMarc-André Lureau " 'capture-output': true } }"); 8003dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 8013dab9fa1SMarc-André Lureau qmp_assert_no_error(ret); 8023dab9fa1SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 8033dab9fa1SMarc-André Lureau pid = qdict_get_int(val, "pid"); 8043dab9fa1SMarc-André Lureau g_assert_cmpint(pid, >, 0); 805cb3e7f08SMarc-André Lureau qobject_unref(ret); 8063dab9fa1SMarc-André Lureau 8073dab9fa1SMarc-André Lureau /* wait for completion */ 8083dab9fa1SMarc-André Lureau now = g_get_monotonic_time(); 8091792d7d0SEric Blake do { 810015715f5SMarkus Armbruster ret = qmp_fd(fixture->fd, 811015715f5SMarkus Armbruster "{'execute': 'guest-exec-status'," 812015715f5SMarkus Armbruster " 'arguments': { 'pid': %" PRId64 " } }", pid); 8133dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 8143dab9fa1SMarc-André Lureau val = qdict_get_qdict(ret, "return"); 8153dab9fa1SMarc-André Lureau exited = qdict_get_bool(val, "exited"); 8163dab9fa1SMarc-André Lureau if (!exited) { 817cb3e7f08SMarc-André Lureau qobject_unref(ret); 8183dab9fa1SMarc-André Lureau } 8193dab9fa1SMarc-André Lureau } while (!exited && 8203dab9fa1SMarc-André Lureau g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND); 8213dab9fa1SMarc-André Lureau g_assert(exited); 8223dab9fa1SMarc-André Lureau 8233dab9fa1SMarc-André Lureau /* check stdout */ 8243dab9fa1SMarc-André Lureau exitcode = qdict_get_int(val, "exitcode"); 8253dab9fa1SMarc-André Lureau g_assert_cmpint(exitcode, ==, 0); 8263dab9fa1SMarc-André Lureau out = qdict_get_str(val, "out-data"); 8273dab9fa1SMarc-André Lureau decoded = g_base64_decode(out, &len); 8283dab9fa1SMarc-André Lureau g_assert_cmpint(len, ==, 12); 8293dab9fa1SMarc-André Lureau g_assert_cmpstr((char *)decoded, ==, "\" test_str \""); 8303dab9fa1SMarc-André Lureau g_free(decoded); 831cb3e7f08SMarc-André Lureau qobject_unref(ret); 8323dab9fa1SMarc-André Lureau } 8333dab9fa1SMarc-André Lureau 8343dab9fa1SMarc-André Lureau static void test_qga_guest_exec_invalid(gconstpointer fix) 8353dab9fa1SMarc-André Lureau { 8363dab9fa1SMarc-André Lureau const TestFixture *fixture = fix; 8373dab9fa1SMarc-André Lureau QDict *ret, *error; 8383dab9fa1SMarc-André Lureau const gchar *class, *desc; 8393dab9fa1SMarc-André Lureau 8403dab9fa1SMarc-André Lureau /* invalid command */ 8413dab9fa1SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {" 8423dab9fa1SMarc-André Lureau " 'path': '/bin/invalid-cmd42' } }"); 8433dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 8443dab9fa1SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 8453dab9fa1SMarc-André Lureau g_assert_nonnull(error); 8463dab9fa1SMarc-André Lureau class = qdict_get_str(error, "class"); 8473dab9fa1SMarc-André Lureau desc = qdict_get_str(error, "desc"); 8483dab9fa1SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 8493dab9fa1SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 850cb3e7f08SMarc-André Lureau qobject_unref(ret); 8513dab9fa1SMarc-André Lureau 8523dab9fa1SMarc-André Lureau /* invalid pid */ 8533dab9fa1SMarc-André Lureau ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status'," 8543dab9fa1SMarc-André Lureau " 'arguments': { 'pid': 0 } }"); 8553dab9fa1SMarc-André Lureau g_assert_nonnull(ret); 8563dab9fa1SMarc-André Lureau error = qdict_get_qdict(ret, "error"); 8573dab9fa1SMarc-André Lureau g_assert_nonnull(error); 8583dab9fa1SMarc-André Lureau class = qdict_get_str(error, "class"); 8593dab9fa1SMarc-André Lureau desc = qdict_get_str(error, "desc"); 8603dab9fa1SMarc-André Lureau g_assert_cmpstr(class, ==, "GenericError"); 8613dab9fa1SMarc-André Lureau g_assert_cmpint(strlen(desc), >, 0); 862cb3e7f08SMarc-André Lureau qobject_unref(ret); 8633dab9fa1SMarc-André Lureau } 8643dab9fa1SMarc-André Lureau 865509b97fdSTomáš Golembiovský static void test_qga_guest_get_host_name(gconstpointer fix) 866509b97fdSTomáš Golembiovský { 867509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 868509b97fdSTomáš Golembiovský QDict *ret, *val; 869509b97fdSTomáš Golembiovský 870509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}"); 871509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 872509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 873509b97fdSTomáš Golembiovský 874509b97fdSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 875509b97fdSTomáš Golembiovský g_assert(qdict_haskey(val, "host-name")); 876509b97fdSTomáš Golembiovský 877509b97fdSTomáš Golembiovský qobject_unref(ret); 878509b97fdSTomáš Golembiovský } 879509b97fdSTomáš Golembiovský 880509b97fdSTomáš Golembiovský static void test_qga_guest_get_timezone(gconstpointer fix) 881509b97fdSTomáš Golembiovský { 882509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 883509b97fdSTomáš Golembiovský QDict *ret, *val; 884509b97fdSTomáš Golembiovský 885509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}"); 886509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 887509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 888509b97fdSTomáš Golembiovský 889509b97fdSTomáš Golembiovský /* Make sure there's at least offset */ 890509b97fdSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 891509b97fdSTomáš Golembiovský g_assert(qdict_haskey(val, "offset")); 892509b97fdSTomáš Golembiovský 893509b97fdSTomáš Golembiovský qobject_unref(ret); 894509b97fdSTomáš Golembiovský } 895509b97fdSTomáš Golembiovský 896509b97fdSTomáš Golembiovský static void test_qga_guest_get_users(gconstpointer fix) 897509b97fdSTomáš Golembiovský { 898509b97fdSTomáš Golembiovský const TestFixture *fixture = fix; 899509b97fdSTomáš Golembiovský QDict *ret; 900509b97fdSTomáš Golembiovský QList *val; 901509b97fdSTomáš Golembiovský 902509b97fdSTomáš Golembiovský ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}"); 903509b97fdSTomáš Golembiovský g_assert_nonnull(ret); 904509b97fdSTomáš Golembiovský qmp_assert_no_error(ret); 905509b97fdSTomáš Golembiovský 906509b97fdSTomáš Golembiovský /* There is not much to test here */ 907509b97fdSTomáš Golembiovský val = qdict_get_qlist(ret, "return"); 908509b97fdSTomáš Golembiovský g_assert_nonnull(val); 909509b97fdSTomáš Golembiovský 910509b97fdSTomáš Golembiovský qobject_unref(ret); 911509b97fdSTomáš Golembiovský } 912509b97fdSTomáš Golembiovský 913339ca68bSTomáš Golembiovský static void test_qga_guest_get_osinfo(gconstpointer data) 914339ca68bSTomáš Golembiovský { 915339ca68bSTomáš Golembiovský TestFixture fixture; 916339ca68bSTomáš Golembiovský const gchar *str; 917*a85d0926SMarc-André Lureau QDict *ret = NULL; 918*a85d0926SMarc-André Lureau char *env[2]; 919*a85d0926SMarc-André Lureau QDict *val; 920339ca68bSTomáš Golembiovský 921339ca68bSTomáš Golembiovský env[0] = g_strdup_printf( 922*a85d0926SMarc-André Lureau "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release", 923*a85d0926SMarc-André Lureau g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); 924339ca68bSTomáš Golembiovský env[1] = NULL; 925339ca68bSTomáš Golembiovský fixture_setup(&fixture, NULL, env); 926339ca68bSTomáš Golembiovský 927339ca68bSTomáš Golembiovský ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}"); 928339ca68bSTomáš Golembiovský g_assert_nonnull(ret); 929339ca68bSTomáš Golembiovský qmp_assert_no_error(ret); 930339ca68bSTomáš Golembiovský 931339ca68bSTomáš Golembiovský val = qdict_get_qdict(ret, "return"); 932339ca68bSTomáš Golembiovský 933339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "id"); 934339ca68bSTomáš Golembiovský g_assert_nonnull(str); 935339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "qemu-ga-test"); 936339ca68bSTomáš Golembiovský 937339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "name"); 938339ca68bSTomáš Golembiovský g_assert_nonnull(str); 939339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "QEMU-GA"); 940339ca68bSTomáš Golembiovský 941339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "pretty-name"); 942339ca68bSTomáš Golembiovský g_assert_nonnull(str); 943339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "QEMU Guest Agent test"); 944339ca68bSTomáš Golembiovský 945339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "version"); 946339ca68bSTomáš Golembiovský g_assert_nonnull(str); 947339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "Test 1"); 948339ca68bSTomáš Golembiovský 949339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "version-id"); 950339ca68bSTomáš Golembiovský g_assert_nonnull(str); 951339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "1"); 952339ca68bSTomáš Golembiovský 953339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "variant"); 954339ca68bSTomáš Golembiovský g_assert_nonnull(str); 955339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc."); 956339ca68bSTomáš Golembiovský 957339ca68bSTomáš Golembiovský str = qdict_get_try_str(val, "variant-id"); 958339ca68bSTomáš Golembiovský g_assert_nonnull(str); 959339ca68bSTomáš Golembiovský g_assert_cmpstr(str, ==, "unit-test"); 960339ca68bSTomáš Golembiovský 961cb3e7f08SMarc-André Lureau qobject_unref(ret); 962339ca68bSTomáš Golembiovský g_free(env[0]); 963339ca68bSTomáš Golembiovský fixture_tear_down(&fixture, NULL); 964339ca68bSTomáš Golembiovský } 965339ca68bSTomáš Golembiovský 96662c39b30SMarc-André Lureau int main(int argc, char **argv) 96762c39b30SMarc-André Lureau { 96862c39b30SMarc-André Lureau TestFixture fix; 96962c39b30SMarc-André Lureau int ret; 97062c39b30SMarc-André Lureau 971a7bd942cSMarc-André Lureau #ifdef QEMU_SANITIZE_THREAD 972a7bd942cSMarc-André Lureau { 973a7bd942cSMarc-André Lureau g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116"); 974a7bd942cSMarc-André Lureau return 0; 975a7bd942cSMarc-André Lureau } 976a7bd942cSMarc-André Lureau #endif 977a7bd942cSMarc-André Lureau 97862c39b30SMarc-André Lureau setlocale (LC_ALL, ""); 97962c39b30SMarc-André Lureau g_test_init(&argc, &argv, NULL); 980c28afa76STomáš Golembiovský fixture_setup(&fix, NULL, NULL); 98162c39b30SMarc-André Lureau 98262c39b30SMarc-André Lureau g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited); 98362c39b30SMarc-André Lureau g_test_add_data_func("/qga/sync", &fix, test_qga_sync); 98462c39b30SMarc-André Lureau g_test_add_data_func("/qga/ping", &fix, test_qga_ping); 98562c39b30SMarc-André Lureau g_test_add_data_func("/qga/info", &fix, test_qga_info); 98662c39b30SMarc-André Lureau g_test_add_data_func("/qga/network-get-interfaces", &fix, 98762c39b30SMarc-André Lureau test_qga_network_get_interfaces); 988ec72c0e2SBruce Rogers if (!access("/sys/devices/system/cpu/cpu0", F_OK)) { 98962c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus); 990ec72c0e2SBruce Rogers } 99162c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo); 99262c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-memory-block-info", &fix, 99362c39b30SMarc-André Lureau test_qga_get_memory_block_info); 99462c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-memory-blocks", &fix, 99562c39b30SMarc-André Lureau test_qga_get_memory_blocks); 99662c39b30SMarc-André Lureau g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops); 9974eaab85cSMarc-André Lureau g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read); 99862c39b30SMarc-André Lureau g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); 9994eaca8deSMarc-André Lureau g_test_add_data_func("/qga/id", &fix, test_qga_id); 1000d4d7ed73SMarkus Armbruster g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob); 100162c39b30SMarc-André Lureau g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); 10024bdadd86SMarc-André Lureau g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args); 100362c39b30SMarc-André Lureau g_test_add_data_func("/qga/fsfreeze-status", &fix, 100462c39b30SMarc-André Lureau test_qga_fsfreeze_status); 100562c39b30SMarc-André Lureau 100662c39b30SMarc-André Lureau g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist); 100762c39b30SMarc-André Lureau g_test_add_data_func("/qga/config", NULL, test_qga_config); 10083dab9fa1SMarc-André Lureau g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec); 10093dab9fa1SMarc-André Lureau g_test_add_data_func("/qga/guest-exec-invalid", &fix, 10103dab9fa1SMarc-André Lureau test_qga_guest_exec_invalid); 1011339ca68bSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-osinfo", &fix, 1012339ca68bSTomáš Golembiovský test_qga_guest_get_osinfo); 1013509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-host-name", &fix, 1014509b97fdSTomáš Golembiovský test_qga_guest_get_host_name); 1015509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-timezone", &fix, 1016509b97fdSTomáš Golembiovský test_qga_guest_get_timezone); 1017509b97fdSTomáš Golembiovský g_test_add_data_func("/qga/guest-get-users", &fix, 1018509b97fdSTomáš Golembiovský test_qga_guest_get_users); 101962c39b30SMarc-André Lureau 102062c39b30SMarc-André Lureau ret = g_test_run(); 102162c39b30SMarc-André Lureau 102262c39b30SMarc-André Lureau fixture_tear_down(&fix, NULL); 102362c39b30SMarc-André Lureau 102462c39b30SMarc-André Lureau return ret; 102562c39b30SMarc-André Lureau } 1026