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
connect_qga(char * path)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
qga_watch(GPid pid,gint status,gpointer user_data)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
fixture_setup(TestFixture * fixture,gconstpointer data,gchar ** envp)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
fixture_tear_down(TestFixture * fixture,gconstpointer data)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
qmp_assertion_message_error(const char * domain,const char * file,int line,const char * func,const char * expr,QDict * dict)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
test_qga_sync_delimited(gconstpointer fix)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
test_qga_sync(gconstpointer fix)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
test_qga_ping(gconstpointer fix)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
test_qga_id(gconstpointer fix)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
test_qga_invalid_oob(gconstpointer fix)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
test_qga_invalid_args(gconstpointer fix)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
test_qga_invalid_cmd(gconstpointer fix)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
test_qga_info(gconstpointer fix)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
test_qga_get_vcpus(gconstpointer fix)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
test_qga_get_fsinfo(gconstpointer fix)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
test_qga_get_memory_block_info(gconstpointer fix)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
test_qga_get_memory_blocks(gconstpointer fix)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
test_qga_network_get_interfaces(gconstpointer fix)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
test_qga_file_ops(gconstpointer fix)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
test_qga_file_write_read(gconstpointer fix)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
test_qga_get_time(gconstpointer fix)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
test_qga_blockedrpcs(gconstpointer data)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
test_qga_allowedrpcs(gconstpointer data)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
test_qga_config(gconstpointer data)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
test_qga_fsfreeze_status(gconstpointer fix)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
wait_for_guest_exec_completion(int fd,int64_t pid)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
test_qga_guest_exec(gconstpointer fix)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)
test_qga_guest_exec_separated(gconstpointer fix)847c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix)
848c7d74f27SDaniel Xu {
849c7d74f27SDaniel Xu }
test_qga_guest_exec_merged(gconstpointer fix)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
test_qga_guest_exec_separated(gconstpointer fix)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
test_qga_guest_exec_merged(gconstpointer fix)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
test_qga_guest_exec_invalid(gconstpointer fix)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
test_qga_guest_get_host_name(gconstpointer fix)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ý
test_qga_guest_get_timezone(gconstpointer fix)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ý
test_qga_guest_get_users(gconstpointer fix)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ý
test_qga_guest_get_osinfo(gconstpointer data)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ý
main(int argc,char ** argv)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