xref: /qemu/tests/unit/test-qga.c (revision c7d74f272450b032cd5d1317ee017b4ffe65ee89)
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) {
355dc51100SPaolo Bonzini             close(s);
3662c39b30SMarc-André Lureau             return -1;
3762c39b30SMarc-André Lureau         }
3862c39b30SMarc-André Lureau     } while (ret == -1);
3962c39b30SMarc-André Lureau 
4062c39b30SMarc-André Lureau     return s;
4162c39b30SMarc-André Lureau }
4262c39b30SMarc-André Lureau 
4362c39b30SMarc-André Lureau static void qga_watch(GPid pid, gint status, gpointer user_data)
4462c39b30SMarc-André Lureau {
4562c39b30SMarc-André Lureau     TestFixture *fixture = user_data;
4662c39b30SMarc-André Lureau 
4762c39b30SMarc-André Lureau     g_assert_cmpint(status, ==, 0);
4862c39b30SMarc-André Lureau     g_main_loop_quit(fixture->loop);
4962c39b30SMarc-André Lureau }
5062c39b30SMarc-André Lureau 
5162c39b30SMarc-André Lureau static void
52c28afa76STomáš Golembiovský fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp)
5362c39b30SMarc-André Lureau {
5462c39b30SMarc-André Lureau     const gchar *extra_arg = data;
5562c39b30SMarc-André Lureau     GError *error = NULL;
56bb6960a1SMarc-André Lureau     g_autofree char *cwd = NULL;
57bb6960a1SMarc-André Lureau     g_autofree char *path = NULL;
58bb6960a1SMarc-André Lureau     g_autofree char *cmd = NULL;
59bb6960a1SMarc-André Lureau     g_auto(GStrv) argv = NULL;
6062c39b30SMarc-André Lureau 
6162c39b30SMarc-André Lureau     fixture->loop = g_main_loop_new(NULL, FALSE);
6262c39b30SMarc-André Lureau 
635b9f2781SBin Meng     fixture->test_dir = g_strdup_printf("%s/qgatest.XXXXXX", g_get_tmp_dir());
643c239aa7SBin Meng     g_assert_nonnull(g_mkdtemp(fixture->test_dir));
6562c39b30SMarc-André Lureau 
6662c39b30SMarc-André Lureau     path = g_build_filename(fixture->test_dir, "sock", NULL);
6762c39b30SMarc-André Lureau     cwd = g_get_current_dir();
68f15bff25SPaolo Bonzini     cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s",
69f15bff25SPaolo Bonzini                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR,
7062c39b30SMarc-André Lureau                           fixture->test_dir, path,
7162c39b30SMarc-André Lureau                           getenv("QTEST_LOG") ? "-v" : "",
7262c39b30SMarc-André Lureau                           extra_arg ?: "");
7362c39b30SMarc-André Lureau     g_shell_parse_argv(cmd, NULL, &argv, &error);
7462c39b30SMarc-André Lureau     g_assert_no_error(error);
7562c39b30SMarc-André Lureau 
76c28afa76STomáš Golembiovský     g_spawn_async(fixture->test_dir, argv, envp,
7762c39b30SMarc-André Lureau                   G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
7862c39b30SMarc-André Lureau                   NULL, NULL, &fixture->pid, &error);
7962c39b30SMarc-André Lureau     g_assert_no_error(error);
8062c39b30SMarc-André Lureau 
8162c39b30SMarc-André Lureau     g_child_watch_add(fixture->pid, qga_watch, fixture);
8262c39b30SMarc-André Lureau 
8362c39b30SMarc-André Lureau     fixture->fd = connect_qga(path);
8462c39b30SMarc-André Lureau     g_assert_cmpint(fixture->fd, !=, -1);
8562c39b30SMarc-André Lureau }
8662c39b30SMarc-André Lureau 
8762c39b30SMarc-André Lureau static void
8862c39b30SMarc-André Lureau fixture_tear_down(TestFixture *fixture, gconstpointer data)
8962c39b30SMarc-André Lureau {
90bb6960a1SMarc-André Lureau     g_autofree char *tmp = NULL;
9162c39b30SMarc-André Lureau 
9262c39b30SMarc-André Lureau     kill(fixture->pid, SIGTERM);
9362c39b30SMarc-André Lureau 
9462c39b30SMarc-André Lureau     g_main_loop_run(fixture->loop);
9562c39b30SMarc-André Lureau     g_main_loop_unref(fixture->loop);
9662c39b30SMarc-André Lureau 
9762c39b30SMarc-André Lureau     g_spawn_close_pid(fixture->pid);
9862c39b30SMarc-André Lureau 
9962c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "foo", NULL);
10062c39b30SMarc-André Lureau     g_unlink(tmp);
10162c39b30SMarc-André Lureau     g_free(tmp);
10262c39b30SMarc-André Lureau 
10362c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
10462c39b30SMarc-André Lureau     g_unlink(tmp);
10562c39b30SMarc-André Lureau     g_free(tmp);
10662c39b30SMarc-André Lureau 
10762c39b30SMarc-André Lureau     tmp = g_build_filename(fixture->test_dir, "sock", NULL);
10862c39b30SMarc-André Lureau     g_unlink(tmp);
10962c39b30SMarc-André Lureau 
11062c39b30SMarc-André Lureau     g_rmdir(fixture->test_dir);
11162c39b30SMarc-André Lureau     g_free(fixture->test_dir);
11243d1da7cSAlex Chen     close(fixture->fd);
11362c39b30SMarc-André Lureau }
11462c39b30SMarc-André Lureau 
11562c39b30SMarc-André Lureau static void qmp_assertion_message_error(const char     *domain,
11662c39b30SMarc-André Lureau                                         const char     *file,
11762c39b30SMarc-André Lureau                                         int             line,
11862c39b30SMarc-André Lureau                                         const char     *func,
11962c39b30SMarc-André Lureau                                         const char     *expr,
12062c39b30SMarc-André Lureau                                         QDict          *dict)
12162c39b30SMarc-André Lureau {
12262c39b30SMarc-André Lureau     const char *class, *desc;
123bb6960a1SMarc-André Lureau     g_autofree char *s = NULL;
12462c39b30SMarc-André Lureau     QDict *error;
12562c39b30SMarc-André Lureau 
12662c39b30SMarc-André Lureau     error = qdict_get_qdict(dict, "error");
12762c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
12862c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
12962c39b30SMarc-André Lureau 
13062c39b30SMarc-André Lureau     s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
13162c39b30SMarc-André Lureau     g_assertion_message(domain, file, line, func, s);
13262c39b30SMarc-André Lureau }
13362c39b30SMarc-André Lureau 
13462c39b30SMarc-André Lureau #define qmp_assert_no_error(err) do {                                   \
13562c39b30SMarc-André Lureau     if (qdict_haskey(err, "error")) {                                   \
13662c39b30SMarc-André Lureau         qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
13762c39b30SMarc-André Lureau                                     G_STRFUNC, #err, err);              \
13862c39b30SMarc-André Lureau     }                                                                   \
13962c39b30SMarc-André Lureau } while (0)
14062c39b30SMarc-André Lureau 
14162c39b30SMarc-André Lureau static void test_qga_sync_delimited(gconstpointer fix)
14262c39b30SMarc-André Lureau {
14362c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
1440f555602SPaolo Bonzini     guint32 v, r = g_test_rand_int();
14562c39b30SMarc-André Lureau     unsigned char c;
146bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
14762c39b30SMarc-André Lureau 
148e2f64a68SMarkus Armbruster     qmp_fd_send_raw(fixture->fd, "\xff");
149015715f5SMarkus Armbruster     qmp_fd_send(fixture->fd,
150e2f64a68SMarkus Armbruster                 "{'execute': 'guest-sync-delimited',"
151015715f5SMarkus Armbruster                 " 'arguments': {'id': %u } }",
152015715f5SMarkus Armbruster                 r);
15362c39b30SMarc-André Lureau 
1545229564bSEric Blake     /*
1555229564bSEric Blake      * Read and ignore garbage until resynchronized.
1565229564bSEric Blake      *
1575229564bSEric Blake      * Note that the full reset sequence would involve checking the
1585229564bSEric Blake      * response of guest-sync-delimited and repeating the loop if
1595229564bSEric Blake      * 'id' field of the response does not match the 'id' field of
1605229564bSEric Blake      * the request. Testing this fully would require inserting
1615229564bSEric Blake      * garbage in the response stream and is left as a future test
1625229564bSEric Blake      * to implement.
1635229564bSEric Blake      *
1645229564bSEric Blake      * TODO: The server shouldn't emit so much garbage (among other
1655229564bSEric Blake      * things, it loudly complains about the client's \xff being
1665229564bSEric Blake      * invalid JSON, even though it is a documented part of the
1675229564bSEric Blake      * handshake.
1685229564bSEric Blake      */
1695229564bSEric Blake     do {
17062c39b30SMarc-André Lureau         v = read(fixture->fd, &c, 1);
17162c39b30SMarc-André Lureau         g_assert_cmpint(v, ==, 1);
1725229564bSEric Blake     } while (c != 0xff);
17362c39b30SMarc-André Lureau 
17462c39b30SMarc-André Lureau     ret = qmp_fd_receive(fixture->fd);
17562c39b30SMarc-André Lureau     g_assert_nonnull(ret);
17662c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
17762c39b30SMarc-André Lureau 
17862c39b30SMarc-André Lureau     v = qdict_get_int(ret, "return");
17962c39b30SMarc-André Lureau     g_assert_cmpint(r, ==, v);
18062c39b30SMarc-André Lureau }
18162c39b30SMarc-André Lureau 
18262c39b30SMarc-André Lureau static void test_qga_sync(gconstpointer fix)
18362c39b30SMarc-André Lureau {
18462c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
1850f555602SPaolo Bonzini     guint32 v, r = g_test_rand_int();
186bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
18762c39b30SMarc-André Lureau 
1885229564bSEric Blake     /*
1895229564bSEric Blake      * TODO guest-sync is inherently limited: we cannot distinguish
1905229564bSEric Blake      * failure caused by reacting to garbage on the wire prior to this
1915229564bSEric Blake      * command, from failure of this actual command. Clients are
1925229564bSEric Blake      * supposed to be able to send a raw '\xff' byte to at least
1935229564bSEric Blake      * re-synchronize the server's parser prior to this command, but
1945229564bSEric Blake      * we are not in a position to test that here because (at least
1955229564bSEric Blake      * for now) it causes the server to issue an error message about
1965229564bSEric Blake      * invalid JSON. Testing of '\xff' handling is done in
1975229564bSEric Blake      * guest-sync-delimited instead.
1985229564bSEric Blake      */
199015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
200015715f5SMarkus Armbruster                  "{'execute': 'guest-sync', 'arguments': {'id': %u } }",
201015715f5SMarkus Armbruster                  r);
20262c39b30SMarc-André Lureau 
20362c39b30SMarc-André Lureau     g_assert_nonnull(ret);
20462c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
20562c39b30SMarc-André Lureau 
20662c39b30SMarc-André Lureau     v = qdict_get_int(ret, "return");
20762c39b30SMarc-André Lureau     g_assert_cmpint(r, ==, v);
20862c39b30SMarc-André Lureau }
20962c39b30SMarc-André Lureau 
21062c39b30SMarc-André Lureau static void test_qga_ping(gconstpointer fix)
21162c39b30SMarc-André Lureau {
21262c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
213bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
21462c39b30SMarc-André Lureau 
21562c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
21662c39b30SMarc-André Lureau     g_assert_nonnull(ret);
21762c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
21862c39b30SMarc-André Lureau }
21962c39b30SMarc-André Lureau 
2204eaca8deSMarc-André Lureau static void test_qga_id(gconstpointer fix)
221b5f84310SMarkus Armbruster {
222b5f84310SMarkus Armbruster     const TestFixture *fixture = fix;
223bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
224b5f84310SMarkus Armbruster 
225b5f84310SMarkus Armbruster     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
226b5f84310SMarkus Armbruster     g_assert_nonnull(ret);
2274eaca8deSMarc-André Lureau     qmp_assert_no_error(ret);
2284eaca8deSMarc-André Lureau     g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1);
229b5f84310SMarkus Armbruster }
230b5f84310SMarkus Armbruster 
231d4d7ed73SMarkus Armbruster static void test_qga_invalid_oob(gconstpointer fix)
232d4d7ed73SMarkus Armbruster {
233d4d7ed73SMarkus Armbruster     const TestFixture *fixture = fix;
234ebb4d82dSMarc-André Lureau     QDict *ret;
235d4d7ed73SMarkus Armbruster 
23600ecec15SMarkus Armbruster     ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}");
237d4d7ed73SMarkus Armbruster     g_assert_nonnull(ret);
238d4d7ed73SMarkus Armbruster 
2393bc1b8eeSMarkus Armbruster     qmp_expect_error_and_unref(ret, "GenericError");
240d4d7ed73SMarkus Armbruster }
241d4d7ed73SMarkus Armbruster 
2424bdadd86SMarc-André Lureau static void test_qga_invalid_args(gconstpointer fix)
2434bdadd86SMarc-André Lureau {
2444bdadd86SMarc-André Lureau     const TestFixture *fixture = fix;
245bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
246bb6960a1SMarc-André Lureau     QDict *error;
2474bdadd86SMarc-André Lureau     const gchar *class, *desc;
2484bdadd86SMarc-André Lureau 
2494bdadd86SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
2504bdadd86SMarc-André Lureau                  "'arguments': {'foo': 42 }}");
2514bdadd86SMarc-André Lureau     g_assert_nonnull(ret);
2524bdadd86SMarc-André Lureau 
2534bdadd86SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
2544bdadd86SMarc-André Lureau     class = qdict_get_try_str(error, "class");
2554bdadd86SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
2564bdadd86SMarc-André Lureau 
2574bdadd86SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
258910f738bSMarkus Armbruster     g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
2594bdadd86SMarc-André Lureau }
2604bdadd86SMarc-André Lureau 
26162c39b30SMarc-André Lureau static void test_qga_invalid_cmd(gconstpointer fix)
26262c39b30SMarc-André Lureau {
26362c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
264bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
265bb6960a1SMarc-André Lureau     QDict *error;
26662c39b30SMarc-André Lureau     const gchar *class, *desc;
26762c39b30SMarc-André Lureau 
26862c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
26962c39b30SMarc-André Lureau     g_assert_nonnull(ret);
27062c39b30SMarc-André Lureau 
27162c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
27262c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
27362c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
27462c39b30SMarc-André Lureau 
27562c39b30SMarc-André Lureau     g_assert_cmpstr(class, ==, "CommandNotFound");
27662c39b30SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
27762c39b30SMarc-André Lureau }
27862c39b30SMarc-André Lureau 
27962c39b30SMarc-André Lureau static void test_qga_info(gconstpointer fix)
28062c39b30SMarc-André Lureau {
28162c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
282bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
283bb6960a1SMarc-André Lureau     QDict *val;
28462c39b30SMarc-André Lureau     const gchar *version;
28562c39b30SMarc-André Lureau 
28662c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
28762c39b30SMarc-André Lureau     g_assert_nonnull(ret);
28862c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
28962c39b30SMarc-André Lureau 
29062c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
29162c39b30SMarc-André Lureau     version = qdict_get_try_str(val, "version");
29262c39b30SMarc-André Lureau     g_assert_cmpstr(version, ==, QEMU_VERSION);
29362c39b30SMarc-André Lureau }
29462c39b30SMarc-André Lureau 
29562c39b30SMarc-André Lureau static void test_qga_get_vcpus(gconstpointer fix)
29662c39b30SMarc-André Lureau {
29762c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
298bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
29962c39b30SMarc-André Lureau     QList *list;
30062c39b30SMarc-André Lureau     const QListEntry *entry;
30162c39b30SMarc-André Lureau 
30262c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
30362c39b30SMarc-André Lureau     g_assert_nonnull(ret);
30462c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
30562c39b30SMarc-André Lureau 
30662c39b30SMarc-André Lureau     /* check there is at least a cpu */
30762c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
30862c39b30SMarc-André Lureau     entry = qlist_first(list);
3097dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
3107dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id"));
31162c39b30SMarc-André Lureau }
31262c39b30SMarc-André Lureau 
31362c39b30SMarc-André Lureau static void test_qga_get_fsinfo(gconstpointer fix)
31462c39b30SMarc-André Lureau {
31562c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
316bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
31762c39b30SMarc-André Lureau     QList *list;
31862c39b30SMarc-André Lureau     const QListEntry *entry;
31962c39b30SMarc-André Lureau 
32062c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
32162c39b30SMarc-André Lureau     g_assert_nonnull(ret);
32262c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
32362c39b30SMarc-André Lureau 
324b3e9e584SMichael Roth     /* sanity-check the response if there are any filesystems */
32562c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
32662c39b30SMarc-André Lureau     entry = qlist_first(list);
327b3e9e584SMichael Roth     if (entry) {
3287dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
3297dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint"));
3307dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type"));
3317dc847ebSMax Reitz         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk"));
332b3e9e584SMichael Roth     }
33362c39b30SMarc-André Lureau }
33462c39b30SMarc-André Lureau 
33562c39b30SMarc-André Lureau static void test_qga_get_memory_block_info(gconstpointer fix)
33662c39b30SMarc-André Lureau {
33762c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
338bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
339bb6960a1SMarc-André Lureau     QDict *val;
34062c39b30SMarc-André Lureau     int64_t size;
34162c39b30SMarc-André Lureau 
34262c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
34362c39b30SMarc-André Lureau     g_assert_nonnull(ret);
34462c39b30SMarc-André Lureau 
34562c39b30SMarc-André Lureau     /* some systems might not expose memory block info in sysfs */
34662c39b30SMarc-André Lureau     if (!qdict_haskey(ret, "error")) {
34762c39b30SMarc-André Lureau         /* check there is at least some memory */
34862c39b30SMarc-André Lureau         val = qdict_get_qdict(ret, "return");
34962c39b30SMarc-André Lureau         size = qdict_get_int(val, "size");
35062c39b30SMarc-André Lureau         g_assert_cmpint(size, >, 0);
35162c39b30SMarc-André Lureau     }
35262c39b30SMarc-André Lureau }
35362c39b30SMarc-André Lureau 
35462c39b30SMarc-André Lureau static void test_qga_get_memory_blocks(gconstpointer fix)
35562c39b30SMarc-André Lureau {
35662c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
357bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
35862c39b30SMarc-André Lureau     QList *list;
35962c39b30SMarc-André Lureau     const QListEntry *entry;
36062c39b30SMarc-André Lureau 
36162c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
36262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
36362c39b30SMarc-André Lureau 
36462c39b30SMarc-André Lureau     /* some systems might not expose memory block info in sysfs */
36562c39b30SMarc-André Lureau     if (!qdict_haskey(ret, "error")) {
36662c39b30SMarc-André Lureau         list = qdict_get_qlist(ret, "return");
36762c39b30SMarc-André Lureau         entry = qlist_first(list);
36862c39b30SMarc-André Lureau         /* newer versions of qga may return empty list without error */
36962c39b30SMarc-André Lureau         if (entry) {
3707dc847ebSMax Reitz             g_assert(qdict_haskey(qobject_to(QDict, entry->value),
3717dc847ebSMax Reitz                                   "phys-index"));
3727dc847ebSMax Reitz             g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
37362c39b30SMarc-André Lureau         }
37462c39b30SMarc-André Lureau     }
37562c39b30SMarc-André Lureau }
37662c39b30SMarc-André Lureau 
37762c39b30SMarc-André Lureau static void test_qga_network_get_interfaces(gconstpointer fix)
37862c39b30SMarc-André Lureau {
37962c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
380bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
38162c39b30SMarc-André Lureau     QList *list;
38262c39b30SMarc-André Lureau     const QListEntry *entry;
38362c39b30SMarc-André Lureau 
38462c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
38562c39b30SMarc-André Lureau     g_assert_nonnull(ret);
38662c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
38762c39b30SMarc-André Lureau 
38862c39b30SMarc-André Lureau     /* check there is at least an interface */
38962c39b30SMarc-André Lureau     list = qdict_get_qlist(ret, "return");
39062c39b30SMarc-André Lureau     entry = qlist_first(list);
3917dc847ebSMax Reitz     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
39262c39b30SMarc-André Lureau }
39362c39b30SMarc-André Lureau 
39462c39b30SMarc-André Lureau static void test_qga_file_ops(gconstpointer fix)
39562c39b30SMarc-André Lureau {
39662c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
3974eaab85cSMarc-André Lureau     const unsigned char helloworld[] = "Hello World!\n";
39862c39b30SMarc-André Lureau     const char *b64;
399015715f5SMarkus Armbruster     gchar *path, *enc;
4004eaab85cSMarc-André Lureau     unsigned char *dec;
40162c39b30SMarc-André Lureau     QDict *ret, *val;
40262c39b30SMarc-André Lureau     int64_t id, eof;
40362c39b30SMarc-André Lureau     gsize count;
40462c39b30SMarc-André Lureau     FILE *f;
40562c39b30SMarc-André Lureau     char tmp[100];
40662c39b30SMarc-André Lureau 
40762c39b30SMarc-André Lureau     /* open */
40862c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
40962c39b30SMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
41062c39b30SMarc-André Lureau     g_assert_nonnull(ret);
41162c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
41262c39b30SMarc-André Lureau     id = qdict_get_int(ret, "return");
413cb3e7f08SMarc-André Lureau     qobject_unref(ret);
41462c39b30SMarc-André Lureau 
41562c39b30SMarc-André Lureau     enc = g_base64_encode(helloworld, sizeof(helloworld));
41662c39b30SMarc-André Lureau     /* write */
417015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
418015715f5SMarkus Armbruster                  "{'execute': 'guest-file-write',"
419015715f5SMarkus Armbruster                  " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }",
420015715f5SMarkus Armbruster                  id, enc);
42162c39b30SMarc-André Lureau     g_assert_nonnull(ret);
42262c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
42362c39b30SMarc-André Lureau 
42462c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
42562c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
42662c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
42762c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
42862c39b30SMarc-André Lureau     g_assert_cmpint(eof, ==, 0);
429cb3e7f08SMarc-André Lureau     qobject_unref(ret);
43062c39b30SMarc-André Lureau 
43162c39b30SMarc-André Lureau     /* flush */
432015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
433015715f5SMarkus Armbruster                  "{'execute': 'guest-file-flush',"
43462c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
43562c39b30SMarc-André Lureau                  id);
436cb3e7f08SMarc-André Lureau     qobject_unref(ret);
43762c39b30SMarc-André Lureau 
43862c39b30SMarc-André Lureau     /* close */
439015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
440015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
44162c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
44262c39b30SMarc-André Lureau                  id);
443cb3e7f08SMarc-André Lureau     qobject_unref(ret);
44462c39b30SMarc-André Lureau 
44562c39b30SMarc-André Lureau     /* check content */
44662c39b30SMarc-André Lureau     path = g_build_filename(fixture->test_dir, "foo", NULL);
44762c39b30SMarc-André Lureau     f = fopen(path, "r");
4481e271338SMarc-André Lureau     g_free(path);
44962c39b30SMarc-André Lureau     g_assert_nonnull(f);
45062c39b30SMarc-André Lureau     count = fread(tmp, 1, sizeof(tmp), f);
45162c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
45262c39b30SMarc-André Lureau     tmp[count] = 0;
45362c39b30SMarc-André Lureau     g_assert_cmpstr(tmp, ==, (char *)helloworld);
45462c39b30SMarc-André Lureau     fclose(f);
45562c39b30SMarc-André Lureau 
45662c39b30SMarc-André Lureau     /* open */
45762c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
45862c39b30SMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
45962c39b30SMarc-André Lureau     g_assert_nonnull(ret);
46062c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
46162c39b30SMarc-André Lureau     id = qdict_get_int(ret, "return");
462cb3e7f08SMarc-André Lureau     qobject_unref(ret);
46362c39b30SMarc-André Lureau 
46462c39b30SMarc-André Lureau     /* read */
465015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
466015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
46762c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
46862c39b30SMarc-André Lureau                  id);
46962c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
47062c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
47162c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
47262c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
47362c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
47462c39b30SMarc-André Lureau     g_assert(eof);
47562c39b30SMarc-André Lureau     g_assert_cmpstr(b64, ==, enc);
47662c39b30SMarc-André Lureau 
477cb3e7f08SMarc-André Lureau     qobject_unref(ret);
47862c39b30SMarc-André Lureau     g_free(enc);
47962c39b30SMarc-André Lureau 
48062c39b30SMarc-André Lureau     /* read eof */
481015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
482015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
48362c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
48462c39b30SMarc-André Lureau                  id);
48562c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
48662c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
48762c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
48862c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
48962c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, 0);
49062c39b30SMarc-André Lureau     g_assert(eof);
49162c39b30SMarc-André Lureau     g_assert_cmpstr(b64, ==, "");
492cb3e7f08SMarc-André Lureau     qobject_unref(ret);
49362c39b30SMarc-André Lureau 
49462c39b30SMarc-André Lureau     /* seek */
495015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
496015715f5SMarkus Armbruster                  "{'execute': 'guest-file-seek',"
49762c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ", "
498015715f5SMarkus Armbruster                  " 'offset': %d, 'whence': %s } }",
4990b4b4938SEric Blake                  id, 6, "set");
50062c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
50162c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
50262c39b30SMarc-André Lureau     count = qdict_get_int(val, "position");
50362c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
50462c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, 6);
50562c39b30SMarc-André Lureau     g_assert(!eof);
506cb3e7f08SMarc-André Lureau     qobject_unref(ret);
50762c39b30SMarc-André Lureau 
50862c39b30SMarc-André Lureau     /* partial read */
509015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
510015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
51162c39b30SMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
51262c39b30SMarc-André Lureau                  id);
51362c39b30SMarc-André Lureau     val = qdict_get_qdict(ret, "return");
51462c39b30SMarc-André Lureau     count = qdict_get_int(val, "count");
51562c39b30SMarc-André Lureau     eof = qdict_get_bool(val, "eof");
51662c39b30SMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
51762c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
51862c39b30SMarc-André Lureau     g_assert(eof);
51962c39b30SMarc-André Lureau     dec = g_base64_decode(b64, &count);
52062c39b30SMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
52162c39b30SMarc-André Lureau     g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6);
52262c39b30SMarc-André Lureau     g_free(dec);
52362c39b30SMarc-André Lureau 
524cb3e7f08SMarc-André Lureau     qobject_unref(ret);
52562c39b30SMarc-André Lureau 
52662c39b30SMarc-André Lureau     /* close */
527015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
528015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
52962c39b30SMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
53062c39b30SMarc-André Lureau                  id);
531cb3e7f08SMarc-André Lureau     qobject_unref(ret);
53262c39b30SMarc-André Lureau }
53362c39b30SMarc-André Lureau 
5344eaab85cSMarc-André Lureau static void test_qga_file_write_read(gconstpointer fix)
5354eaab85cSMarc-André Lureau {
5364eaab85cSMarc-André Lureau     const TestFixture *fixture = fix;
5374eaab85cSMarc-André Lureau     const unsigned char helloworld[] = "Hello World!\n";
5384eaab85cSMarc-André Lureau     const char *b64;
539015715f5SMarkus Armbruster     gchar *enc;
5404eaab85cSMarc-André Lureau     QDict *ret, *val;
5414eaab85cSMarc-André Lureau     int64_t id, eof;
5424eaab85cSMarc-André Lureau     gsize count;
5434eaab85cSMarc-André Lureau 
5444eaab85cSMarc-André Lureau     /* open */
5454eaab85cSMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
5464eaab85cSMarc-André Lureau                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
5474eaab85cSMarc-André Lureau     g_assert_nonnull(ret);
5484eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5494eaab85cSMarc-André Lureau     id = qdict_get_int(ret, "return");
550cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5514eaab85cSMarc-André Lureau 
5524eaab85cSMarc-André Lureau     enc = g_base64_encode(helloworld, sizeof(helloworld));
5534eaab85cSMarc-André Lureau     /* write */
554015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
555015715f5SMarkus Armbruster                  "{'execute': 'guest-file-write',"
5564eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ","
557015715f5SMarkus Armbruster                  " 'buf-b64': %s } }", id, enc);
5584eaab85cSMarc-André Lureau     g_assert_nonnull(ret);
5594eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5604eaab85cSMarc-André Lureau 
5614eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5624eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
5634eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5644eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
5654eaab85cSMarc-André Lureau     g_assert_cmpint(eof, ==, 0);
566cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5674eaab85cSMarc-André Lureau 
5684eaab85cSMarc-André Lureau     /* read (check implicit flush) */
569015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
570015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
5714eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
5724eaab85cSMarc-André Lureau                  id);
5734eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5744eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
5754eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5764eaab85cSMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
5774eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, 0);
5784eaab85cSMarc-André Lureau     g_assert(eof);
5794eaab85cSMarc-André Lureau     g_assert_cmpstr(b64, ==, "");
580cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5814eaab85cSMarc-André Lureau 
5824eaab85cSMarc-André Lureau     /* seek to 0 */
583015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
584015715f5SMarkus Armbruster                  "{'execute': 'guest-file-seek',"
5854eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 ", "
586015715f5SMarkus Armbruster                  " 'offset': %d, 'whence': %s } }",
5870b4b4938SEric Blake                  id, 0, "set");
5884eaab85cSMarc-André Lureau     qmp_assert_no_error(ret);
5894eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
5904eaab85cSMarc-André Lureau     count = qdict_get_int(val, "position");
5914eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
5924eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, 0);
5934eaab85cSMarc-André Lureau     g_assert(!eof);
594cb3e7f08SMarc-André Lureau     qobject_unref(ret);
5954eaab85cSMarc-André Lureau 
5964eaab85cSMarc-André Lureau     /* read */
597015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
598015715f5SMarkus Armbruster                  "{'execute': 'guest-file-read',"
5994eaab85cSMarc-André Lureau                  " 'arguments': { 'handle': %" PRId64 "} }",
6004eaab85cSMarc-André Lureau                  id);
6014eaab85cSMarc-André Lureau     val = qdict_get_qdict(ret, "return");
6024eaab85cSMarc-André Lureau     count = qdict_get_int(val, "count");
6034eaab85cSMarc-André Lureau     eof = qdict_get_bool(val, "eof");
6044eaab85cSMarc-André Lureau     b64 = qdict_get_str(val, "buf-b64");
6054eaab85cSMarc-André Lureau     g_assert_cmpint(count, ==, sizeof(helloworld));
6064eaab85cSMarc-André Lureau     g_assert(eof);
6074eaab85cSMarc-André Lureau     g_assert_cmpstr(b64, ==, enc);
608cb3e7f08SMarc-André Lureau     qobject_unref(ret);
6094eaab85cSMarc-André Lureau     g_free(enc);
6104eaab85cSMarc-André Lureau 
6114eaab85cSMarc-André Lureau     /* close */
612015715f5SMarkus Armbruster     ret = qmp_fd(fixture->fd,
613015715f5SMarkus Armbruster                  "{'execute': 'guest-file-close',"
6144eaab85cSMarc-André Lureau                  " 'arguments': {'handle': %" PRId64 "} }",
6154eaab85cSMarc-André Lureau                  id);
616cb3e7f08SMarc-André Lureau     qobject_unref(ret);
6174eaab85cSMarc-André Lureau }
6184eaab85cSMarc-André Lureau 
61962c39b30SMarc-André Lureau static void test_qga_get_time(gconstpointer fix)
62062c39b30SMarc-André Lureau {
62162c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
622bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
62362c39b30SMarc-André Lureau     int64_t time;
62462c39b30SMarc-André Lureau 
62562c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
62662c39b30SMarc-André Lureau     g_assert_nonnull(ret);
62762c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
62862c39b30SMarc-André Lureau 
62962c39b30SMarc-André Lureau     time = qdict_get_int(ret, "return");
63062c39b30SMarc-André Lureau     g_assert_cmpint(time, >, 0);
63162c39b30SMarc-André Lureau }
63262c39b30SMarc-André Lureau 
633ebf70554SThomas Huth static void test_qga_blockedrpcs(gconstpointer data)
63462c39b30SMarc-André Lureau {
63562c39b30SMarc-André Lureau     TestFixture fix;
63662c39b30SMarc-André Lureau     QDict *ret, *error;
63762c39b30SMarc-André Lureau     const gchar *class, *desc;
63862c39b30SMarc-André Lureau 
639c28afa76STomáš Golembiovský     fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL);
64062c39b30SMarc-André Lureau 
641ebf70554SThomas Huth     /* check blocked RPCs */
64262c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
64362c39b30SMarc-André Lureau     g_assert_nonnull(ret);
64462c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
64562c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
64662c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
6472546be1cSMichal Privoznik     g_assert_cmpstr(class, ==, "CommandNotFound");
64862c39b30SMarc-André Lureau     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
649cb3e7f08SMarc-André Lureau     qobject_unref(ret);
65062c39b30SMarc-André Lureau 
65162c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
65262c39b30SMarc-André Lureau     g_assert_nonnull(ret);
65362c39b30SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
65462c39b30SMarc-André Lureau     class = qdict_get_try_str(error, "class");
65562c39b30SMarc-André Lureau     desc = qdict_get_try_str(error, "desc");
6562546be1cSMichal Privoznik     g_assert_cmpstr(class, ==, "CommandNotFound");
65762c39b30SMarc-André Lureau     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
658cb3e7f08SMarc-André Lureau     qobject_unref(ret);
65962c39b30SMarc-André Lureau 
66062c39b30SMarc-André Lureau     /* check something work */
66162c39b30SMarc-André Lureau     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
66262c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
663cb3e7f08SMarc-André Lureau     qobject_unref(ret);
66462c39b30SMarc-André Lureau 
66562c39b30SMarc-André Lureau     fixture_tear_down(&fix, NULL);
66662c39b30SMarc-André Lureau }
66762c39b30SMarc-André Lureau 
66862c39b30SMarc-André Lureau static void test_qga_config(gconstpointer data)
66962c39b30SMarc-André Lureau {
67062c39b30SMarc-André Lureau     GError *error = NULL;
671bb6960a1SMarc-André Lureau     g_autofree char *out = NULL;
672bb6960a1SMarc-André Lureau     g_autofree char *err = NULL;
673bb6960a1SMarc-André Lureau     g_autofree char *cwd = NULL;
674bb6960a1SMarc-André Lureau     g_autofree char *cmd = NULL;
675bb6960a1SMarc-André Lureau     g_auto(GStrv) argv = NULL;
676bb6960a1SMarc-André Lureau     g_auto(GStrv) strv = NULL;
677bb6960a1SMarc-André Lureau     g_autoptr(GKeyFile) kf = NULL;
678bb6960a1SMarc-André Lureau     char *str;
67962c39b30SMarc-André Lureau     char *env[2];
6801741b945SMarc-André Lureau     int status;
68162c39b30SMarc-André Lureau     gsize n;
68262c39b30SMarc-André Lureau 
68362c39b30SMarc-André Lureau     cwd = g_get_current_dir();
684f15bff25SPaolo Bonzini     cmd = g_strdup_printf("%s%cqga%cqemu-ga -D",
685f15bff25SPaolo Bonzini                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
68662c39b30SMarc-André Lureau     g_shell_parse_argv(cmd, NULL, &argv, &error);
68762c39b30SMarc-André Lureau     g_assert_no_error(error);
68862c39b30SMarc-André Lureau 
6891741b945SMarc-André Lureau     env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
6901741b945SMarc-André Lureau                              G_DIR_SEPARATOR, G_DIR_SEPARATOR);
69162c39b30SMarc-André Lureau     env[1] = NULL;
69262c39b30SMarc-André Lureau     g_spawn_sync(NULL, argv, env, 0,
69362c39b30SMarc-André Lureau                  NULL, NULL, &out, &err, &status, &error);
6941e271338SMarc-André Lureau 
69562c39b30SMarc-André Lureau     g_assert_no_error(error);
69662c39b30SMarc-André Lureau     g_assert_cmpstr(err, ==, "");
69762c39b30SMarc-André Lureau     g_assert_cmpint(status, ==, 0);
69862c39b30SMarc-André Lureau 
69962c39b30SMarc-André Lureau     kf = g_key_file_new();
70062c39b30SMarc-André Lureau     g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
70162c39b30SMarc-André Lureau     g_assert_no_error(error);
70262c39b30SMarc-André Lureau 
70362c39b30SMarc-André Lureau     str = g_key_file_get_start_group(kf);
70462c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "general");
70562c39b30SMarc-André Lureau     g_free(str);
70662c39b30SMarc-André Lureau 
70762c39b30SMarc-André Lureau     g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error));
70862c39b30SMarc-André Lureau     g_assert_no_error(error);
70962c39b30SMarc-André Lureau 
71062c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "method", &error);
71162c39b30SMarc-André Lureau     g_assert_no_error(error);
71262c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "virtio-serial");
71362c39b30SMarc-André Lureau     g_free(str);
71462c39b30SMarc-André Lureau 
71562c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "path", &error);
71662c39b30SMarc-André Lureau     g_assert_no_error(error);
71762c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
71862c39b30SMarc-André Lureau     g_free(str);
71962c39b30SMarc-André Lureau 
72062c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "pidfile", &error);
72162c39b30SMarc-André Lureau     g_assert_no_error(error);
72262c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
72362c39b30SMarc-André Lureau     g_free(str);
72462c39b30SMarc-André Lureau 
72562c39b30SMarc-André Lureau     str = g_key_file_get_string(kf, "general", "statedir", &error);
72662c39b30SMarc-André Lureau     g_assert_no_error(error);
72762c39b30SMarc-André Lureau     g_assert_cmpstr(str, ==, "/var/state");
72862c39b30SMarc-André Lureau     g_free(str);
72962c39b30SMarc-André Lureau 
73062c39b30SMarc-André Lureau     g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error));
73162c39b30SMarc-André Lureau     g_assert_no_error(error);
73262c39b30SMarc-André Lureau 
733582a098eSThomas Huth     strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error);
73462c39b30SMarc-André Lureau     g_assert_cmpint(n, ==, 2);
73562c39b30SMarc-André Lureau     g_assert_true(g_strv_contains((const char * const *)strv,
73662c39b30SMarc-André Lureau                                   "guest-ping"));
73762c39b30SMarc-André Lureau     g_assert_true(g_strv_contains((const char * const *)strv,
73862c39b30SMarc-André Lureau                                   "guest-get-time"));
73962c39b30SMarc-André Lureau     g_assert_no_error(error);
74062c39b30SMarc-André Lureau 
74162c39b30SMarc-André Lureau     g_free(env[0]);
74262c39b30SMarc-André Lureau }
74362c39b30SMarc-André Lureau 
74462c39b30SMarc-André Lureau static void test_qga_fsfreeze_status(gconstpointer fix)
74562c39b30SMarc-André Lureau {
74662c39b30SMarc-André Lureau     const TestFixture *fixture = fix;
747bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
74862c39b30SMarc-André Lureau     const gchar *status;
74962c39b30SMarc-André Lureau 
75062c39b30SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
75162c39b30SMarc-André Lureau     g_assert_nonnull(ret);
75262c39b30SMarc-André Lureau     qmp_assert_no_error(ret);
75362c39b30SMarc-André Lureau 
75462c39b30SMarc-André Lureau     status = qdict_get_try_str(ret, "return");
75562c39b30SMarc-André Lureau     g_assert_cmpstr(status, ==, "thawed");
75662c39b30SMarc-André Lureau }
75762c39b30SMarc-André Lureau 
758*c7d74f27SDaniel Xu static QDict *wait_for_guest_exec_completion(int fd, int64_t pid)
7593dab9fa1SMarc-André Lureau {
760*c7d74f27SDaniel Xu     QDict *ret = NULL;
761*c7d74f27SDaniel Xu     int64_t now;
7623dab9fa1SMarc-André Lureau     bool exited;
763*c7d74f27SDaniel Xu     QDict *val;
7643dab9fa1SMarc-André Lureau 
7653dab9fa1SMarc-André Lureau     now = g_get_monotonic_time();
7661792d7d0SEric Blake     do {
767*c7d74f27SDaniel Xu         ret = qmp_fd(fd,
768015715f5SMarkus Armbruster                      "{'execute': 'guest-exec-status',"
769015715f5SMarkus Armbruster                      " 'arguments': { 'pid': %" PRId64 " } }", pid);
7703dab9fa1SMarc-André Lureau         g_assert_nonnull(ret);
7713dab9fa1SMarc-André Lureau         val = qdict_get_qdict(ret, "return");
7723dab9fa1SMarc-André Lureau         exited = qdict_get_bool(val, "exited");
7733dab9fa1SMarc-André Lureau         if (!exited) {
774cb3e7f08SMarc-André Lureau             qobject_unref(ret);
7753dab9fa1SMarc-André Lureau         }
7763dab9fa1SMarc-André Lureau     } while (!exited &&
7773dab9fa1SMarc-André Lureau              g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
7783dab9fa1SMarc-André Lureau     g_assert(exited);
7793dab9fa1SMarc-André Lureau 
780*c7d74f27SDaniel Xu     return ret;
781*c7d74f27SDaniel Xu }
782*c7d74f27SDaniel Xu 
783*c7d74f27SDaniel Xu static void test_qga_guest_exec(gconstpointer fix)
784*c7d74f27SDaniel Xu {
785*c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
786*c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
787*c7d74f27SDaniel Xu     QDict *val;
788*c7d74f27SDaniel Xu     const gchar *out;
789*c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
790*c7d74f27SDaniel Xu     int64_t pid, exitcode;
791*c7d74f27SDaniel Xu     gsize len;
792*c7d74f27SDaniel Xu 
793*c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
794*c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
795*c7d74f27SDaniel Xu                  " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ],"
796*c7d74f27SDaniel Xu                  " 'capture-output': true } }");
797*c7d74f27SDaniel Xu     g_assert_nonnull(ret);
798*c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
799*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
800*c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
801*c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
802*c7d74f27SDaniel Xu     qobject_unref(ret);
803*c7d74f27SDaniel Xu 
804*c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
805*c7d74f27SDaniel Xu 
8063dab9fa1SMarc-André Lureau     /* check stdout */
807*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
8083dab9fa1SMarc-André Lureau     exitcode = qdict_get_int(val, "exitcode");
8093dab9fa1SMarc-André Lureau     g_assert_cmpint(exitcode, ==, 0);
8103dab9fa1SMarc-André Lureau     out = qdict_get_str(val, "out-data");
8113dab9fa1SMarc-André Lureau     decoded = g_base64_decode(out, &len);
8123dab9fa1SMarc-André Lureau     g_assert_cmpint(len, ==, 12);
8133dab9fa1SMarc-André Lureau     g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
8143dab9fa1SMarc-André Lureau }
8153dab9fa1SMarc-André Lureau 
816*c7d74f27SDaniel Xu #if defined(G_OS_WIN32)
817*c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix)
818*c7d74f27SDaniel Xu {
819*c7d74f27SDaniel Xu }
820*c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix)
821*c7d74f27SDaniel Xu {
822*c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
823*c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
824*c7d74f27SDaniel Xu     QDict *val;
825*c7d74f27SDaniel Xu     const gchar *class, *desc;
826*c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
827*c7d74f27SDaniel Xu 
828*c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
829*c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
830*c7d74f27SDaniel Xu                  " 'path': 'echo',"
831*c7d74f27SDaniel Xu                  " 'arg': [ 'execution never reaches here' ],"
832*c7d74f27SDaniel Xu                  " 'capture-output': 'merged' } }");
833*c7d74f27SDaniel Xu 
834*c7d74f27SDaniel Xu     g_assert_nonnull(ret);
835*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "error");
836*c7d74f27SDaniel Xu     g_assert_nonnull(val);
837*c7d74f27SDaniel Xu     class = qdict_get_str(val, "class");
838*c7d74f27SDaniel Xu     desc = qdict_get_str(val, "desc");
839*c7d74f27SDaniel Xu     g_assert_cmpstr(class, ==, "GenericError");
840*c7d74f27SDaniel Xu     g_assert_cmpint(strlen(desc), >, 0);
841*c7d74f27SDaniel Xu }
842*c7d74f27SDaniel Xu #else
843*c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix)
844*c7d74f27SDaniel Xu {
845*c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
846*c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
847*c7d74f27SDaniel Xu     QDict *val;
848*c7d74f27SDaniel Xu     const gchar *out, *err;
849*c7d74f27SDaniel Xu     g_autofree guchar *out_decoded = NULL;
850*c7d74f27SDaniel Xu     g_autofree guchar *err_decoded = NULL;
851*c7d74f27SDaniel Xu     int64_t pid, exitcode;
852*c7d74f27SDaniel Xu     gsize len;
853*c7d74f27SDaniel Xu 
854*c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
855*c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
856*c7d74f27SDaniel Xu                  " 'path': '/bin/bash',"
857*c7d74f27SDaniel Xu                  " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
858*c7d74f27SDaniel Xu                  " 'capture-output': 'separated' } }");
859*c7d74f27SDaniel Xu     g_assert_nonnull(ret);
860*c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
861*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
862*c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
863*c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
864*c7d74f27SDaniel Xu     qobject_unref(ret);
865*c7d74f27SDaniel Xu 
866*c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
867*c7d74f27SDaniel Xu 
868*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
869*c7d74f27SDaniel Xu     exitcode = qdict_get_int(val, "exitcode");
870*c7d74f27SDaniel Xu     g_assert_cmpint(exitcode, ==, 0);
871*c7d74f27SDaniel Xu 
872*c7d74f27SDaniel Xu     /* check stdout */
873*c7d74f27SDaniel Xu     out = qdict_get_str(val, "out-data");
874*c7d74f27SDaniel Xu     out_decoded = g_base64_decode(out, &len);
875*c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 14);
876*c7d74f27SDaniel Xu     g_assert_cmpstr((char *)out_decoded, ==, "stdout\nstdout\n");
877*c7d74f27SDaniel Xu 
878*c7d74f27SDaniel Xu     /* check stderr */
879*c7d74f27SDaniel Xu     err = qdict_get_try_str(val, "err-data");
880*c7d74f27SDaniel Xu     err_decoded = g_base64_decode(err, &len);
881*c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 14);
882*c7d74f27SDaniel Xu     g_assert_cmpstr((char *)err_decoded, ==, "stderr\nstderr\n");
883*c7d74f27SDaniel Xu }
884*c7d74f27SDaniel Xu 
885*c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix)
886*c7d74f27SDaniel Xu {
887*c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
888*c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
889*c7d74f27SDaniel Xu     QDict *val;
890*c7d74f27SDaniel Xu     const gchar *out, *err;
891*c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
892*c7d74f27SDaniel Xu     int64_t pid, exitcode;
893*c7d74f27SDaniel Xu     gsize len;
894*c7d74f27SDaniel Xu 
895*c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
896*c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
897*c7d74f27SDaniel Xu                  " 'path': '/bin/bash',"
898*c7d74f27SDaniel Xu                  " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
899*c7d74f27SDaniel Xu                  " 'capture-output': 'merged' } }");
900*c7d74f27SDaniel Xu     g_assert_nonnull(ret);
901*c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
902*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
903*c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
904*c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
905*c7d74f27SDaniel Xu     qobject_unref(ret);
906*c7d74f27SDaniel Xu 
907*c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
908*c7d74f27SDaniel Xu 
909*c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
910*c7d74f27SDaniel Xu     exitcode = qdict_get_int(val, "exitcode");
911*c7d74f27SDaniel Xu     g_assert_cmpint(exitcode, ==, 0);
912*c7d74f27SDaniel Xu 
913*c7d74f27SDaniel Xu     /* check stdout */
914*c7d74f27SDaniel Xu     out = qdict_get_str(val, "out-data");
915*c7d74f27SDaniel Xu     decoded = g_base64_decode(out, &len);
916*c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 28);
917*c7d74f27SDaniel Xu     g_assert_cmpstr((char *)decoded, ==, "stdout\nstderr\nstdout\nstderr\n");
918*c7d74f27SDaniel Xu 
919*c7d74f27SDaniel Xu     /* check stderr */
920*c7d74f27SDaniel Xu     err = qdict_get_try_str(val, "err-data");
921*c7d74f27SDaniel Xu     g_assert_null(err);
922*c7d74f27SDaniel Xu }
923*c7d74f27SDaniel Xu #endif
924*c7d74f27SDaniel Xu 
9253dab9fa1SMarc-André Lureau static void test_qga_guest_exec_invalid(gconstpointer fix)
9263dab9fa1SMarc-André Lureau {
9273dab9fa1SMarc-André Lureau     const TestFixture *fixture = fix;
928bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
929bb6960a1SMarc-André Lureau     QDict *error;
9303dab9fa1SMarc-André Lureau     const gchar *class, *desc;
9313dab9fa1SMarc-André Lureau 
9323dab9fa1SMarc-André Lureau     /* invalid command */
9333dab9fa1SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
9343dab9fa1SMarc-André Lureau                  " 'path': '/bin/invalid-cmd42' } }");
9353dab9fa1SMarc-André Lureau     g_assert_nonnull(ret);
9363dab9fa1SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
9373dab9fa1SMarc-André Lureau     g_assert_nonnull(error);
9383dab9fa1SMarc-André Lureau     class = qdict_get_str(error, "class");
9393dab9fa1SMarc-André Lureau     desc = qdict_get_str(error, "desc");
9403dab9fa1SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
9413dab9fa1SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
942cb3e7f08SMarc-André Lureau     qobject_unref(ret);
9433dab9fa1SMarc-André Lureau 
9443dab9fa1SMarc-André Lureau     /* invalid pid */
9453dab9fa1SMarc-André Lureau     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
9463dab9fa1SMarc-André Lureau                  " 'arguments': { 'pid': 0 } }");
9473dab9fa1SMarc-André Lureau     g_assert_nonnull(ret);
9483dab9fa1SMarc-André Lureau     error = qdict_get_qdict(ret, "error");
9493dab9fa1SMarc-André Lureau     g_assert_nonnull(error);
9503dab9fa1SMarc-André Lureau     class = qdict_get_str(error, "class");
9513dab9fa1SMarc-André Lureau     desc = qdict_get_str(error, "desc");
9523dab9fa1SMarc-André Lureau     g_assert_cmpstr(class, ==, "GenericError");
9533dab9fa1SMarc-André Lureau     g_assert_cmpint(strlen(desc), >, 0);
9543dab9fa1SMarc-André Lureau }
9553dab9fa1SMarc-André Lureau 
956509b97fdSTomáš Golembiovský static void test_qga_guest_get_host_name(gconstpointer fix)
957509b97fdSTomáš Golembiovský {
958509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
959bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
960bb6960a1SMarc-André Lureau     QDict *val;
961509b97fdSTomáš Golembiovský 
962509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
963509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
964509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
965509b97fdSTomáš Golembiovský 
966509b97fdSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
967509b97fdSTomáš Golembiovský     g_assert(qdict_haskey(val, "host-name"));
968509b97fdSTomáš Golembiovský }
969509b97fdSTomáš Golembiovský 
970509b97fdSTomáš Golembiovský static void test_qga_guest_get_timezone(gconstpointer fix)
971509b97fdSTomáš Golembiovský {
972509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
973bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
974bb6960a1SMarc-André Lureau     QDict *val;
975509b97fdSTomáš Golembiovský 
976509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
977509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
978509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
979509b97fdSTomáš Golembiovský 
980509b97fdSTomáš Golembiovský     /* Make sure there's at least offset */
981509b97fdSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
982509b97fdSTomáš Golembiovský     g_assert(qdict_haskey(val, "offset"));
983509b97fdSTomáš Golembiovský }
984509b97fdSTomáš Golembiovský 
985509b97fdSTomáš Golembiovský static void test_qga_guest_get_users(gconstpointer fix)
986509b97fdSTomáš Golembiovský {
987509b97fdSTomáš Golembiovský     const TestFixture *fixture = fix;
988bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
989509b97fdSTomáš Golembiovský     QList *val;
990509b97fdSTomáš Golembiovský 
991509b97fdSTomáš Golembiovský     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
992509b97fdSTomáš Golembiovský     g_assert_nonnull(ret);
993509b97fdSTomáš Golembiovský     qmp_assert_no_error(ret);
994509b97fdSTomáš Golembiovský 
995509b97fdSTomáš Golembiovský     /* There is not much to test here */
996509b97fdSTomáš Golembiovský     val = qdict_get_qlist(ret, "return");
997509b97fdSTomáš Golembiovský     g_assert_nonnull(val);
998509b97fdSTomáš Golembiovský }
999509b97fdSTomáš Golembiovský 
1000339ca68bSTomáš Golembiovský static void test_qga_guest_get_osinfo(gconstpointer data)
1001339ca68bSTomáš Golembiovský {
1002339ca68bSTomáš Golembiovský     TestFixture fixture;
1003339ca68bSTomáš Golembiovský     const gchar *str;
1004bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
1005a85d0926SMarc-André Lureau     char *env[2];
1006a85d0926SMarc-André Lureau     QDict *val;
1007339ca68bSTomáš Golembiovský 
1008339ca68bSTomáš Golembiovský     env[0] = g_strdup_printf(
1009a85d0926SMarc-André Lureau         "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release",
1010a85d0926SMarc-André Lureau         g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
1011339ca68bSTomáš Golembiovský     env[1] = NULL;
1012339ca68bSTomáš Golembiovský     fixture_setup(&fixture, NULL, env);
1013339ca68bSTomáš Golembiovský 
1014339ca68bSTomáš Golembiovský     ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
1015339ca68bSTomáš Golembiovský     g_assert_nonnull(ret);
1016339ca68bSTomáš Golembiovský     qmp_assert_no_error(ret);
1017339ca68bSTomáš Golembiovský 
1018339ca68bSTomáš Golembiovský     val = qdict_get_qdict(ret, "return");
1019339ca68bSTomáš Golembiovský 
1020339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "id");
1021339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1022339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "qemu-ga-test");
1023339ca68bSTomáš Golembiovský 
1024339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "name");
1025339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1026339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "QEMU-GA");
1027339ca68bSTomáš Golembiovský 
1028339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "pretty-name");
1029339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1030339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "QEMU Guest Agent test");
1031339ca68bSTomáš Golembiovský 
1032339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "version");
1033339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1034339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "Test 1");
1035339ca68bSTomáš Golembiovský 
1036339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "version-id");
1037339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1038339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "1");
1039339ca68bSTomáš Golembiovský 
1040339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "variant");
1041339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1042339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc.");
1043339ca68bSTomáš Golembiovský 
1044339ca68bSTomáš Golembiovský     str = qdict_get_try_str(val, "variant-id");
1045339ca68bSTomáš Golembiovský     g_assert_nonnull(str);
1046339ca68bSTomáš Golembiovský     g_assert_cmpstr(str, ==, "unit-test");
1047339ca68bSTomáš Golembiovský 
1048339ca68bSTomáš Golembiovský     g_free(env[0]);
1049339ca68bSTomáš Golembiovský     fixture_tear_down(&fixture, NULL);
1050339ca68bSTomáš Golembiovský }
1051339ca68bSTomáš Golembiovský 
105262c39b30SMarc-André Lureau int main(int argc, char **argv)
105362c39b30SMarc-André Lureau {
105462c39b30SMarc-André Lureau     TestFixture fix;
105562c39b30SMarc-André Lureau     int ret;
105662c39b30SMarc-André Lureau 
1057a7bd942cSMarc-André Lureau #ifdef QEMU_SANITIZE_THREAD
1058a7bd942cSMarc-André Lureau     {
1059a7bd942cSMarc-André Lureau         g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116");
1060a7bd942cSMarc-André Lureau         return 0;
1061a7bd942cSMarc-André Lureau     }
1062a7bd942cSMarc-André Lureau #endif
1063a7bd942cSMarc-André Lureau 
106462c39b30SMarc-André Lureau     setlocale (LC_ALL, "");
106562c39b30SMarc-André Lureau     g_test_init(&argc, &argv, NULL);
1066c28afa76STomáš Golembiovský     fixture_setup(&fix, NULL, NULL);
106762c39b30SMarc-André Lureau 
106862c39b30SMarc-André Lureau     g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
106962c39b30SMarc-André Lureau     g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
107062c39b30SMarc-André Lureau     g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
107162c39b30SMarc-André Lureau     g_test_add_data_func("/qga/info", &fix, test_qga_info);
107262c39b30SMarc-André Lureau     g_test_add_data_func("/qga/network-get-interfaces", &fix,
107362c39b30SMarc-André Lureau                          test_qga_network_get_interfaces);
1074ec72c0e2SBruce Rogers     if (!access("/sys/devices/system/cpu/cpu0", F_OK)) {
107562c39b30SMarc-André Lureau         g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
1076ec72c0e2SBruce Rogers     }
107762c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
107862c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-memory-block-info", &fix,
107962c39b30SMarc-André Lureau                          test_qga_get_memory_block_info);
108062c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-memory-blocks", &fix,
108162c39b30SMarc-André Lureau                          test_qga_get_memory_blocks);
108262c39b30SMarc-André Lureau     g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
10834eaab85cSMarc-André Lureau     g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
108462c39b30SMarc-André Lureau     g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
10854eaca8deSMarc-André Lureau     g_test_add_data_func("/qga/id", &fix, test_qga_id);
1086d4d7ed73SMarkus Armbruster     g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob);
108762c39b30SMarc-André Lureau     g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
10884bdadd86SMarc-André Lureau     g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args);
108962c39b30SMarc-André Lureau     g_test_add_data_func("/qga/fsfreeze-status", &fix,
109062c39b30SMarc-André Lureau                          test_qga_fsfreeze_status);
109162c39b30SMarc-André Lureau 
1092ebf70554SThomas Huth     g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs);
109362c39b30SMarc-André Lureau     g_test_add_data_func("/qga/config", NULL, test_qga_config);
10943dab9fa1SMarc-André Lureau     g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
1095*c7d74f27SDaniel Xu     g_test_add_data_func("/qga/guest-exec-separated", &fix,
1096*c7d74f27SDaniel Xu                          test_qga_guest_exec_separated);
1097*c7d74f27SDaniel Xu     g_test_add_data_func("/qga/guest-exec-merged", &fix,
1098*c7d74f27SDaniel Xu                          test_qga_guest_exec_merged);
10993dab9fa1SMarc-André Lureau     g_test_add_data_func("/qga/guest-exec-invalid", &fix,
11003dab9fa1SMarc-André Lureau                          test_qga_guest_exec_invalid);
1101339ca68bSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-osinfo", &fix,
1102339ca68bSTomáš Golembiovský                          test_qga_guest_get_osinfo);
1103509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-host-name", &fix,
1104509b97fdSTomáš Golembiovský                          test_qga_guest_get_host_name);
1105509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-timezone", &fix,
1106509b97fdSTomáš Golembiovský                          test_qga_guest_get_timezone);
1107509b97fdSTomáš Golembiovský     g_test_add_data_func("/qga/guest-get-users", &fix,
1108509b97fdSTomáš Golembiovský                          test_qga_guest_get_users);
110962c39b30SMarc-André Lureau 
111062c39b30SMarc-André Lureau     ret = g_test_run();
111162c39b30SMarc-André Lureau 
111262c39b30SMarc-André Lureau     fixture_tear_down(&fix, NULL);
111362c39b30SMarc-André Lureau 
111462c39b30SMarc-André Lureau     return ret;
111562c39b30SMarc-André Lureau }
1116