xref: /qemu/tests/unit/test-qga.c (revision 582a098e6ca00dd42f317dad8affd13e5a20bc42)
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;
55bb6960a1SMarc-André Lureau     g_autofree char *cwd = NULL;
56bb6960a1SMarc-André Lureau     g_autofree char *path = NULL;
57bb6960a1SMarc-André Lureau     g_autofree char *cmd = NULL;
58bb6960a1SMarc-André Lureau     g_auto(GStrv) argv = NULL;
5962c39b30SMarc-André Lureau 
6062c39b30SMarc-André Lureau     fixture->loop = g_main_loop_new(NULL, FALSE);
6162c39b30SMarc-André Lureau 
6262c39b30SMarc-André Lureau     fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
633c239aa7SBin Meng     g_assert_nonnull(g_mkdtemp(fixture->test_dir));
6462c39b30SMarc-André Lureau 
6562c39b30SMarc-André Lureau     path = g_build_filename(fixture->test_dir, "sock", NULL);
6662c39b30SMarc-André Lureau     cwd = g_get_current_dir();
67f15bff25SPaolo Bonzini     cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s",
68f15bff25SPaolo Bonzini                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR,
6962c39b30SMarc-André Lureau                           fixture->test_dir, path,
7062c39b30SMarc-André Lureau                           getenv("QTEST_LOG") ? "-v" : "",
7162c39b30SMarc-André Lureau                           extra_arg ?: "");
7262c39b30SMarc-André Lureau     g_shell_parse_argv(cmd, NULL, &argv, &error);
7362c39b30SMarc-André Lureau     g_assert_no_error(error);
7462c39b30SMarc-André Lureau 
75c28afa76STomáš Golembiovský     g_spawn_async(fixture->test_dir, argv, envp,
7662c39b30SMarc-André Lureau                   G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
7762c39b30SMarc-André Lureau                   NULL, NULL, &fixture->pid, &error);
7862c39b30SMarc-André Lureau     g_assert_no_error(error);
7962c39b30SMarc-André Lureau 
8062c39b30SMarc-André Lureau     g_child_watch_add(fixture->pid, qga_watch, fixture);
8162c39b30SMarc-André Lureau 
8262c39b30SMarc-André Lureau     fixture->fd = connect_qga(path);
8362c39b30SMarc-André Lureau     g_assert_cmpint(fixture->fd, !=, -1);
8462c39b30SMarc-André Lureau }
8562c39b30SMarc-André Lureau 
8662c39b30SMarc-André Lureau static void
8762c39b30SMarc-André Lureau fixture_tear_down(TestFixture *fixture, gconstpointer data)
8862c39b30SMarc-André Lureau {
89bb6960a1SMarc-André Lureau     g_autofree char *tmp = NULL;
9062c39b30SMarc-André Lureau 
9162c39b30SMarc-André Lureau     kill(fixture->pid, SIGTERM);
9262c39b30SMarc-André Lureau 
9362c39b30SMarc-André Lureau     g_main_loop_run(fixture->loop);
9462c39b30SMarc-André Lureau     g_main_loop_unref(fixture->loop);
9562c39b30SMarc-André Lureau 
9662c39b30SMarc-André Lureau     g_spawn_close_pid(fixture->pid);
9762c39b30SMarc-André Lureau 
9862c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "foo", NULL);
9962c39b30SMarc-André Lureau     g_unlink(tmp);
10062c39b30SMarc-André Lureau     g_free(tmp);
10162c39b30SMarc-André Lureau 
10262c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
10362c39b30SMarc-André Lureau     g_unlink(tmp);
10462c39b30SMarc-André Lureau     g_free(tmp);
10562c39b30SMarc-André Lureau 
10662c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "sock", NULL);
10762c39b30SMarc-André Lureau     g_unlink(tmp);
10862c39b30SMarc-André Lureau 
10962c39b30SMarc-André Lureau     g_rmdir(fixture->test_dir);
11062c39b30SMarc-André Lureau     g_free(fixture->test_dir);
11143d1da7cSAlex Chen     close(fixture->fd);
11262c39b30SMarc-André Lureau }
11362c39b30SMarc-André Lureau 
11462c39b30SMarc-André Lureau static void qmp_assertion_message_error(const char     *domain,
11562c39b30SMarc-André Lureau                                         const char     *file,
11662c39b30SMarc-André Lureau                                         int             line,
11762c39b30SMarc-André Lureau                                         const char     *func,
11862c39b30SMarc-André Lureau                                         const char     *expr,
11962c39b30SMarc-André Lureau                                         QDict          *dict)
12062c39b30SMarc-André Lureau {
12162c39b30SMarc-André Lureau     const char *class, *desc;
122bb6960a1SMarc-André Lureau     g_autofree char *s = NULL;
12362c39b30SMarc-André Lureau     QDict *error;
12462c39b30SMarc-André Lureau 
12562c39b30SMarc-André Lureau     error = qdict_get_qdict(dict, "error");
12662c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
12762c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
12862c39b30SMarc-André Lureau 
12962c39b30SMarc-André Lureau     s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
13062c39b30SMarc-André Lureau     g_assertion_message(domain, file, line, func, s);
13162c39b30SMarc-André Lureau }
13262c39b30SMarc-André Lureau 
13362c39b30SMarc-André Lureau #define qmp_assert_no_error(err) do {                                   \
13462c39b30SMarc-André Lureau     if (qdict_haskey(err, "error")) {                                   \
13562c39b30SMarc-André Lureau         qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
13662c39b30SMarc-André Lureau                                     G_STRFUNC, #err, err);              \
13762c39b30SMarc-André Lureau     }                                                                   \
13862c39b30SMarc-André Lureau } while (0)
13962c39b30SMarc-André Lureau 
14062c39b30SMarc-André Lureau static void test_qga_sync_delimited(gconstpointer fix)
14162c39b30SMarc-André Lureau {
14262c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
1430f555602SPaolo Bonzini     guint32 v, r = g_test_rand_int();
14462c39b30SMarc-André Lureau     unsigned char c;
145bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
14662c39b30SMarc-André Lureau 
147e2f64a68SMarkus Armbruster     qmp_fd_send_raw(fixture->fd, "\xff");
148015715f5SMarkus Armbruster     qmp_fd_send(fixture->fd,
149e2f64a68SMarkus Armbruster                 "{'execute': 'guest-sync-delimited',"
150015715f5SMarkus Armbruster                 " 'arguments': {'id': %u } }",
151015715f5SMarkus Armbruster                 r);
15262c39b30SMarc-André Lureau 
1535229564bSEric Blake     /*
1545229564bSEric Blake      * Read and ignore garbage until resynchronized.
1555229564bSEric Blake      *
1565229564bSEric Blake      * Note that the full reset sequence would involve checking the
1575229564bSEric Blake      * response of guest-sync-delimited and repeating the loop if
1585229564bSEric Blake      * 'id' field of the response does not match the 'id' field of
1595229564bSEric Blake      * the request. Testing this fully would require inserting
1605229564bSEric Blake      * garbage in the response stream and is left as a future test
1615229564bSEric Blake      * to implement.
1625229564bSEric Blake      *
1635229564bSEric Blake      * TODO: The server shouldn't emit so much garbage (among other
1645229564bSEric Blake      * things, it loudly complains about the client's \xff being
1655229564bSEric Blake      * invalid JSON, even though it is a documented part of the
1665229564bSEric Blake      * handshake.
1675229564bSEric Blake      */
1685229564bSEric Blake     do {
16962c39b30SMarc-André Lureau         v = read(fixture->fd, &c, 1);
17062c39b30SMarc-André Lureau         g_assert_cmpint(v, ==, 1);
1715229564bSEric Blake     } while (c != 0xff);
17262c39b30SMarc-André Lureau 
17362c39b30SMarc-André Lureau     ret = qmp_fd_receive(fixture->fd);
17462c39b30SMarc-André Lureau     g_assert_nonnull(ret);
17562c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
17662c39b30SMarc-André Lureau 
17762c39b30SMarc-André Lureau     v = qdict_get_int(ret, "return");
17862c39b30SMarc-André Lureau     g_assert_cmpint(r, ==, v);
17962c39b30SMarc-André Lureau }
18062c39b30SMarc-André Lureau 
18162c39b30SMarc-André Lureau static void test_qga_sync(gconstpointer fix)
18262c39b30SMarc-André Lureau {
18362c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
1840f555602SPaolo Bonzini     guint32 v, r = g_test_rand_int();
185bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
18662c39b30SMarc-André Lureau 
1875229564bSEric Blake     /*
1885229564bSEric Blake      * TODO guest-sync is inherently limited: we cannot distinguish
1895229564bSEric Blake      * failure caused by reacting to garbage on the wire prior to this
1905229564bSEric Blake      * command, from failure of this actual command. Clients are
1915229564bSEric Blake      * supposed to be able to send a raw '\xff' byte to at least
1925229564bSEric Blake      * re-synchronize the server's parser prior to this command, but
1935229564bSEric Blake      * we are not in a position to test that here because (at least
1945229564bSEric Blake      * for now) it causes the server to issue an error message about
1955229564bSEric Blake      * invalid JSON. Testing of '\xff' handling is done in
1965229564bSEric Blake      * guest-sync-delimited instead.
1975229564bSEric Blake      */
198015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
199015715f5SMarkus Armbruster                  "{'execute': 'guest-sync', 'arguments': {'id': %u } }",
200015715f5SMarkus Armbruster                  r);
20162c39b30SMarc-André Lureau 
20262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
20362c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
20462c39b30SMarc-André Lureau 
20562c39b30SMarc-André Lureau     v = qdict_get_int(ret, "return");
20662c39b30SMarc-André Lureau     g_assert_cmpint(r, ==, v);
20762c39b30SMarc-André Lureau }
20862c39b30SMarc-André Lureau 
20962c39b30SMarc-André Lureau static void test_qga_ping(gconstpointer fix)
21062c39b30SMarc-André Lureau {
21162c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
212bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
21362c39b30SMarc-André Lureau 
21462c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
21562c39b30SMarc-André Lureau     g_assert_nonnull(ret);
21662c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
21762c39b30SMarc-André Lureau }
21862c39b30SMarc-André Lureau 
2194eaca8deSMarc-André Lureau static void test_qga_id(gconstpointer fix)
220b5f84310SMarkus Armbruster {
221b5f84310SMarkus Armbruster     const TestFixture *fixture = fix;
222bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
223b5f84310SMarkus Armbruster 
224b5f84310SMarkus Armbruster     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
225b5f84310SMarkus Armbruster     g_assert_nonnull(ret);
2264eaca8deSMarc-André Lureau     qmp_assert_no_error(ret);
2274eaca8deSMarc-André Lureau     g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1);
228b5f84310SMarkus Armbruster }
229b5f84310SMarkus Armbruster 
230d4d7ed73SMarkus Armbruster static void test_qga_invalid_oob(gconstpointer fix)
231d4d7ed73SMarkus Armbruster {
232d4d7ed73SMarkus Armbruster     const TestFixture *fixture = fix;
233ebb4d82dSMarc-André Lureau     QDict *ret;
234d4d7ed73SMarkus Armbruster 
23500ecec15SMarkus Armbruster     ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}");
236d4d7ed73SMarkus Armbruster     g_assert_nonnull(ret);
237d4d7ed73SMarkus Armbruster 
2383bc1b8eeSMarkus Armbruster     qmp_expect_error_and_unref(ret, "GenericError");
239d4d7ed73SMarkus Armbruster }
240d4d7ed73SMarkus Armbruster 
2414bdadd86SMarc-André Lureau static void test_qga_invalid_args(gconstpointer fix)
2424bdadd86SMarc-André Lureau {
2434bdadd86SMarc-André Lureau     const TestFixture *fixture = fix;
244bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
245bb6960a1SMarc-André Lureau     QDict *error;
2464bdadd86SMarc-André Lureau     const gchar *class, *desc;
2474bdadd86SMarc-André Lureau 
2484bdadd86SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
2494bdadd86SMarc-André Lureau                  "'arguments': {'foo': 42 }}");
2504bdadd86SMarc-André Lureau     g_assert_nonnull(ret);
2514bdadd86SMarc-André Lureau 
2524bdadd86SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
2534bdadd86SMarc-André Lureau     class = qdict_get_try_str(error, "class");
2544bdadd86SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
2554bdadd86SMarc-André Lureau 
2564bdadd86SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
257910f738bSMarkus Armbruster     g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
2584bdadd86SMarc-André Lureau }
2594bdadd86SMarc-André Lureau 
26062c39b30SMarc-André Lureau static void test_qga_invalid_cmd(gconstpointer fix)
26162c39b30SMarc-André Lureau {
26262c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
263bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
264bb6960a1SMarc-André Lureau     QDict *error;
26562c39b30SMarc-André Lureau     const gchar *class, *desc;
26662c39b30SMarc-André Lureau 
26762c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
26862c39b30SMarc-André Lureau     g_assert_nonnull(ret);
26962c39b30SMarc-André Lureau 
27062c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
27162c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
27262c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
27362c39b30SMarc-André Lureau 
27462c39b30SMarc-André Lureau     g_assert_cmpstr(class, ==, "CommandNotFound");
27562c39b30SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
27662c39b30SMarc-André Lureau }
27762c39b30SMarc-André Lureau 
27862c39b30SMarc-André Lureau static void test_qga_info(gconstpointer fix)
27962c39b30SMarc-André Lureau {
28062c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
281bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
282bb6960a1SMarc-André Lureau     QDict *val;
28362c39b30SMarc-André Lureau     const gchar *version;
28462c39b30SMarc-André Lureau 
28562c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
28662c39b30SMarc-André Lureau     g_assert_nonnull(ret);
28762c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
28862c39b30SMarc-André Lureau 
28962c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
29062c39b30SMarc-André Lureau     version = qdict_get_try_str(val, "version");
29162c39b30SMarc-André Lureau     g_assert_cmpstr(version, ==, QEMU_VERSION);
29262c39b30SMarc-André Lureau }
29362c39b30SMarc-André Lureau 
29462c39b30SMarc-André Lureau static void test_qga_get_vcpus(gconstpointer fix)
29562c39b30SMarc-André Lureau {
29662c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
297bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
29862c39b30SMarc-André Lureau     QList *list;
29962c39b30SMarc-André Lureau     const QListEntry *entry;
30062c39b30SMarc-André Lureau 
30162c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
30262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
30362c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
30462c39b30SMarc-André Lureau 
30562c39b30SMarc-André Lureau     /* check there is at least a cpu */
30662c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
30762c39b30SMarc-André Lureau     entry = qlist_first(list);
3087dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
3097dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id"));
31062c39b30SMarc-André Lureau }
31162c39b30SMarc-André Lureau 
31262c39b30SMarc-André Lureau static void test_qga_get_fsinfo(gconstpointer fix)
31362c39b30SMarc-André Lureau {
31462c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
315bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
31662c39b30SMarc-André Lureau     QList *list;
31762c39b30SMarc-André Lureau     const QListEntry *entry;
31862c39b30SMarc-André Lureau 
31962c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
32062c39b30SMarc-André Lureau     g_assert_nonnull(ret);
32162c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
32262c39b30SMarc-André Lureau 
323b3e9e584SMichael Roth     /* sanity-check the response if there are any filesystems */
32462c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
32562c39b30SMarc-André Lureau     entry = qlist_first(list);
326b3e9e584SMichael Roth     if (entry) {
3277dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
3287dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint"));
3297dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type"));
3307dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk"));
331b3e9e584SMichael Roth     }
33262c39b30SMarc-André Lureau }
33362c39b30SMarc-André Lureau 
33462c39b30SMarc-André Lureau static void test_qga_get_memory_block_info(gconstpointer fix)
33562c39b30SMarc-André Lureau {
33662c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
337bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
338bb6960a1SMarc-André Lureau     QDict *val;
33962c39b30SMarc-André Lureau     int64_t size;
34062c39b30SMarc-André Lureau 
34162c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
34262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
34362c39b30SMarc-André Lureau 
34462c39b30SMarc-André Lureau     /* some systems might not expose memory block info in sysfs */
34562c39b30SMarc-André Lureau     if (!qdict_haskey(ret, "error")) {
34662c39b30SMarc-André Lureau         /* check there is at least some memory */
34762c39b30SMarc-André Lureau         val = qdict_get_qdict(ret, "return");
34862c39b30SMarc-André Lureau         size = qdict_get_int(val, "size");
34962c39b30SMarc-André Lureau         g_assert_cmpint(size, >, 0);
35062c39b30SMarc-André Lureau     }
35162c39b30SMarc-André Lureau }
35262c39b30SMarc-André Lureau 
35362c39b30SMarc-André Lureau static void test_qga_get_memory_blocks(gconstpointer fix)
35462c39b30SMarc-André Lureau {
35562c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
356bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
35762c39b30SMarc-André Lureau     QList *list;
35862c39b30SMarc-André Lureau     const QListEntry *entry;
35962c39b30SMarc-André Lureau 
36062c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
36162c39b30SMarc-André Lureau     g_assert_nonnull(ret);
36262c39b30SMarc-André Lureau 
36362c39b30SMarc-André Lureau     /* some systems might not expose memory block info in sysfs */
36462c39b30SMarc-André Lureau     if (!qdict_haskey(ret, "error")) {
36562c39b30SMarc-André Lureau         list = qdict_get_qlist(ret, "return");
36662c39b30SMarc-André Lureau         entry = qlist_first(list);
36762c39b30SMarc-André Lureau         /* newer versions of qga may return empty list without error */
36862c39b30SMarc-André Lureau         if (entry) {
3697dc847ebSMax Reitz             g_assert(qdict_haskey(qobject_to(QDict, entry->value),
3707dc847ebSMax Reitz                                   "phys-index"));
3717dc847ebSMax Reitz             g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
37262c39b30SMarc-André Lureau         }
37362c39b30SMarc-André Lureau     }
37462c39b30SMarc-André Lureau }
37562c39b30SMarc-André Lureau 
37662c39b30SMarc-André Lureau static void test_qga_network_get_interfaces(gconstpointer fix)
37762c39b30SMarc-André Lureau {
37862c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
379bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
38062c39b30SMarc-André Lureau     QList *list;
38162c39b30SMarc-André Lureau     const QListEntry *entry;
38262c39b30SMarc-André Lureau 
38362c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
38462c39b30SMarc-André Lureau     g_assert_nonnull(ret);
38562c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
38662c39b30SMarc-André Lureau 
38762c39b30SMarc-André Lureau     /* check there is at least an interface */
38862c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
38962c39b30SMarc-André Lureau     entry = qlist_first(list);
3907dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
39162c39b30SMarc-André Lureau }
39262c39b30SMarc-André Lureau 
39362c39b30SMarc-André Lureau static void test_qga_file_ops(gconstpointer fix)
39462c39b30SMarc-André Lureau {
39562c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
3964eaab85cSMarc-André Lureau     const unsigned char helloworld[] = "Hello World!\n";
39762c39b30SMarc-André Lureau     const char *b64;
398015715f5SMarkus Armbruster     gchar *path, *enc;
3994eaab85cSMarc-André Lureau     unsigned char *dec;
40062c39b30SMarc-André Lureau     QDict *ret, *val;
40162c39b30SMarc-André Lureau     int64_t id, eof;
40262c39b30SMarc-André Lureau     gsize count;
40362c39b30SMarc-André Lureau     FILE *f;
40462c39b30SMarc-André Lureau     char tmp[100];
40562c39b30SMarc-André Lureau 
40662c39b30SMarc-André Lureau     /* open */
40762c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
40862c39b30SMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
40962c39b30SMarc-André Lureau     g_assert_nonnull(ret);
41062c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
41162c39b30SMarc-André Lureau     id = qdict_get_int(ret, "return");
412cb3e7f08SMarc-André Lureau     qobject_unref(ret);
41362c39b30SMarc-André Lureau 
41462c39b30SMarc-André Lureau     enc = g_base64_encode(helloworld, sizeof(helloworld));
41562c39b30SMarc-André Lureau     /* write */
416015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
417015715f5SMarkus Armbruster                  "{'execute': 'guest-file-write',"
418015715f5SMarkus Armbruster                  " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }",
419015715f5SMarkus Armbruster                  id, enc);
42062c39b30SMarc-André Lureau     g_assert_nonnull(ret);
42162c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
42262c39b30SMarc-André Lureau 
42362c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
42462c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
42562c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
42662c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
42762c39b30SMarc-André Lureau     g_assert_cmpint(eof, ==, 0);
428cb3e7f08SMarc-André Lureau     qobject_unref(ret);
42962c39b30SMarc-André Lureau 
43062c39b30SMarc-André Lureau     /* flush */
431015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
432015715f5SMarkus Armbruster                  "{'execute': 'guest-file-flush',"
43362c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
43462c39b30SMarc-André Lureau                  id);
435cb3e7f08SMarc-André Lureau     qobject_unref(ret);
43662c39b30SMarc-André Lureau 
43762c39b30SMarc-André Lureau     /* close */
438015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
439015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
44062c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
44162c39b30SMarc-André Lureau                  id);
442cb3e7f08SMarc-André Lureau     qobject_unref(ret);
44362c39b30SMarc-André Lureau 
44462c39b30SMarc-André Lureau     /* check content */
44562c39b30SMarc-André Lureau     path = g_build_filename(fixture->test_dir, "foo", NULL);
44662c39b30SMarc-André Lureau     f = fopen(path, "r");
4471e271338SMarc-André Lureau     g_free(path);
44862c39b30SMarc-André Lureau     g_assert_nonnull(f);
44962c39b30SMarc-André Lureau     count = fread(tmp, 1, sizeof(tmp), f);
45062c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
45162c39b30SMarc-André Lureau     tmp[count] = 0;
45262c39b30SMarc-André Lureau     g_assert_cmpstr(tmp, ==, (char *)helloworld);
45362c39b30SMarc-André Lureau     fclose(f);
45462c39b30SMarc-André Lureau 
45562c39b30SMarc-André Lureau     /* open */
45662c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
45762c39b30SMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
45862c39b30SMarc-André Lureau     g_assert_nonnull(ret);
45962c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
46062c39b30SMarc-André Lureau     id = qdict_get_int(ret, "return");
461cb3e7f08SMarc-André Lureau     qobject_unref(ret);
46262c39b30SMarc-André Lureau 
46362c39b30SMarc-André Lureau     /* read */
464015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
465015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
46662c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
46762c39b30SMarc-André Lureau                  id);
46862c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
46962c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
47062c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
47162c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
47262c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
47362c39b30SMarc-André Lureau     g_assert(eof);
47462c39b30SMarc-André Lureau     g_assert_cmpstr(b64, ==, enc);
47562c39b30SMarc-André Lureau 
476cb3e7f08SMarc-André Lureau     qobject_unref(ret);
47762c39b30SMarc-André Lureau     g_free(enc);
47862c39b30SMarc-André Lureau 
47962c39b30SMarc-André Lureau     /* read eof */
480015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
481015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
48262c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
48362c39b30SMarc-André Lureau                  id);
48462c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
48562c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
48662c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
48762c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
48862c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, 0);
48962c39b30SMarc-André Lureau     g_assert(eof);
49062c39b30SMarc-André Lureau     g_assert_cmpstr(b64, ==, "");
491cb3e7f08SMarc-André Lureau     qobject_unref(ret);
49262c39b30SMarc-André Lureau 
49362c39b30SMarc-André Lureau     /* seek */
494015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
495015715f5SMarkus Armbruster                  "{'execute': 'guest-file-seek',"
49662c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ", "
497015715f5SMarkus Armbruster                  " 'offset': %d, 'whence': %s } }",
4980b4b4938SEric Blake                  id, 6, "set");
49962c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
50062c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
50162c39b30SMarc-André Lureau     count = qdict_get_int(val, "position");
50262c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
50362c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, 6);
50462c39b30SMarc-André Lureau     g_assert(!eof);
505cb3e7f08SMarc-André Lureau     qobject_unref(ret);
50662c39b30SMarc-André Lureau 
50762c39b30SMarc-André Lureau     /* partial read */
508015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
509015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
51062c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
51162c39b30SMarc-André Lureau                  id);
51262c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
51362c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
51462c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
51562c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
51662c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
51762c39b30SMarc-André Lureau     g_assert(eof);
51862c39b30SMarc-André Lureau     dec = g_base64_decode(b64, &count);
51962c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
52062c39b30SMarc-André Lureau     g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6);
52162c39b30SMarc-André Lureau     g_free(dec);
52262c39b30SMarc-André Lureau 
523cb3e7f08SMarc-André Lureau     qobject_unref(ret);
52462c39b30SMarc-André Lureau 
52562c39b30SMarc-André Lureau     /* close */
526015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
527015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
52862c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
52962c39b30SMarc-André Lureau                  id);
530cb3e7f08SMarc-André Lureau     qobject_unref(ret);
53162c39b30SMarc-André Lureau }
53262c39b30SMarc-André Lureau 
5334eaab85cSMarc-André Lureau static void test_qga_file_write_read(gconstpointer fix)
5344eaab85cSMarc-André Lureau {
5354eaab85cSMarc-André Lureau     const TestFixture *fixture = fix;
5364eaab85cSMarc-André Lureau     const unsigned char helloworld[] = "Hello World!\n";
5374eaab85cSMarc-André Lureau     const char *b64;
538015715f5SMarkus Armbruster     gchar *enc;
5394eaab85cSMarc-André Lureau     QDict *ret, *val;
5404eaab85cSMarc-André Lureau     int64_t id, eof;
5414eaab85cSMarc-André Lureau     gsize count;
5424eaab85cSMarc-André Lureau 
5434eaab85cSMarc-André Lureau     /* open */
5444eaab85cSMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
5454eaab85cSMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
5464eaab85cSMarc-André Lureau     g_assert_nonnull(ret);
5474eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5484eaab85cSMarc-André Lureau     id = qdict_get_int(ret, "return");
549cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5504eaab85cSMarc-André Lureau 
5514eaab85cSMarc-André Lureau     enc = g_base64_encode(helloworld, sizeof(helloworld));
5524eaab85cSMarc-André Lureau     /* write */
553015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
554015715f5SMarkus Armbruster                  "{'execute': 'guest-file-write',"
5554eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ","
556015715f5SMarkus Armbruster                  " 'buf-b64': %s } }", id, enc);
5574eaab85cSMarc-André Lureau     g_assert_nonnull(ret);
5584eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5594eaab85cSMarc-André Lureau 
5604eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5614eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
5624eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5634eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
5644eaab85cSMarc-André Lureau     g_assert_cmpint(eof, ==, 0);
565cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5664eaab85cSMarc-André Lureau 
5674eaab85cSMarc-André Lureau     /* read (check implicit flush) */
568015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
569015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
5704eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
5714eaab85cSMarc-André Lureau                  id);
5724eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5734eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
5744eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5754eaab85cSMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
5764eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, 0);
5774eaab85cSMarc-André Lureau     g_assert(eof);
5784eaab85cSMarc-André Lureau     g_assert_cmpstr(b64, ==, "");
579cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5804eaab85cSMarc-André Lureau 
5814eaab85cSMarc-André Lureau     /* seek to 0 */
582015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
583015715f5SMarkus Armbruster                  "{'execute': 'guest-file-seek',"
5844eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ", "
585015715f5SMarkus Armbruster                  " 'offset': %d, 'whence': %s } }",
5860b4b4938SEric Blake                  id, 0, "set");
5874eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5884eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5894eaab85cSMarc-André Lureau     count = qdict_get_int(val, "position");
5904eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5914eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, 0);
5924eaab85cSMarc-André Lureau     g_assert(!eof);
593cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5944eaab85cSMarc-André Lureau 
5954eaab85cSMarc-André Lureau     /* read */
596015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
597015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
5984eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
5994eaab85cSMarc-André Lureau                  id);
6004eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
6014eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
6024eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
6034eaab85cSMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
6044eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
6054eaab85cSMarc-André Lureau     g_assert(eof);
6064eaab85cSMarc-André Lureau     g_assert_cmpstr(b64, ==, enc);
607cb3e7f08SMarc-André Lureau     qobject_unref(ret);
6084eaab85cSMarc-André Lureau     g_free(enc);
6094eaab85cSMarc-André Lureau 
6104eaab85cSMarc-André Lureau     /* close */
611015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
612015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
6134eaab85cSMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
6144eaab85cSMarc-André Lureau                  id);
615cb3e7f08SMarc-André Lureau     qobject_unref(ret);
6164eaab85cSMarc-André Lureau }
6174eaab85cSMarc-André Lureau 
61862c39b30SMarc-André Lureau static void test_qga_get_time(gconstpointer fix)
61962c39b30SMarc-André Lureau {
62062c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
621bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
62262c39b30SMarc-André Lureau     int64_t time;
62362c39b30SMarc-André Lureau 
62462c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
62562c39b30SMarc-André Lureau     g_assert_nonnull(ret);
62662c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
62762c39b30SMarc-André Lureau 
62862c39b30SMarc-André Lureau     time = qdict_get_int(ret, "return");
62962c39b30SMarc-André Lureau     g_assert_cmpint(time, >, 0);
63062c39b30SMarc-André Lureau }
63162c39b30SMarc-André Lureau 
632ebf70554SThomas Huth static void test_qga_blockedrpcs(gconstpointer data)
63362c39b30SMarc-André Lureau {
63462c39b30SMarc-André Lureau     TestFixture fix;
63562c39b30SMarc-André Lureau     QDict *ret, *error;
63662c39b30SMarc-André Lureau     const gchar *class, *desc;
63762c39b30SMarc-André Lureau 
638c28afa76STomáš Golembiovský     fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL);
63962c39b30SMarc-André Lureau 
640ebf70554SThomas Huth     /* check blocked RPCs */
64162c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
64262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
64362c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
64462c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
64562c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
6462546be1cSMichal Privoznik     g_assert_cmpstr(class, ==, "CommandNotFound");
64762c39b30SMarc-André Lureau     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
648cb3e7f08SMarc-André Lureau     qobject_unref(ret);
64962c39b30SMarc-André Lureau 
65062c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
65162c39b30SMarc-André Lureau     g_assert_nonnull(ret);
65262c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
65362c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
65462c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
6552546be1cSMichal Privoznik     g_assert_cmpstr(class, ==, "CommandNotFound");
65662c39b30SMarc-André Lureau     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
657cb3e7f08SMarc-André Lureau     qobject_unref(ret);
65862c39b30SMarc-André Lureau 
65962c39b30SMarc-André Lureau     /* check something work */
66062c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
66162c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
662cb3e7f08SMarc-André Lureau     qobject_unref(ret);
66362c39b30SMarc-André Lureau 
66462c39b30SMarc-André Lureau     fixture_tear_down(&fix, NULL);
66562c39b30SMarc-André Lureau }
66662c39b30SMarc-André Lureau 
66762c39b30SMarc-André Lureau static void test_qga_config(gconstpointer data)
66862c39b30SMarc-André Lureau {
66962c39b30SMarc-André Lureau     GError *error = NULL;
670bb6960a1SMarc-André Lureau     g_autofree char *out = NULL;
671bb6960a1SMarc-André Lureau     g_autofree char *err = NULL;
672bb6960a1SMarc-André Lureau     g_autofree char *cwd = NULL;
673bb6960a1SMarc-André Lureau     g_autofree char *cmd = NULL;
674bb6960a1SMarc-André Lureau     g_auto(GStrv) argv = NULL;
675bb6960a1SMarc-André Lureau     g_auto(GStrv) strv = NULL;
676bb6960a1SMarc-André Lureau     g_autoptr(GKeyFile) kf = NULL;
677bb6960a1SMarc-André Lureau     char *str;
67862c39b30SMarc-André Lureau     char *env[2];
6791741b945SMarc-André Lureau     int status;
68062c39b30SMarc-André Lureau     gsize n;
68162c39b30SMarc-André Lureau 
68262c39b30SMarc-André Lureau     cwd = g_get_current_dir();
683f15bff25SPaolo Bonzini     cmd = g_strdup_printf("%s%cqga%cqemu-ga -D",
684f15bff25SPaolo Bonzini                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
68562c39b30SMarc-André Lureau     g_shell_parse_argv(cmd, NULL, &argv, &error);
68662c39b30SMarc-André Lureau     g_assert_no_error(error);
68762c39b30SMarc-André Lureau 
6881741b945SMarc-André Lureau     env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
6891741b945SMarc-André Lureau                              G_DIR_SEPARATOR, G_DIR_SEPARATOR);
69062c39b30SMarc-André Lureau     env[1] = NULL;
69162c39b30SMarc-André Lureau     g_spawn_sync(NULL, argv, env, 0,
69262c39b30SMarc-André Lureau                  NULL, NULL, &out, &err, &status, &error);
6931e271338SMarc-André Lureau 
69462c39b30SMarc-André Lureau     g_assert_no_error(error);
69562c39b30SMarc-André Lureau     g_assert_cmpstr(err, ==, "");
69662c39b30SMarc-André Lureau     g_assert_cmpint(status, ==, 0);
69762c39b30SMarc-André Lureau 
69862c39b30SMarc-André Lureau     kf = g_key_file_new();
69962c39b30SMarc-André Lureau     g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
70062c39b30SMarc-André Lureau     g_assert_no_error(error);
70162c39b30SMarc-André Lureau 
70262c39b30SMarc-André Lureau     str = g_key_file_get_start_group(kf);
70362c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "general");
70462c39b30SMarc-André Lureau     g_free(str);
70562c39b30SMarc-André Lureau 
70662c39b30SMarc-André Lureau     g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error));
70762c39b30SMarc-André Lureau     g_assert_no_error(error);
70862c39b30SMarc-André Lureau 
70962c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "method", &error);
71062c39b30SMarc-André Lureau     g_assert_no_error(error);
71162c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "virtio-serial");
71262c39b30SMarc-André Lureau     g_free(str);
71362c39b30SMarc-André Lureau 
71462c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "path", &error);
71562c39b30SMarc-André Lureau     g_assert_no_error(error);
71662c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
71762c39b30SMarc-André Lureau     g_free(str);
71862c39b30SMarc-André Lureau 
71962c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "pidfile", &error);
72062c39b30SMarc-André Lureau     g_assert_no_error(error);
72162c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
72262c39b30SMarc-André Lureau     g_free(str);
72362c39b30SMarc-André Lureau 
72462c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "statedir", &error);
72562c39b30SMarc-André Lureau     g_assert_no_error(error);
72662c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/var/state");
72762c39b30SMarc-André Lureau     g_free(str);
72862c39b30SMarc-André Lureau 
72962c39b30SMarc-André Lureau     g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error));
73062c39b30SMarc-André Lureau     g_assert_no_error(error);
73162c39b30SMarc-André Lureau 
732*582a098eSThomas Huth     strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error);
73362c39b30SMarc-André Lureau     g_assert_cmpint(n, ==, 2);
73462c39b30SMarc-André Lureau     g_assert_true(g_strv_contains((const char * const *)strv,
73562c39b30SMarc-André Lureau                                   "guest-ping"));
73662c39b30SMarc-André Lureau     g_assert_true(g_strv_contains((const char * const *)strv,
73762c39b30SMarc-André Lureau                                   "guest-get-time"));
73862c39b30SMarc-André Lureau     g_assert_no_error(error);
73962c39b30SMarc-André Lureau 
74062c39b30SMarc-André Lureau     g_free(env[0]);
74162c39b30SMarc-André Lureau }
74262c39b30SMarc-André Lureau 
74362c39b30SMarc-André Lureau static void test_qga_fsfreeze_status(gconstpointer fix)
74462c39b30SMarc-André Lureau {
74562c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
746bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
74762c39b30SMarc-André Lureau     const gchar *status;
74862c39b30SMarc-André Lureau 
74962c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
75062c39b30SMarc-André Lureau     g_assert_nonnull(ret);
75162c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
75262c39b30SMarc-André Lureau 
75362c39b30SMarc-André Lureau     status = qdict_get_try_str(ret, "return");
75462c39b30SMarc-André Lureau     g_assert_cmpstr(status, ==, "thawed");
75562c39b30SMarc-André Lureau }
75662c39b30SMarc-André Lureau 
7573dab9fa1SMarc-André Lureau static void test_qga_guest_exec(gconstpointer fix)
7583dab9fa1SMarc-André Lureau {
7593dab9fa1SMarc-André Lureau     const TestFixture *fixture = fix;
760bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
761bb6960a1SMarc-André Lureau     QDict *val;
7623dab9fa1SMarc-André Lureau     const gchar *out;
763bb6960a1SMarc-André Lureau     g_autofree guchar *decoded = NULL;
7643dab9fa1SMarc-André Lureau     int64_t pid, now, exitcode;
7653dab9fa1SMarc-André Lureau     gsize len;
7663dab9fa1SMarc-André Lureau     bool exited;
7673dab9fa1SMarc-André Lureau 
7683dab9fa1SMarc-André Lureau     /* exec 'echo foo bar' */
7693dab9fa1SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
7703dab9fa1SMarc-André Lureau                  " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ],"
7713dab9fa1SMarc-André Lureau                  " 'capture-output': true } }");
7723dab9fa1SMarc-André Lureau     g_assert_nonnull(ret);
7733dab9fa1SMarc-André Lureau     qmp_assert_no_error(ret);
7743dab9fa1SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
7753dab9fa1SMarc-André Lureau     pid = qdict_get_int(val, "pid");
7763dab9fa1SMarc-André Lureau     g_assert_cmpint(pid, >, 0);
777cb3e7f08SMarc-André Lureau     qobject_unref(ret);
7783dab9fa1SMarc-André Lureau 
7793dab9fa1SMarc-André Lureau     /* wait for completion */
7803dab9fa1SMarc-André Lureau     now = g_get_monotonic_time();
7811792d7d0SEric Blake     do {
782015715f5SMarkus Armbruster         ret = qmp_fd(fixture->fd,
783015715f5SMarkus Armbruster                      "{'execute': 'guest-exec-status',"
784015715f5SMarkus Armbruster                      " 'arguments': { 'pid': %" PRId64 " } }", pid);
7853dab9fa1SMarc-André Lureau         g_assert_nonnull(ret);
7863dab9fa1SMarc-André Lureau         val = qdict_get_qdict(ret, "return");
7873dab9fa1SMarc-André Lureau         exited = qdict_get_bool(val, "exited");
7883dab9fa1SMarc-André Lureau         if (!exited) {
789cb3e7f08SMarc-André Lureau             qobject_unref(ret);
7903dab9fa1SMarc-André Lureau         }
7913dab9fa1SMarc-André Lureau     } while (!exited &&
7923dab9fa1SMarc-André Lureau              g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
7933dab9fa1SMarc-André Lureau     g_assert(exited);
7943dab9fa1SMarc-André Lureau 
7953dab9fa1SMarc-André Lureau     /* check stdout */
7963dab9fa1SMarc-André Lureau     exitcode = qdict_get_int(val, "exitcode");
7973dab9fa1SMarc-André Lureau     g_assert_cmpint(exitcode, ==, 0);
7983dab9fa1SMarc-André Lureau     out = qdict_get_str(val, "out-data");
7993dab9fa1SMarc-André Lureau     decoded = g_base64_decode(out, &len);
8003dab9fa1SMarc-André Lureau     g_assert_cmpint(len, ==, 12);
8013dab9fa1SMarc-André Lureau     g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
8023dab9fa1SMarc-André Lureau }
8033dab9fa1SMarc-André Lureau 
8043dab9fa1SMarc-André Lureau static void test_qga_guest_exec_invalid(gconstpointer fix)
8053dab9fa1SMarc-André Lureau {
8063dab9fa1SMarc-André Lureau     const TestFixture *fixture = fix;
807bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
808bb6960a1SMarc-André Lureau     QDict *error;
8093dab9fa1SMarc-André Lureau     const gchar *class, *desc;
8103dab9fa1SMarc-André Lureau 
8113dab9fa1SMarc-André Lureau     /* invalid command */
8123dab9fa1SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
8133dab9fa1SMarc-André Lureau                  " 'path': '/bin/invalid-cmd42' } }");
8143dab9fa1SMarc-André Lureau     g_assert_nonnull(ret);
8153dab9fa1SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
8163dab9fa1SMarc-André Lureau     g_assert_nonnull(error);
8173dab9fa1SMarc-André Lureau     class = qdict_get_str(error, "class");
8183dab9fa1SMarc-André Lureau     desc = qdict_get_str(error, "desc");
8193dab9fa1SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
8203dab9fa1SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
821cb3e7f08SMarc-André Lureau     qobject_unref(ret);
8223dab9fa1SMarc-André Lureau 
8233dab9fa1SMarc-André Lureau     /* invalid pid */
8243dab9fa1SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
8253dab9fa1SMarc-André Lureau                  " 'arguments': { 'pid': 0 } }");
8263dab9fa1SMarc-André Lureau     g_assert_nonnull(ret);
8273dab9fa1SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
8283dab9fa1SMarc-André Lureau     g_assert_nonnull(error);
8293dab9fa1SMarc-André Lureau     class = qdict_get_str(error, "class");
8303dab9fa1SMarc-André Lureau     desc = qdict_get_str(error, "desc");
8313dab9fa1SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
8323dab9fa1SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
8333dab9fa1SMarc-André Lureau }
8343dab9fa1SMarc-André Lureau 
835509b97fdSTomáš Golembiovský static void test_qga_guest_get_host_name(gconstpointer fix)
836509b97fdSTomáš Golembiovský {
837509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
838bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
839bb6960a1SMarc-André Lureau     QDict *val;
840509b97fdSTomáš Golembiovský 
841509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
842509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
843509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
844509b97fdSTomáš Golembiovský 
845509b97fdSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
846509b97fdSTomáš Golembiovský     g_assert(qdict_haskey(val, "host-name"));
847509b97fdSTomáš Golembiovský }
848509b97fdSTomáš Golembiovský 
849509b97fdSTomáš Golembiovský static void test_qga_guest_get_timezone(gconstpointer fix)
850509b97fdSTomáš Golembiovský {
851509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
852bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
853bb6960a1SMarc-André Lureau     QDict *val;
854509b97fdSTomáš Golembiovský 
855509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
856509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
857509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
858509b97fdSTomáš Golembiovský 
859509b97fdSTomáš Golembiovský     /* Make sure there's at least offset */
860509b97fdSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
861509b97fdSTomáš Golembiovský     g_assert(qdict_haskey(val, "offset"));
862509b97fdSTomáš Golembiovský }
863509b97fdSTomáš Golembiovský 
864509b97fdSTomáš Golembiovský static void test_qga_guest_get_users(gconstpointer fix)
865509b97fdSTomáš Golembiovský {
866509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
867bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
868509b97fdSTomáš Golembiovský     QList *val;
869509b97fdSTomáš Golembiovský 
870509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
871509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
872509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
873509b97fdSTomáš Golembiovský 
874509b97fdSTomáš Golembiovský     /* There is not much to test here */
875509b97fdSTomáš Golembiovský     val = qdict_get_qlist(ret, "return");
876509b97fdSTomáš Golembiovský     g_assert_nonnull(val);
877509b97fdSTomáš Golembiovský }
878509b97fdSTomáš Golembiovský 
879339ca68bSTomáš Golembiovský static void test_qga_guest_get_osinfo(gconstpointer data)
880339ca68bSTomáš Golembiovský {
881339ca68bSTomáš Golembiovský     TestFixture fixture;
882339ca68bSTomáš Golembiovský     const gchar *str;
883bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
884a85d0926SMarc-André Lureau     char *env[2];
885a85d0926SMarc-André Lureau     QDict *val;
886339ca68bSTomáš Golembiovský 
887339ca68bSTomáš Golembiovský     env[0] = g_strdup_printf(
888a85d0926SMarc-André Lureau         "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release",
889a85d0926SMarc-André Lureau         g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
890339ca68bSTomáš Golembiovský     env[1] = NULL;
891339ca68bSTomáš Golembiovský     fixture_setup(&fixture, NULL, env);
892339ca68bSTomáš Golembiovský 
893339ca68bSTomáš Golembiovský     ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
894339ca68bSTomáš Golembiovský     g_assert_nonnull(ret);
895339ca68bSTomáš Golembiovský     qmp_assert_no_error(ret);
896339ca68bSTomáš Golembiovský 
897339ca68bSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
898339ca68bSTomáš Golembiovský 
899339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "id");
900339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
901339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "qemu-ga-test");
902339ca68bSTomáš Golembiovský 
903339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "name");
904339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
905339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "QEMU-GA");
906339ca68bSTomáš Golembiovský 
907339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "pretty-name");
908339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
909339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "QEMU Guest Agent test");
910339ca68bSTomáš Golembiovský 
911339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "version");
912339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
913339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "Test 1");
914339ca68bSTomáš Golembiovský 
915339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "version-id");
916339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
917339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "1");
918339ca68bSTomáš Golembiovský 
919339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "variant");
920339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
921339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc.");
922339ca68bSTomáš Golembiovský 
923339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "variant-id");
924339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
925339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "unit-test");
926339ca68bSTomáš Golembiovský 
927339ca68bSTomáš Golembiovský     g_free(env[0]);
928339ca68bSTomáš Golembiovský     fixture_tear_down(&fixture, NULL);
929339ca68bSTomáš Golembiovský }
930339ca68bSTomáš Golembiovský 
93162c39b30SMarc-André Lureau int main(int argc, char **argv)
93262c39b30SMarc-André Lureau {
93362c39b30SMarc-André Lureau     TestFixture fix;
93462c39b30SMarc-André Lureau     int ret;
93562c39b30SMarc-André Lureau 
936a7bd942cSMarc-André Lureau #ifdef QEMU_SANITIZE_THREAD
937a7bd942cSMarc-André Lureau     {
938a7bd942cSMarc-André Lureau         g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116");
939a7bd942cSMarc-André Lureau         return 0;
940a7bd942cSMarc-André Lureau     }
941a7bd942cSMarc-André Lureau #endif
942a7bd942cSMarc-André Lureau 
94362c39b30SMarc-André Lureau     setlocale (LC_ALL, "");
94462c39b30SMarc-André Lureau     g_test_init(&argc, &argv, NULL);
945c28afa76STomáš Golembiovský     fixture_setup(&fix, NULL, NULL);
94662c39b30SMarc-André Lureau 
94762c39b30SMarc-André Lureau     g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
94862c39b30SMarc-André Lureau     g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
94962c39b30SMarc-André Lureau     g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
95062c39b30SMarc-André Lureau     g_test_add_data_func("/qga/info", &fix, test_qga_info);
95162c39b30SMarc-André Lureau     g_test_add_data_func("/qga/network-get-interfaces", &fix,
95262c39b30SMarc-André Lureau                          test_qga_network_get_interfaces);
953ec72c0e2SBruce Rogers     if (!access("/sys/devices/system/cpu/cpu0", F_OK)) {
95462c39b30SMarc-André Lureau         g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
955ec72c0e2SBruce Rogers     }
95662c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
95762c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-memory-block-info", &fix,
95862c39b30SMarc-André Lureau                          test_qga_get_memory_block_info);
95962c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-memory-blocks", &fix,
96062c39b30SMarc-André Lureau                          test_qga_get_memory_blocks);
96162c39b30SMarc-André Lureau     g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
9624eaab85cSMarc-André Lureau     g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
96362c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
9644eaca8deSMarc-André Lureau     g_test_add_data_func("/qga/id", &fix, test_qga_id);
965d4d7ed73SMarkus Armbruster     g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob);
96662c39b30SMarc-André Lureau     g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
9674bdadd86SMarc-André Lureau     g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args);
96862c39b30SMarc-André Lureau     g_test_add_data_func("/qga/fsfreeze-status", &fix,
96962c39b30SMarc-André Lureau                          test_qga_fsfreeze_status);
97062c39b30SMarc-André Lureau 
971ebf70554SThomas Huth     g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs);
97262c39b30SMarc-André Lureau     g_test_add_data_func("/qga/config", NULL, test_qga_config);
9733dab9fa1SMarc-André Lureau     g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
9743dab9fa1SMarc-André Lureau     g_test_add_data_func("/qga/guest-exec-invalid", &fix,
9753dab9fa1SMarc-André Lureau                          test_qga_guest_exec_invalid);
976339ca68bSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-osinfo", &fix,
977339ca68bSTomáš Golembiovský                          test_qga_guest_get_osinfo);
978509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-host-name", &fix,
979509b97fdSTomáš Golembiovský                          test_qga_guest_get_host_name);
980509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-timezone", &fix,
981509b97fdSTomáš Golembiovský                          test_qga_guest_get_timezone);
982509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-users", &fix,
983509b97fdSTomáš Golembiovský                          test_qga_guest_get_users);
98462c39b30SMarc-André Lureau 
98562c39b30SMarc-André Lureau     ret = g_test_run();
98662c39b30SMarc-André Lureau 
98762c39b30SMarc-André Lureau     fixture_tear_down(&fix, NULL);
98862c39b30SMarc-André Lureau 
98962c39b30SMarc-André Lureau     return ret;
99062c39b30SMarc-André Lureau }
991