xref: /openbmc/qemu/tests/unit/test-qga.c (revision bd2e12310b18b51aefbf834e6d54989fd175976f)
1da668aa1SThomas Huth #include "qemu/osdep.h"
2da668aa1SThomas Huth #include <locale.h>
3da668aa1SThomas Huth #include <glib/gstdio.h>
4da668aa1SThomas Huth #include <sys/socket.h>
5da668aa1SThomas Huth #include <sys/un.h>
6da668aa1SThomas Huth 
7907b5105SMarc-André Lureau #include "../qtest/libqtest.h"
8da668aa1SThomas Huth #include "qapi/qmp/qdict.h"
9da668aa1SThomas Huth #include "qapi/qmp/qlist.h"
10da668aa1SThomas Huth 
11da668aa1SThomas Huth typedef struct {
12da668aa1SThomas Huth     char *test_dir;
13da668aa1SThomas Huth     GMainLoop *loop;
14da668aa1SThomas Huth     int fd;
15da668aa1SThomas Huth     GPid pid;
16da668aa1SThomas Huth } TestFixture;
17da668aa1SThomas Huth 
connect_qga(char * path)18da668aa1SThomas Huth static int connect_qga(char *path)
19da668aa1SThomas Huth {
20da668aa1SThomas Huth     int s, ret, len, i = 0;
21da668aa1SThomas Huth     struct sockaddr_un remote;
22da668aa1SThomas Huth 
23da668aa1SThomas Huth     s = socket(AF_UNIX, SOCK_STREAM, 0);
24da668aa1SThomas Huth     g_assert(s != -1);
25da668aa1SThomas Huth 
26da668aa1SThomas Huth     remote.sun_family = AF_UNIX;
27da668aa1SThomas Huth     do {
28da668aa1SThomas Huth         strcpy(remote.sun_path, path);
29da668aa1SThomas Huth         len = strlen(remote.sun_path) + sizeof(remote.sun_family);
30da668aa1SThomas Huth         ret = connect(s, (struct sockaddr *)&remote, len);
31da668aa1SThomas Huth         if (ret == -1) {
32da668aa1SThomas Huth             g_usleep(G_USEC_PER_SEC);
33da668aa1SThomas Huth         }
34da668aa1SThomas Huth         if (i++ == 10) {
355dc51100SPaolo Bonzini             close(s);
36da668aa1SThomas Huth             return -1;
37da668aa1SThomas Huth         }
38da668aa1SThomas Huth     } while (ret == -1);
39da668aa1SThomas Huth 
40da668aa1SThomas Huth     return s;
41da668aa1SThomas Huth }
42da668aa1SThomas Huth 
qga_watch(GPid pid,gint status,gpointer user_data)43da668aa1SThomas Huth static void qga_watch(GPid pid, gint status, gpointer user_data)
44da668aa1SThomas Huth {
45da668aa1SThomas Huth     TestFixture *fixture = user_data;
46da668aa1SThomas Huth 
47da668aa1SThomas Huth     g_assert_cmpint(status, ==, 0);
48da668aa1SThomas Huth     g_main_loop_quit(fixture->loop);
49da668aa1SThomas Huth }
50da668aa1SThomas Huth 
51da668aa1SThomas Huth static void
fixture_setup(TestFixture * fixture,gconstpointer data,gchar ** envp)52da668aa1SThomas Huth fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp)
53da668aa1SThomas Huth {
54da668aa1SThomas Huth     const gchar *extra_arg = data;
55da668aa1SThomas Huth     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;
60da668aa1SThomas Huth 
61da668aa1SThomas Huth     fixture->loop = g_main_loop_new(NULL, FALSE);
62da668aa1SThomas Huth 
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));
65da668aa1SThomas Huth 
66da668aa1SThomas Huth     path = g_build_filename(fixture->test_dir, "sock", NULL);
67da668aa1SThomas Huth     cwd = g_get_current_dir();
68da668aa1SThomas Huth     cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s",
69da668aa1SThomas Huth                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR,
70da668aa1SThomas Huth                           fixture->test_dir, path,
71da668aa1SThomas Huth                           getenv("QTEST_LOG") ? "-v" : "",
72da668aa1SThomas Huth                           extra_arg ?: "");
73da668aa1SThomas Huth     g_shell_parse_argv(cmd, NULL, &argv, &error);
74da668aa1SThomas Huth     g_assert_no_error(error);
75da668aa1SThomas Huth 
76da668aa1SThomas Huth     g_spawn_async(fixture->test_dir, argv, envp,
77da668aa1SThomas Huth                   G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
78da668aa1SThomas Huth                   NULL, NULL, &fixture->pid, &error);
79da668aa1SThomas Huth     g_assert_no_error(error);
80da668aa1SThomas Huth 
81da668aa1SThomas Huth     g_child_watch_add(fixture->pid, qga_watch, fixture);
82da668aa1SThomas Huth 
83da668aa1SThomas Huth     fixture->fd = connect_qga(path);
84da668aa1SThomas Huth     g_assert_cmpint(fixture->fd, !=, -1);
85da668aa1SThomas Huth }
86da668aa1SThomas Huth 
87da668aa1SThomas Huth static void
fixture_tear_down(TestFixture * fixture,gconstpointer data)88da668aa1SThomas Huth fixture_tear_down(TestFixture *fixture, gconstpointer data)
89da668aa1SThomas Huth {
90bb6960a1SMarc-André Lureau     g_autofree char *tmp = NULL;
91da668aa1SThomas Huth 
92da668aa1SThomas Huth     kill(fixture->pid, SIGTERM);
93da668aa1SThomas Huth 
94da668aa1SThomas Huth     g_main_loop_run(fixture->loop);
95da668aa1SThomas Huth     g_main_loop_unref(fixture->loop);
96da668aa1SThomas Huth 
97da668aa1SThomas Huth     g_spawn_close_pid(fixture->pid);
98da668aa1SThomas Huth 
99da668aa1SThomas Huth     tmp = g_build_filename(fixture->test_dir, "foo", NULL);
100da668aa1SThomas Huth     g_unlink(tmp);
101da668aa1SThomas Huth     g_free(tmp);
102da668aa1SThomas Huth 
103da668aa1SThomas Huth     tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
104da668aa1SThomas Huth     g_unlink(tmp);
105da668aa1SThomas Huth     g_free(tmp);
106da668aa1SThomas Huth 
107da668aa1SThomas Huth     tmp = g_build_filename(fixture->test_dir, "sock", NULL);
108da668aa1SThomas Huth     g_unlink(tmp);
109da668aa1SThomas Huth 
110da668aa1SThomas Huth     g_rmdir(fixture->test_dir);
111da668aa1SThomas Huth     g_free(fixture->test_dir);
112da668aa1SThomas Huth     close(fixture->fd);
113da668aa1SThomas Huth }
114da668aa1SThomas Huth 
qmp_assertion_message_error(const char * domain,const char * file,int line,const char * func,const char * expr,QDict * dict)115da668aa1SThomas Huth static void qmp_assertion_message_error(const char     *domain,
116da668aa1SThomas Huth                                         const char     *file,
117da668aa1SThomas Huth                                         int             line,
118da668aa1SThomas Huth                                         const char     *func,
119da668aa1SThomas Huth                                         const char     *expr,
120da668aa1SThomas Huth                                         QDict          *dict)
121da668aa1SThomas Huth {
122da668aa1SThomas Huth     const char *class, *desc;
123bb6960a1SMarc-André Lureau     g_autofree char *s = NULL;
124da668aa1SThomas Huth     QDict *error;
125da668aa1SThomas Huth 
126da668aa1SThomas Huth     error = qdict_get_qdict(dict, "error");
127da668aa1SThomas Huth     class = qdict_get_try_str(error, "class");
128da668aa1SThomas Huth     desc = qdict_get_try_str(error, "desc");
129da668aa1SThomas Huth 
130da668aa1SThomas Huth     s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
131da668aa1SThomas Huth     g_assertion_message(domain, file, line, func, s);
132da668aa1SThomas Huth }
133da668aa1SThomas Huth 
134da668aa1SThomas Huth #define qmp_assert_no_error(err) do {                                   \
135da668aa1SThomas Huth     if (qdict_haskey(err, "error")) {                                   \
136da668aa1SThomas Huth         qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
137da668aa1SThomas Huth                                     G_STRFUNC, #err, err);              \
138da668aa1SThomas Huth     }                                                                   \
139da668aa1SThomas Huth } while (0)
140da668aa1SThomas Huth 
test_qga_sync_delimited(gconstpointer fix)141da668aa1SThomas Huth static void test_qga_sync_delimited(gconstpointer fix)
142da668aa1SThomas Huth {
143da668aa1SThomas Huth     const TestFixture *fixture = fix;
144da668aa1SThomas Huth     guint32 v, r = g_test_rand_int();
145da668aa1SThomas Huth     unsigned char c;
146bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
147da668aa1SThomas Huth 
148da668aa1SThomas Huth     qmp_fd_send_raw(fixture->fd, "\xff");
149da668aa1SThomas Huth     qmp_fd_send(fixture->fd,
150da668aa1SThomas Huth                 "{'execute': 'guest-sync-delimited',"
151da668aa1SThomas Huth                 " 'arguments': {'id': %u } }",
152da668aa1SThomas Huth                 r);
153da668aa1SThomas Huth 
154da668aa1SThomas Huth     /*
155da668aa1SThomas Huth      * Read and ignore garbage until resynchronized.
156da668aa1SThomas Huth      *
157da668aa1SThomas Huth      * Note that the full reset sequence would involve checking the
158da668aa1SThomas Huth      * response of guest-sync-delimited and repeating the loop if
159da668aa1SThomas Huth      * 'id' field of the response does not match the 'id' field of
160da668aa1SThomas Huth      * the request. Testing this fully would require inserting
161da668aa1SThomas Huth      * garbage in the response stream and is left as a future test
162da668aa1SThomas Huth      * to implement.
163da668aa1SThomas Huth      *
164da668aa1SThomas Huth      * TODO: The server shouldn't emit so much garbage (among other
165da668aa1SThomas Huth      * things, it loudly complains about the client's \xff being
166da668aa1SThomas Huth      * invalid JSON, even though it is a documented part of the
167da668aa1SThomas Huth      * handshake.
168da668aa1SThomas Huth      */
169da668aa1SThomas Huth     do {
170da668aa1SThomas Huth         v = read(fixture->fd, &c, 1);
171da668aa1SThomas Huth         g_assert_cmpint(v, ==, 1);
172da668aa1SThomas Huth     } while (c != 0xff);
173da668aa1SThomas Huth 
174da668aa1SThomas Huth     ret = qmp_fd_receive(fixture->fd);
175da668aa1SThomas Huth     g_assert_nonnull(ret);
176da668aa1SThomas Huth     qmp_assert_no_error(ret);
177da668aa1SThomas Huth 
178da668aa1SThomas Huth     v = qdict_get_int(ret, "return");
179da668aa1SThomas Huth     g_assert_cmpint(r, ==, v);
180da668aa1SThomas Huth }
181da668aa1SThomas Huth 
test_qga_sync(gconstpointer fix)182da668aa1SThomas Huth static void test_qga_sync(gconstpointer fix)
183da668aa1SThomas Huth {
184da668aa1SThomas Huth     const TestFixture *fixture = fix;
185da668aa1SThomas Huth     guint32 v, r = g_test_rand_int();
186bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
187da668aa1SThomas Huth 
188da668aa1SThomas Huth     /*
189da668aa1SThomas Huth      * TODO guest-sync is inherently limited: we cannot distinguish
190da668aa1SThomas Huth      * failure caused by reacting to garbage on the wire prior to this
191da668aa1SThomas Huth      * command, from failure of this actual command. Clients are
192da668aa1SThomas Huth      * supposed to be able to send a raw '\xff' byte to at least
193da668aa1SThomas Huth      * re-synchronize the server's parser prior to this command, but
194da668aa1SThomas Huth      * we are not in a position to test that here because (at least
195da668aa1SThomas Huth      * for now) it causes the server to issue an error message about
196da668aa1SThomas Huth      * invalid JSON. Testing of '\xff' handling is done in
197da668aa1SThomas Huth      * guest-sync-delimited instead.
198da668aa1SThomas Huth      */
199da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
200da668aa1SThomas Huth                  "{'execute': 'guest-sync', 'arguments': {'id': %u } }",
201da668aa1SThomas Huth                  r);
202da668aa1SThomas Huth 
203da668aa1SThomas Huth     g_assert_nonnull(ret);
204da668aa1SThomas Huth     qmp_assert_no_error(ret);
205da668aa1SThomas Huth 
206da668aa1SThomas Huth     v = qdict_get_int(ret, "return");
207da668aa1SThomas Huth     g_assert_cmpint(r, ==, v);
208da668aa1SThomas Huth }
209da668aa1SThomas Huth 
test_qga_ping(gconstpointer fix)210da668aa1SThomas Huth static void test_qga_ping(gconstpointer fix)
211da668aa1SThomas Huth {
212da668aa1SThomas Huth     const TestFixture *fixture = fix;
213bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
214da668aa1SThomas Huth 
215da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
216da668aa1SThomas Huth     g_assert_nonnull(ret);
217da668aa1SThomas Huth     qmp_assert_no_error(ret);
218da668aa1SThomas Huth }
219da668aa1SThomas Huth 
test_qga_id(gconstpointer fix)220da668aa1SThomas Huth static void test_qga_id(gconstpointer fix)
221da668aa1SThomas Huth {
222da668aa1SThomas Huth     const TestFixture *fixture = fix;
223bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
224da668aa1SThomas Huth 
225da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
226da668aa1SThomas Huth     g_assert_nonnull(ret);
227da668aa1SThomas Huth     qmp_assert_no_error(ret);
228da668aa1SThomas Huth     g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1);
229da668aa1SThomas Huth }
230da668aa1SThomas Huth 
test_qga_invalid_oob(gconstpointer fix)231da668aa1SThomas Huth static void test_qga_invalid_oob(gconstpointer fix)
232da668aa1SThomas Huth {
233da668aa1SThomas Huth     const TestFixture *fixture = fix;
234da668aa1SThomas Huth     QDict *ret;
235da668aa1SThomas Huth 
236da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}");
237da668aa1SThomas Huth     g_assert_nonnull(ret);
238da668aa1SThomas Huth 
239da668aa1SThomas Huth     qmp_expect_error_and_unref(ret, "GenericError");
240da668aa1SThomas Huth }
241da668aa1SThomas Huth 
test_qga_invalid_args(gconstpointer fix)242da668aa1SThomas Huth static void test_qga_invalid_args(gconstpointer fix)
243da668aa1SThomas Huth {
244da668aa1SThomas Huth     const TestFixture *fixture = fix;
245bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
246bb6960a1SMarc-André Lureau     QDict *error;
247da668aa1SThomas Huth     const gchar *class, *desc;
248da668aa1SThomas Huth 
249da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
250da668aa1SThomas Huth                  "'arguments': {'foo': 42 }}");
251da668aa1SThomas Huth     g_assert_nonnull(ret);
252da668aa1SThomas Huth 
253da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
254da668aa1SThomas Huth     class = qdict_get_try_str(error, "class");
255da668aa1SThomas Huth     desc = qdict_get_try_str(error, "desc");
256da668aa1SThomas Huth 
257da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "GenericError");
258da668aa1SThomas Huth     g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
259da668aa1SThomas Huth }
260da668aa1SThomas Huth 
test_qga_invalid_cmd(gconstpointer fix)261da668aa1SThomas Huth static void test_qga_invalid_cmd(gconstpointer fix)
262da668aa1SThomas Huth {
263da668aa1SThomas Huth     const TestFixture *fixture = fix;
264bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
265bb6960a1SMarc-André Lureau     QDict *error;
266da668aa1SThomas Huth     const gchar *class, *desc;
267da668aa1SThomas Huth 
268da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
269da668aa1SThomas Huth     g_assert_nonnull(ret);
270da668aa1SThomas Huth 
271da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
272da668aa1SThomas Huth     class = qdict_get_try_str(error, "class");
273da668aa1SThomas Huth     desc = qdict_get_try_str(error, "desc");
274da668aa1SThomas Huth 
275da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "CommandNotFound");
276da668aa1SThomas Huth     g_assert_cmpint(strlen(desc), >, 0);
277da668aa1SThomas Huth }
278da668aa1SThomas Huth 
test_qga_info(gconstpointer fix)279da668aa1SThomas Huth static void test_qga_info(gconstpointer fix)
280da668aa1SThomas Huth {
281da668aa1SThomas Huth     const TestFixture *fixture = fix;
282bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
283bb6960a1SMarc-André Lureau     QDict *val;
284da668aa1SThomas Huth     const gchar *version;
285da668aa1SThomas Huth 
286da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
287da668aa1SThomas Huth     g_assert_nonnull(ret);
288da668aa1SThomas Huth     qmp_assert_no_error(ret);
289da668aa1SThomas Huth 
290da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
291da668aa1SThomas Huth     version = qdict_get_try_str(val, "version");
292da668aa1SThomas Huth     g_assert_cmpstr(version, ==, QEMU_VERSION);
293da668aa1SThomas Huth }
294da668aa1SThomas Huth 
test_qga_get_vcpus(gconstpointer fix)295da668aa1SThomas Huth static void test_qga_get_vcpus(gconstpointer fix)
296da668aa1SThomas Huth {
297da668aa1SThomas Huth     const TestFixture *fixture = fix;
298bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
299da668aa1SThomas Huth     QList *list;
300da668aa1SThomas Huth     const QListEntry *entry;
301da668aa1SThomas Huth 
302da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
303da668aa1SThomas Huth     g_assert_nonnull(ret);
304da668aa1SThomas Huth     qmp_assert_no_error(ret);
305da668aa1SThomas Huth 
306da668aa1SThomas Huth     /* check there is at least a cpu */
307da668aa1SThomas Huth     list = qdict_get_qlist(ret, "return");
308da668aa1SThomas Huth     entry = qlist_first(list);
309da668aa1SThomas Huth     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
310da668aa1SThomas Huth     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id"));
311da668aa1SThomas Huth }
312da668aa1SThomas Huth 
test_qga_get_fsinfo(gconstpointer fix)313da668aa1SThomas Huth static void test_qga_get_fsinfo(gconstpointer fix)
314da668aa1SThomas Huth {
315da668aa1SThomas Huth     const TestFixture *fixture = fix;
316bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
317da668aa1SThomas Huth     QList *list;
318da668aa1SThomas Huth     const QListEntry *entry;
319da668aa1SThomas Huth 
320da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
321da668aa1SThomas Huth     g_assert_nonnull(ret);
322da668aa1SThomas Huth     qmp_assert_no_error(ret);
323da668aa1SThomas Huth 
324da668aa1SThomas Huth     /* sanity-check the response if there are any filesystems */
325da668aa1SThomas Huth     list = qdict_get_qlist(ret, "return");
326da668aa1SThomas Huth     entry = qlist_first(list);
327da668aa1SThomas Huth     if (entry) {
328da668aa1SThomas Huth         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
329da668aa1SThomas Huth         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint"));
330da668aa1SThomas Huth         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type"));
331da668aa1SThomas Huth         g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk"));
332da668aa1SThomas Huth     }
333da668aa1SThomas Huth }
334da668aa1SThomas Huth 
test_qga_get_memory_block_info(gconstpointer fix)335da668aa1SThomas Huth static void test_qga_get_memory_block_info(gconstpointer fix)
336da668aa1SThomas Huth {
337da668aa1SThomas Huth     const TestFixture *fixture = fix;
338bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
339bb6960a1SMarc-André Lureau     QDict *val;
340da668aa1SThomas Huth     int64_t size;
341da668aa1SThomas Huth 
342da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
343da668aa1SThomas Huth     g_assert_nonnull(ret);
344da668aa1SThomas Huth 
345da668aa1SThomas Huth     /* some systems might not expose memory block info in sysfs */
346da668aa1SThomas Huth     if (!qdict_haskey(ret, "error")) {
347da668aa1SThomas Huth         /* check there is at least some memory */
348da668aa1SThomas Huth         val = qdict_get_qdict(ret, "return");
349da668aa1SThomas Huth         size = qdict_get_int(val, "size");
350da668aa1SThomas Huth         g_assert_cmpint(size, >, 0);
351da668aa1SThomas Huth     }
352da668aa1SThomas Huth }
353da668aa1SThomas Huth 
test_qga_get_memory_blocks(gconstpointer fix)354da668aa1SThomas Huth static void test_qga_get_memory_blocks(gconstpointer fix)
355da668aa1SThomas Huth {
356da668aa1SThomas Huth     const TestFixture *fixture = fix;
357bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
358da668aa1SThomas Huth     QList *list;
359da668aa1SThomas Huth     const QListEntry *entry;
360da668aa1SThomas Huth 
361da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
362da668aa1SThomas Huth     g_assert_nonnull(ret);
363da668aa1SThomas Huth 
364da668aa1SThomas Huth     /* some systems might not expose memory block info in sysfs */
365da668aa1SThomas Huth     if (!qdict_haskey(ret, "error")) {
366da668aa1SThomas Huth         list = qdict_get_qlist(ret, "return");
367da668aa1SThomas Huth         entry = qlist_first(list);
368da668aa1SThomas Huth         /* newer versions of qga may return empty list without error */
369da668aa1SThomas Huth         if (entry) {
370da668aa1SThomas Huth             g_assert(qdict_haskey(qobject_to(QDict, entry->value),
371da668aa1SThomas Huth                                   "phys-index"));
372da668aa1SThomas Huth             g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
373da668aa1SThomas Huth         }
374da668aa1SThomas Huth     }
375da668aa1SThomas Huth }
376da668aa1SThomas Huth 
test_qga_network_get_interfaces(gconstpointer fix)377da668aa1SThomas Huth static void test_qga_network_get_interfaces(gconstpointer fix)
378da668aa1SThomas Huth {
379da668aa1SThomas Huth     const TestFixture *fixture = fix;
380bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
381da668aa1SThomas Huth     QList *list;
382da668aa1SThomas Huth     const QListEntry *entry;
383da668aa1SThomas Huth 
384da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
385da668aa1SThomas Huth     g_assert_nonnull(ret);
386da668aa1SThomas Huth     qmp_assert_no_error(ret);
387da668aa1SThomas Huth 
388da668aa1SThomas Huth     /* check there is at least an interface */
389da668aa1SThomas Huth     list = qdict_get_qlist(ret, "return");
390da668aa1SThomas Huth     entry = qlist_first(list);
391da668aa1SThomas Huth     g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
392da668aa1SThomas Huth }
393da668aa1SThomas Huth 
test_qga_file_ops(gconstpointer fix)394da668aa1SThomas Huth static void test_qga_file_ops(gconstpointer fix)
395da668aa1SThomas Huth {
396da668aa1SThomas Huth     const TestFixture *fixture = fix;
397da668aa1SThomas Huth     const unsigned char helloworld[] = "Hello World!\n";
398da668aa1SThomas Huth     const char *b64;
399da668aa1SThomas Huth     gchar *path, *enc;
400da668aa1SThomas Huth     unsigned char *dec;
401da668aa1SThomas Huth     QDict *ret, *val;
402da668aa1SThomas Huth     int64_t id, eof;
403da668aa1SThomas Huth     gsize count;
404da668aa1SThomas Huth     FILE *f;
405da668aa1SThomas Huth     char tmp[100];
406da668aa1SThomas Huth 
407da668aa1SThomas Huth     /* open */
408da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
409da668aa1SThomas Huth                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
410da668aa1SThomas Huth     g_assert_nonnull(ret);
411da668aa1SThomas Huth     qmp_assert_no_error(ret);
412da668aa1SThomas Huth     id = qdict_get_int(ret, "return");
413da668aa1SThomas Huth     qobject_unref(ret);
414da668aa1SThomas Huth 
415da668aa1SThomas Huth     enc = g_base64_encode(helloworld, sizeof(helloworld));
416da668aa1SThomas Huth     /* write */
417da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
418da668aa1SThomas Huth                  "{'execute': 'guest-file-write',"
419da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 ", 'buf-b64': %s } }",
420da668aa1SThomas Huth                  id, enc);
421da668aa1SThomas Huth     g_assert_nonnull(ret);
422da668aa1SThomas Huth     qmp_assert_no_error(ret);
423da668aa1SThomas Huth 
424da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
425da668aa1SThomas Huth     count = qdict_get_int(val, "count");
426da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
427da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld));
428da668aa1SThomas Huth     g_assert_cmpint(eof, ==, 0);
429da668aa1SThomas Huth     qobject_unref(ret);
430da668aa1SThomas Huth 
431da668aa1SThomas Huth     /* flush */
432da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
433da668aa1SThomas Huth                  "{'execute': 'guest-file-flush',"
434da668aa1SThomas Huth                  " 'arguments': {'handle': %" PRId64 "} }",
435da668aa1SThomas Huth                  id);
436da668aa1SThomas Huth     qobject_unref(ret);
437da668aa1SThomas Huth 
438da668aa1SThomas Huth     /* close */
439da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
440da668aa1SThomas Huth                  "{'execute': 'guest-file-close',"
441da668aa1SThomas Huth                  " 'arguments': {'handle': %" PRId64 "} }",
442da668aa1SThomas Huth                  id);
443da668aa1SThomas Huth     qobject_unref(ret);
444da668aa1SThomas Huth 
445da668aa1SThomas Huth     /* check content */
446da668aa1SThomas Huth     path = g_build_filename(fixture->test_dir, "foo", NULL);
447da668aa1SThomas Huth     f = fopen(path, "r");
448da668aa1SThomas Huth     g_free(path);
449da668aa1SThomas Huth     g_assert_nonnull(f);
450da668aa1SThomas Huth     count = fread(tmp, 1, sizeof(tmp), f);
451da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld));
452da668aa1SThomas Huth     tmp[count] = 0;
453da668aa1SThomas Huth     g_assert_cmpstr(tmp, ==, (char *)helloworld);
454da668aa1SThomas Huth     fclose(f);
455da668aa1SThomas Huth 
456da668aa1SThomas Huth     /* open */
457da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
458da668aa1SThomas Huth                  " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
459da668aa1SThomas Huth     g_assert_nonnull(ret);
460da668aa1SThomas Huth     qmp_assert_no_error(ret);
461da668aa1SThomas Huth     id = qdict_get_int(ret, "return");
462da668aa1SThomas Huth     qobject_unref(ret);
463da668aa1SThomas Huth 
464da668aa1SThomas Huth     /* read */
465da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
466da668aa1SThomas Huth                  "{'execute': 'guest-file-read',"
467da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 "} }",
468da668aa1SThomas Huth                  id);
469da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
470da668aa1SThomas Huth     count = qdict_get_int(val, "count");
471da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
472da668aa1SThomas Huth     b64 = qdict_get_str(val, "buf-b64");
473da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld));
474da668aa1SThomas Huth     g_assert(eof);
475da668aa1SThomas Huth     g_assert_cmpstr(b64, ==, enc);
476da668aa1SThomas Huth 
477da668aa1SThomas Huth     qobject_unref(ret);
478da668aa1SThomas Huth     g_free(enc);
479da668aa1SThomas Huth 
480da668aa1SThomas Huth     /* read eof */
481da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
482da668aa1SThomas Huth                  "{'execute': 'guest-file-read',"
483da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 "} }",
484da668aa1SThomas Huth                  id);
485da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
486da668aa1SThomas Huth     count = qdict_get_int(val, "count");
487da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
488da668aa1SThomas Huth     b64 = qdict_get_str(val, "buf-b64");
489da668aa1SThomas Huth     g_assert_cmpint(count, ==, 0);
490da668aa1SThomas Huth     g_assert(eof);
491da668aa1SThomas Huth     g_assert_cmpstr(b64, ==, "");
492da668aa1SThomas Huth     qobject_unref(ret);
493da668aa1SThomas Huth 
494da668aa1SThomas Huth     /* seek */
495da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
496da668aa1SThomas Huth                  "{'execute': 'guest-file-seek',"
497da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 ", "
498da668aa1SThomas Huth                  " 'offset': %d, 'whence': %s } }",
499da668aa1SThomas Huth                  id, 6, "set");
500da668aa1SThomas Huth     qmp_assert_no_error(ret);
501da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
502da668aa1SThomas Huth     count = qdict_get_int(val, "position");
503da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
504da668aa1SThomas Huth     g_assert_cmpint(count, ==, 6);
505da668aa1SThomas Huth     g_assert(!eof);
506da668aa1SThomas Huth     qobject_unref(ret);
507da668aa1SThomas Huth 
508da668aa1SThomas Huth     /* partial read */
509da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
510da668aa1SThomas Huth                  "{'execute': 'guest-file-read',"
511da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 "} }",
512da668aa1SThomas Huth                  id);
513da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
514da668aa1SThomas Huth     count = qdict_get_int(val, "count");
515da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
516da668aa1SThomas Huth     b64 = qdict_get_str(val, "buf-b64");
517da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
518da668aa1SThomas Huth     g_assert(eof);
519da668aa1SThomas Huth     dec = g_base64_decode(b64, &count);
520da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld) - 6);
521da668aa1SThomas Huth     g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6);
522da668aa1SThomas Huth     g_free(dec);
523da668aa1SThomas Huth 
524da668aa1SThomas Huth     qobject_unref(ret);
525da668aa1SThomas Huth 
526da668aa1SThomas Huth     /* close */
527da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
528da668aa1SThomas Huth                  "{'execute': 'guest-file-close',"
529da668aa1SThomas Huth                  " 'arguments': {'handle': %" PRId64 "} }",
530da668aa1SThomas Huth                  id);
531da668aa1SThomas Huth     qobject_unref(ret);
532da668aa1SThomas Huth }
533da668aa1SThomas Huth 
test_qga_file_write_read(gconstpointer fix)534da668aa1SThomas Huth static void test_qga_file_write_read(gconstpointer fix)
535da668aa1SThomas Huth {
536da668aa1SThomas Huth     const TestFixture *fixture = fix;
537da668aa1SThomas Huth     const unsigned char helloworld[] = "Hello World!\n";
538da668aa1SThomas Huth     const char *b64;
539da668aa1SThomas Huth     gchar *enc;
540da668aa1SThomas Huth     QDict *ret, *val;
541da668aa1SThomas Huth     int64_t id, eof;
542da668aa1SThomas Huth     gsize count;
543da668aa1SThomas Huth 
544da668aa1SThomas Huth     /* open */
545da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
546da668aa1SThomas Huth                  " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
547da668aa1SThomas Huth     g_assert_nonnull(ret);
548da668aa1SThomas Huth     qmp_assert_no_error(ret);
549da668aa1SThomas Huth     id = qdict_get_int(ret, "return");
550da668aa1SThomas Huth     qobject_unref(ret);
551da668aa1SThomas Huth 
552da668aa1SThomas Huth     enc = g_base64_encode(helloworld, sizeof(helloworld));
553da668aa1SThomas Huth     /* write */
554da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
555da668aa1SThomas Huth                  "{'execute': 'guest-file-write',"
556da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 ","
557da668aa1SThomas Huth                  " 'buf-b64': %s } }", id, enc);
558da668aa1SThomas Huth     g_assert_nonnull(ret);
559da668aa1SThomas Huth     qmp_assert_no_error(ret);
560da668aa1SThomas Huth 
561da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
562da668aa1SThomas Huth     count = qdict_get_int(val, "count");
563da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
564da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld));
565da668aa1SThomas Huth     g_assert_cmpint(eof, ==, 0);
566da668aa1SThomas Huth     qobject_unref(ret);
567da668aa1SThomas Huth 
568da668aa1SThomas Huth     /* read (check implicit flush) */
569da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
570da668aa1SThomas Huth                  "{'execute': 'guest-file-read',"
571da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 "} }",
572da668aa1SThomas Huth                  id);
573da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
574da668aa1SThomas Huth     count = qdict_get_int(val, "count");
575da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
576da668aa1SThomas Huth     b64 = qdict_get_str(val, "buf-b64");
577da668aa1SThomas Huth     g_assert_cmpint(count, ==, 0);
578da668aa1SThomas Huth     g_assert(eof);
579da668aa1SThomas Huth     g_assert_cmpstr(b64, ==, "");
580da668aa1SThomas Huth     qobject_unref(ret);
581da668aa1SThomas Huth 
582da668aa1SThomas Huth     /* seek to 0 */
583da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
584da668aa1SThomas Huth                  "{'execute': 'guest-file-seek',"
585da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 ", "
586da668aa1SThomas Huth                  " 'offset': %d, 'whence': %s } }",
587da668aa1SThomas Huth                  id, 0, "set");
588da668aa1SThomas Huth     qmp_assert_no_error(ret);
589da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
590da668aa1SThomas Huth     count = qdict_get_int(val, "position");
591da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
592da668aa1SThomas Huth     g_assert_cmpint(count, ==, 0);
593da668aa1SThomas Huth     g_assert(!eof);
594da668aa1SThomas Huth     qobject_unref(ret);
595da668aa1SThomas Huth 
596da668aa1SThomas Huth     /* read */
597da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
598da668aa1SThomas Huth                  "{'execute': 'guest-file-read',"
599da668aa1SThomas Huth                  " 'arguments': { 'handle': %" PRId64 "} }",
600da668aa1SThomas Huth                  id);
601da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
602da668aa1SThomas Huth     count = qdict_get_int(val, "count");
603da668aa1SThomas Huth     eof = qdict_get_bool(val, "eof");
604da668aa1SThomas Huth     b64 = qdict_get_str(val, "buf-b64");
605da668aa1SThomas Huth     g_assert_cmpint(count, ==, sizeof(helloworld));
606da668aa1SThomas Huth     g_assert(eof);
607da668aa1SThomas Huth     g_assert_cmpstr(b64, ==, enc);
608da668aa1SThomas Huth     qobject_unref(ret);
609da668aa1SThomas Huth     g_free(enc);
610da668aa1SThomas Huth 
611da668aa1SThomas Huth     /* close */
612da668aa1SThomas Huth     ret = qmp_fd(fixture->fd,
613da668aa1SThomas Huth                  "{'execute': 'guest-file-close',"
614da668aa1SThomas Huth                  " 'arguments': {'handle': %" PRId64 "} }",
615da668aa1SThomas Huth                  id);
616da668aa1SThomas Huth     qobject_unref(ret);
617da668aa1SThomas Huth }
618da668aa1SThomas Huth 
test_qga_get_time(gconstpointer fix)619da668aa1SThomas Huth static void test_qga_get_time(gconstpointer fix)
620da668aa1SThomas Huth {
621da668aa1SThomas Huth     const TestFixture *fixture = fix;
622bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
623da668aa1SThomas Huth     int64_t time;
624da668aa1SThomas Huth 
625da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
626da668aa1SThomas Huth     g_assert_nonnull(ret);
627da668aa1SThomas Huth     qmp_assert_no_error(ret);
628da668aa1SThomas Huth 
629da668aa1SThomas Huth     time = qdict_get_int(ret, "return");
630da668aa1SThomas Huth     g_assert_cmpint(time, >, 0);
631da668aa1SThomas Huth }
632da668aa1SThomas Huth 
test_qga_blockedrpcs(gconstpointer data)633ebf70554SThomas Huth static void test_qga_blockedrpcs(gconstpointer data)
634da668aa1SThomas Huth {
635da668aa1SThomas Huth     TestFixture fix;
636da668aa1SThomas Huth     QDict *ret, *error;
637da668aa1SThomas Huth     const gchar *class, *desc;
638da668aa1SThomas Huth 
639da668aa1SThomas Huth     fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL);
640da668aa1SThomas Huth 
641ebf70554SThomas Huth     /* check blocked RPCs */
642da668aa1SThomas Huth     ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
643da668aa1SThomas Huth     g_assert_nonnull(ret);
644da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
645da668aa1SThomas Huth     class = qdict_get_try_str(error, "class");
646da668aa1SThomas Huth     desc = qdict_get_try_str(error, "desc");
647da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "CommandNotFound");
648da668aa1SThomas Huth     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
649da668aa1SThomas Huth     qobject_unref(ret);
650da668aa1SThomas Huth 
651da668aa1SThomas Huth     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
652da668aa1SThomas Huth     g_assert_nonnull(ret);
653da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
654da668aa1SThomas Huth     class = qdict_get_try_str(error, "class");
655da668aa1SThomas Huth     desc = qdict_get_try_str(error, "desc");
656da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "CommandNotFound");
657da668aa1SThomas Huth     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
658da668aa1SThomas Huth     qobject_unref(ret);
659da668aa1SThomas Huth 
660da668aa1SThomas Huth     /* check something work */
661da668aa1SThomas Huth     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
662da668aa1SThomas Huth     qmp_assert_no_error(ret);
663da668aa1SThomas Huth     qobject_unref(ret);
664da668aa1SThomas Huth 
665da668aa1SThomas Huth     fixture_tear_down(&fix, NULL);
666da668aa1SThomas Huth }
667da668aa1SThomas Huth 
test_qga_allowedrpcs(gconstpointer data)668fcd1ab3aSKonstantin Kostiuk static void test_qga_allowedrpcs(gconstpointer data)
669fcd1ab3aSKonstantin Kostiuk {
670fcd1ab3aSKonstantin Kostiuk     TestFixture fix;
671fcd1ab3aSKonstantin Kostiuk     QDict *ret, *error;
672fcd1ab3aSKonstantin Kostiuk     const gchar *class, *desc;
673fcd1ab3aSKonstantin Kostiuk 
674fcd1ab3aSKonstantin Kostiuk     fixture_setup(&fix, "-a guest-ping,guest-get-time", NULL);
675fcd1ab3aSKonstantin Kostiuk 
676fcd1ab3aSKonstantin Kostiuk     /* check allowed RPCs */
677fcd1ab3aSKonstantin Kostiuk     ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
678fcd1ab3aSKonstantin Kostiuk     qmp_assert_no_error(ret);
679fcd1ab3aSKonstantin Kostiuk     qobject_unref(ret);
680fcd1ab3aSKonstantin Kostiuk 
681fcd1ab3aSKonstantin Kostiuk     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
682fcd1ab3aSKonstantin Kostiuk     qmp_assert_no_error(ret);
683fcd1ab3aSKonstantin Kostiuk     qobject_unref(ret);
684fcd1ab3aSKonstantin Kostiuk 
685fcd1ab3aSKonstantin Kostiuk     /* check something else */
686fcd1ab3aSKonstantin Kostiuk     ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
687fcd1ab3aSKonstantin Kostiuk     g_assert_nonnull(ret);
688fcd1ab3aSKonstantin Kostiuk     error = qdict_get_qdict(ret, "error");
689fcd1ab3aSKonstantin Kostiuk     class = qdict_get_try_str(error, "class");
690fcd1ab3aSKonstantin Kostiuk     desc = qdict_get_try_str(error, "desc");
691fcd1ab3aSKonstantin Kostiuk     g_assert_cmpstr(class, ==, "CommandNotFound");
692fcd1ab3aSKonstantin Kostiuk     g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
693fcd1ab3aSKonstantin Kostiuk     qobject_unref(ret);
694fcd1ab3aSKonstantin Kostiuk 
695fcd1ab3aSKonstantin Kostiuk     fixture_tear_down(&fix, NULL);
696fcd1ab3aSKonstantin Kostiuk }
697fcd1ab3aSKonstantin Kostiuk 
test_qga_config(gconstpointer data)698da668aa1SThomas Huth static void test_qga_config(gconstpointer data)
699da668aa1SThomas Huth {
700da668aa1SThomas Huth     GError *error = NULL;
701bb6960a1SMarc-André Lureau     g_autofree char *out = NULL;
702bb6960a1SMarc-André Lureau     g_autofree char *err = NULL;
703bb6960a1SMarc-André Lureau     g_autofree char *cwd = NULL;
704bb6960a1SMarc-André Lureau     g_autofree char *cmd = NULL;
705bb6960a1SMarc-André Lureau     g_auto(GStrv) argv = NULL;
706bb6960a1SMarc-André Lureau     g_auto(GStrv) strv = NULL;
707bb6960a1SMarc-André Lureau     g_autoptr(GKeyFile) kf = NULL;
708bb6960a1SMarc-André Lureau     char *str;
709da668aa1SThomas Huth     char *env[2];
710da668aa1SThomas Huth     int status;
711da668aa1SThomas Huth     gsize n;
712da668aa1SThomas Huth 
713da668aa1SThomas Huth     cwd = g_get_current_dir();
714da668aa1SThomas Huth     cmd = g_strdup_printf("%s%cqga%cqemu-ga -D",
715da668aa1SThomas Huth                           cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
716da668aa1SThomas Huth     g_shell_parse_argv(cmd, NULL, &argv, &error);
717da668aa1SThomas Huth     g_assert_no_error(error);
718da668aa1SThomas Huth 
719da668aa1SThomas Huth     env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
720da668aa1SThomas Huth                              G_DIR_SEPARATOR, G_DIR_SEPARATOR);
721da668aa1SThomas Huth     env[1] = NULL;
722da668aa1SThomas Huth     g_spawn_sync(NULL, argv, env, 0,
723da668aa1SThomas Huth                  NULL, NULL, &out, &err, &status, &error);
724da668aa1SThomas Huth 
725da668aa1SThomas Huth     g_assert_no_error(error);
726da668aa1SThomas Huth     g_assert_cmpstr(err, ==, "");
727da668aa1SThomas Huth     g_assert_cmpint(status, ==, 0);
728da668aa1SThomas Huth 
729da668aa1SThomas Huth     kf = g_key_file_new();
730da668aa1SThomas Huth     g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
731da668aa1SThomas Huth     g_assert_no_error(error);
732da668aa1SThomas Huth 
733da668aa1SThomas Huth     str = g_key_file_get_start_group(kf);
734da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "general");
735da668aa1SThomas Huth     g_free(str);
736da668aa1SThomas Huth 
737da668aa1SThomas Huth     g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error));
738da668aa1SThomas Huth     g_assert_no_error(error);
739da668aa1SThomas Huth 
740da668aa1SThomas Huth     str = g_key_file_get_string(kf, "general", "method", &error);
741da668aa1SThomas Huth     g_assert_no_error(error);
742da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "virtio-serial");
743da668aa1SThomas Huth     g_free(str);
744da668aa1SThomas Huth 
745da668aa1SThomas Huth     str = g_key_file_get_string(kf, "general", "path", &error);
746da668aa1SThomas Huth     g_assert_no_error(error);
747da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
748da668aa1SThomas Huth     g_free(str);
749da668aa1SThomas Huth 
750da668aa1SThomas Huth     str = g_key_file_get_string(kf, "general", "pidfile", &error);
751da668aa1SThomas Huth     g_assert_no_error(error);
752da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
753da668aa1SThomas Huth     g_free(str);
754da668aa1SThomas Huth 
755da668aa1SThomas Huth     str = g_key_file_get_string(kf, "general", "statedir", &error);
756da668aa1SThomas Huth     g_assert_no_error(error);
757da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "/var/state");
758da668aa1SThomas Huth     g_free(str);
759da668aa1SThomas Huth 
760da668aa1SThomas Huth     g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error));
761da668aa1SThomas Huth     g_assert_no_error(error);
762da668aa1SThomas Huth 
763582a098eSThomas Huth     strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error);
764da668aa1SThomas Huth     g_assert_cmpint(n, ==, 2);
765da668aa1SThomas Huth     g_assert_true(g_strv_contains((const char * const *)strv,
766da668aa1SThomas Huth                                   "guest-ping"));
767da668aa1SThomas Huth     g_assert_true(g_strv_contains((const char * const *)strv,
768da668aa1SThomas Huth                                   "guest-get-time"));
769da668aa1SThomas Huth     g_assert_no_error(error);
770da668aa1SThomas Huth 
771da668aa1SThomas Huth     g_free(env[0]);
772da668aa1SThomas Huth }
773da668aa1SThomas Huth 
test_qga_fsfreeze_status(gconstpointer fix)774da668aa1SThomas Huth static void test_qga_fsfreeze_status(gconstpointer fix)
775da668aa1SThomas Huth {
776da668aa1SThomas Huth     const TestFixture *fixture = fix;
777bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
778da668aa1SThomas Huth     const gchar *status;
779da668aa1SThomas Huth 
780da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
781da668aa1SThomas Huth     g_assert_nonnull(ret);
782da668aa1SThomas Huth     qmp_assert_no_error(ret);
783da668aa1SThomas Huth 
784da668aa1SThomas Huth     status = qdict_get_try_str(ret, "return");
785da668aa1SThomas Huth     g_assert_cmpstr(status, ==, "thawed");
786da668aa1SThomas Huth }
787da668aa1SThomas Huth 
wait_for_guest_exec_completion(int fd,int64_t pid)788c7d74f27SDaniel Xu static QDict *wait_for_guest_exec_completion(int fd, int64_t pid)
789da668aa1SThomas Huth {
790c7d74f27SDaniel Xu     QDict *ret = NULL;
791c7d74f27SDaniel Xu     int64_t now;
792da668aa1SThomas Huth     bool exited;
793c7d74f27SDaniel Xu     QDict *val;
794da668aa1SThomas Huth 
795da668aa1SThomas Huth     now = g_get_monotonic_time();
796da668aa1SThomas Huth     do {
797c7d74f27SDaniel Xu         ret = qmp_fd(fd,
798da668aa1SThomas Huth                      "{'execute': 'guest-exec-status',"
799da668aa1SThomas Huth                      " 'arguments': { 'pid': %" PRId64 " } }", pid);
800da668aa1SThomas Huth         g_assert_nonnull(ret);
801da668aa1SThomas Huth         val = qdict_get_qdict(ret, "return");
802da668aa1SThomas Huth         exited = qdict_get_bool(val, "exited");
803da668aa1SThomas Huth         if (!exited) {
804da668aa1SThomas Huth             qobject_unref(ret);
805da668aa1SThomas Huth         }
806da668aa1SThomas Huth     } while (!exited &&
807da668aa1SThomas Huth              g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
808da668aa1SThomas Huth     g_assert(exited);
809da668aa1SThomas Huth 
810c7d74f27SDaniel Xu     return ret;
811c7d74f27SDaniel Xu }
812c7d74f27SDaniel Xu 
test_qga_guest_exec(gconstpointer fix)813c7d74f27SDaniel Xu static void test_qga_guest_exec(gconstpointer fix)
814c7d74f27SDaniel Xu {
815c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
816c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
817c7d74f27SDaniel Xu     QDict *val;
818c7d74f27SDaniel Xu     const gchar *out;
819c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
820c7d74f27SDaniel Xu     int64_t pid, exitcode;
821c7d74f27SDaniel Xu     gsize len;
822c7d74f27SDaniel Xu 
823c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
824c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
825*8c72e19bSSamuel Tardieu                  " 'path': 'echo', 'arg': [ '-n', '\" test_str \"' ],"
826c7d74f27SDaniel Xu                  " 'capture-output': true } }");
827c7d74f27SDaniel Xu     g_assert_nonnull(ret);
828c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
829c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
830c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
831c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
832c7d74f27SDaniel Xu     qobject_unref(ret);
833c7d74f27SDaniel Xu 
834c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
835c7d74f27SDaniel Xu 
836da668aa1SThomas Huth     /* check stdout */
837c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
838da668aa1SThomas Huth     exitcode = qdict_get_int(val, "exitcode");
839da668aa1SThomas Huth     g_assert_cmpint(exitcode, ==, 0);
840da668aa1SThomas Huth     out = qdict_get_str(val, "out-data");
841da668aa1SThomas Huth     decoded = g_base64_decode(out, &len);
842da668aa1SThomas Huth     g_assert_cmpint(len, ==, 12);
843da668aa1SThomas Huth     g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
844da668aa1SThomas Huth }
845da668aa1SThomas Huth 
846c7d74f27SDaniel Xu #if defined(G_OS_WIN32)
test_qga_guest_exec_separated(gconstpointer fix)847c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix)
848c7d74f27SDaniel Xu {
849c7d74f27SDaniel Xu }
test_qga_guest_exec_merged(gconstpointer fix)850c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix)
851c7d74f27SDaniel Xu {
852c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
853c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
854c7d74f27SDaniel Xu     QDict *val;
855c7d74f27SDaniel Xu     const gchar *class, *desc;
856c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
857c7d74f27SDaniel Xu 
858c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
859c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
860c7d74f27SDaniel Xu                  " 'path': 'echo',"
861c7d74f27SDaniel Xu                  " 'arg': [ 'execution never reaches here' ],"
862c7d74f27SDaniel Xu                  " 'capture-output': 'merged' } }");
863c7d74f27SDaniel Xu 
864c7d74f27SDaniel Xu     g_assert_nonnull(ret);
865c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "error");
866c7d74f27SDaniel Xu     g_assert_nonnull(val);
867c7d74f27SDaniel Xu     class = qdict_get_str(val, "class");
868c7d74f27SDaniel Xu     desc = qdict_get_str(val, "desc");
869c7d74f27SDaniel Xu     g_assert_cmpstr(class, ==, "GenericError");
870c7d74f27SDaniel Xu     g_assert_cmpint(strlen(desc), >, 0);
871c7d74f27SDaniel Xu }
872c7d74f27SDaniel Xu #else
test_qga_guest_exec_separated(gconstpointer fix)873c7d74f27SDaniel Xu static void test_qga_guest_exec_separated(gconstpointer fix)
874c7d74f27SDaniel Xu {
875c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
876c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
877c7d74f27SDaniel Xu     QDict *val;
878c7d74f27SDaniel Xu     const gchar *out, *err;
879c7d74f27SDaniel Xu     g_autofree guchar *out_decoded = NULL;
880c7d74f27SDaniel Xu     g_autofree guchar *err_decoded = NULL;
881c7d74f27SDaniel Xu     int64_t pid, exitcode;
882c7d74f27SDaniel Xu     gsize len;
883c7d74f27SDaniel Xu 
884c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
885c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
886*8c72e19bSSamuel Tardieu                  " 'path': 'bash',"
887c7d74f27SDaniel Xu                  " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
888c7d74f27SDaniel Xu                  " 'capture-output': 'separated' } }");
889c7d74f27SDaniel Xu     g_assert_nonnull(ret);
890c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
891c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
892c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
893c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
894c7d74f27SDaniel Xu     qobject_unref(ret);
895c7d74f27SDaniel Xu 
896c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
897c7d74f27SDaniel Xu 
898c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
899c7d74f27SDaniel Xu     exitcode = qdict_get_int(val, "exitcode");
900c7d74f27SDaniel Xu     g_assert_cmpint(exitcode, ==, 0);
901c7d74f27SDaniel Xu 
902c7d74f27SDaniel Xu     /* check stdout */
903c7d74f27SDaniel Xu     out = qdict_get_str(val, "out-data");
904c7d74f27SDaniel Xu     out_decoded = g_base64_decode(out, &len);
905c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 14);
906c7d74f27SDaniel Xu     g_assert_cmpstr((char *)out_decoded, ==, "stdout\nstdout\n");
907c7d74f27SDaniel Xu 
908c7d74f27SDaniel Xu     /* check stderr */
909c7d74f27SDaniel Xu     err = qdict_get_try_str(val, "err-data");
910c7d74f27SDaniel Xu     err_decoded = g_base64_decode(err, &len);
911c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 14);
912c7d74f27SDaniel Xu     g_assert_cmpstr((char *)err_decoded, ==, "stderr\nstderr\n");
913c7d74f27SDaniel Xu }
914c7d74f27SDaniel Xu 
test_qga_guest_exec_merged(gconstpointer fix)915c7d74f27SDaniel Xu static void test_qga_guest_exec_merged(gconstpointer fix)
916c7d74f27SDaniel Xu {
917c7d74f27SDaniel Xu     const TestFixture *fixture = fix;
918c7d74f27SDaniel Xu     g_autoptr(QDict) ret = NULL;
919c7d74f27SDaniel Xu     QDict *val;
920c7d74f27SDaniel Xu     const gchar *out, *err;
921c7d74f27SDaniel Xu     g_autofree guchar *decoded = NULL;
922c7d74f27SDaniel Xu     int64_t pid, exitcode;
923c7d74f27SDaniel Xu     gsize len;
924c7d74f27SDaniel Xu 
925c7d74f27SDaniel Xu     /* exec 'echo foo bar' */
926c7d74f27SDaniel Xu     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
927*8c72e19bSSamuel Tardieu                  " 'path': 'bash',"
928c7d74f27SDaniel Xu                  " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
929c7d74f27SDaniel Xu                  " 'capture-output': 'merged' } }");
930c7d74f27SDaniel Xu     g_assert_nonnull(ret);
931c7d74f27SDaniel Xu     qmp_assert_no_error(ret);
932c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
933c7d74f27SDaniel Xu     pid = qdict_get_int(val, "pid");
934c7d74f27SDaniel Xu     g_assert_cmpint(pid, >, 0);
935c7d74f27SDaniel Xu     qobject_unref(ret);
936c7d74f27SDaniel Xu 
937c7d74f27SDaniel Xu     ret = wait_for_guest_exec_completion(fixture->fd, pid);
938c7d74f27SDaniel Xu 
939c7d74f27SDaniel Xu     val = qdict_get_qdict(ret, "return");
940c7d74f27SDaniel Xu     exitcode = qdict_get_int(val, "exitcode");
941c7d74f27SDaniel Xu     g_assert_cmpint(exitcode, ==, 0);
942c7d74f27SDaniel Xu 
943c7d74f27SDaniel Xu     /* check stdout */
944c7d74f27SDaniel Xu     out = qdict_get_str(val, "out-data");
945c7d74f27SDaniel Xu     decoded = g_base64_decode(out, &len);
946c7d74f27SDaniel Xu     g_assert_cmpint(len, ==, 28);
947c7d74f27SDaniel Xu     g_assert_cmpstr((char *)decoded, ==, "stdout\nstderr\nstdout\nstderr\n");
948c7d74f27SDaniel Xu 
949c7d74f27SDaniel Xu     /* check stderr */
950c7d74f27SDaniel Xu     err = qdict_get_try_str(val, "err-data");
951c7d74f27SDaniel Xu     g_assert_null(err);
952c7d74f27SDaniel Xu }
953c7d74f27SDaniel Xu #endif
954c7d74f27SDaniel Xu 
test_qga_guest_exec_invalid(gconstpointer fix)955da668aa1SThomas Huth static void test_qga_guest_exec_invalid(gconstpointer fix)
956da668aa1SThomas Huth {
957da668aa1SThomas Huth     const TestFixture *fixture = fix;
958bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
959bb6960a1SMarc-André Lureau     QDict *error;
960da668aa1SThomas Huth     const gchar *class, *desc;
961da668aa1SThomas Huth 
962da668aa1SThomas Huth     /* invalid command */
963da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
964da668aa1SThomas Huth                  " 'path': '/bin/invalid-cmd42' } }");
965da668aa1SThomas Huth     g_assert_nonnull(ret);
966da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
967da668aa1SThomas Huth     g_assert_nonnull(error);
968da668aa1SThomas Huth     class = qdict_get_str(error, "class");
969da668aa1SThomas Huth     desc = qdict_get_str(error, "desc");
970da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "GenericError");
971da668aa1SThomas Huth     g_assert_cmpint(strlen(desc), >, 0);
972da668aa1SThomas Huth     qobject_unref(ret);
973da668aa1SThomas Huth 
974da668aa1SThomas Huth     /* invalid pid */
975da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status',"
976da668aa1SThomas Huth                  " 'arguments': { 'pid': 0 } }");
977da668aa1SThomas Huth     g_assert_nonnull(ret);
978da668aa1SThomas Huth     error = qdict_get_qdict(ret, "error");
979da668aa1SThomas Huth     g_assert_nonnull(error);
980da668aa1SThomas Huth     class = qdict_get_str(error, "class");
981da668aa1SThomas Huth     desc = qdict_get_str(error, "desc");
982da668aa1SThomas Huth     g_assert_cmpstr(class, ==, "GenericError");
983da668aa1SThomas Huth     g_assert_cmpint(strlen(desc), >, 0);
984da668aa1SThomas Huth }
985da668aa1SThomas Huth 
test_qga_guest_get_host_name(gconstpointer fix)986da668aa1SThomas Huth static void test_qga_guest_get_host_name(gconstpointer fix)
987da668aa1SThomas Huth {
988da668aa1SThomas Huth     const TestFixture *fixture = fix;
989bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
990bb6960a1SMarc-André Lureau     QDict *val;
991da668aa1SThomas Huth 
992da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
993da668aa1SThomas Huth     g_assert_nonnull(ret);
994da668aa1SThomas Huth     qmp_assert_no_error(ret);
995da668aa1SThomas Huth 
996da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
997da668aa1SThomas Huth     g_assert(qdict_haskey(val, "host-name"));
998da668aa1SThomas Huth }
999da668aa1SThomas Huth 
test_qga_guest_get_timezone(gconstpointer fix)1000da668aa1SThomas Huth static void test_qga_guest_get_timezone(gconstpointer fix)
1001da668aa1SThomas Huth {
1002da668aa1SThomas Huth     const TestFixture *fixture = fix;
1003bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
1004bb6960a1SMarc-André Lureau     QDict *val;
1005da668aa1SThomas Huth 
1006da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
1007da668aa1SThomas Huth     g_assert_nonnull(ret);
1008da668aa1SThomas Huth     qmp_assert_no_error(ret);
1009da668aa1SThomas Huth 
1010da668aa1SThomas Huth     /* Make sure there's at least offset */
1011da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
1012da668aa1SThomas Huth     g_assert(qdict_haskey(val, "offset"));
1013da668aa1SThomas Huth }
1014da668aa1SThomas Huth 
test_qga_guest_get_users(gconstpointer fix)1015da668aa1SThomas Huth static void test_qga_guest_get_users(gconstpointer fix)
1016da668aa1SThomas Huth {
1017da668aa1SThomas Huth     const TestFixture *fixture = fix;
1018bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
1019da668aa1SThomas Huth     QList *val;
1020da668aa1SThomas Huth 
1021da668aa1SThomas Huth     ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
1022da668aa1SThomas Huth     g_assert_nonnull(ret);
1023da668aa1SThomas Huth     qmp_assert_no_error(ret);
1024da668aa1SThomas Huth 
1025da668aa1SThomas Huth     /* There is not much to test here */
1026da668aa1SThomas Huth     val = qdict_get_qlist(ret, "return");
1027da668aa1SThomas Huth     g_assert_nonnull(val);
1028da668aa1SThomas Huth }
1029da668aa1SThomas Huth 
test_qga_guest_get_osinfo(gconstpointer data)1030da668aa1SThomas Huth static void test_qga_guest_get_osinfo(gconstpointer data)
1031da668aa1SThomas Huth {
1032da668aa1SThomas Huth     TestFixture fixture;
1033da668aa1SThomas Huth     const gchar *str;
1034bb6960a1SMarc-André Lureau     g_autoptr(QDict) ret = NULL;
1035a85d0926SMarc-André Lureau     char *env[2];
1036a85d0926SMarc-André Lureau     QDict *val;
1037da668aa1SThomas Huth 
1038da668aa1SThomas Huth     env[0] = g_strdup_printf(
1039a85d0926SMarc-André Lureau         "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release",
1040a85d0926SMarc-André Lureau         g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
1041da668aa1SThomas Huth     env[1] = NULL;
1042da668aa1SThomas Huth     fixture_setup(&fixture, NULL, env);
1043da668aa1SThomas Huth 
1044da668aa1SThomas Huth     ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
1045da668aa1SThomas Huth     g_assert_nonnull(ret);
1046da668aa1SThomas Huth     qmp_assert_no_error(ret);
1047da668aa1SThomas Huth 
1048da668aa1SThomas Huth     val = qdict_get_qdict(ret, "return");
1049da668aa1SThomas Huth 
1050da668aa1SThomas Huth     str = qdict_get_try_str(val, "id");
1051da668aa1SThomas Huth     g_assert_nonnull(str);
1052da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "qemu-ga-test");
1053da668aa1SThomas Huth 
1054da668aa1SThomas Huth     str = qdict_get_try_str(val, "name");
1055da668aa1SThomas Huth     g_assert_nonnull(str);
1056da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "QEMU-GA");
1057da668aa1SThomas Huth 
1058da668aa1SThomas Huth     str = qdict_get_try_str(val, "pretty-name");
1059da668aa1SThomas Huth     g_assert_nonnull(str);
1060da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "QEMU Guest Agent test");
1061da668aa1SThomas Huth 
1062da668aa1SThomas Huth     str = qdict_get_try_str(val, "version");
1063da668aa1SThomas Huth     g_assert_nonnull(str);
1064da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "Test 1");
1065da668aa1SThomas Huth 
1066da668aa1SThomas Huth     str = qdict_get_try_str(val, "version-id");
1067da668aa1SThomas Huth     g_assert_nonnull(str);
1068da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "1");
1069da668aa1SThomas Huth 
1070da668aa1SThomas Huth     str = qdict_get_try_str(val, "variant");
1071da668aa1SThomas Huth     g_assert_nonnull(str);
1072da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "Unit test \"'$`\\ and \\\\ etc.");
1073da668aa1SThomas Huth 
1074da668aa1SThomas Huth     str = qdict_get_try_str(val, "variant-id");
1075da668aa1SThomas Huth     g_assert_nonnull(str);
1076da668aa1SThomas Huth     g_assert_cmpstr(str, ==, "unit-test");
1077da668aa1SThomas Huth 
1078da668aa1SThomas Huth     g_free(env[0]);
1079da668aa1SThomas Huth     fixture_tear_down(&fixture, NULL);
1080da668aa1SThomas Huth }
1081da668aa1SThomas Huth 
main(int argc,char ** argv)1082da668aa1SThomas Huth int main(int argc, char **argv)
1083da668aa1SThomas Huth {
1084da668aa1SThomas Huth     TestFixture fix;
1085da668aa1SThomas Huth     int ret;
1086da668aa1SThomas Huth 
1087a7bd942cSMarc-André Lureau #ifdef QEMU_SANITIZE_THREAD
1088a7bd942cSMarc-André Lureau     {
1089a7bd942cSMarc-André Lureau         g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116");
1090a7bd942cSMarc-André Lureau         return 0;
1091a7bd942cSMarc-André Lureau     }
1092a7bd942cSMarc-André Lureau #endif
1093a7bd942cSMarc-André Lureau 
1094da668aa1SThomas Huth     setlocale (LC_ALL, "");
1095da668aa1SThomas Huth     g_test_init(&argc, &argv, NULL);
1096da668aa1SThomas Huth     fixture_setup(&fix, NULL, NULL);
1097da668aa1SThomas Huth 
1098da668aa1SThomas Huth     g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
1099da668aa1SThomas Huth     g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
1100da668aa1SThomas Huth     g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
1101da668aa1SThomas Huth     g_test_add_data_func("/qga/info", &fix, test_qga_info);
1102da668aa1SThomas Huth     g_test_add_data_func("/qga/network-get-interfaces", &fix,
1103da668aa1SThomas Huth                          test_qga_network_get_interfaces);
1104da668aa1SThomas Huth     if (!access("/sys/devices/system/cpu/cpu0", F_OK)) {
1105da668aa1SThomas Huth         g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
1106da668aa1SThomas Huth     }
1107da668aa1SThomas Huth     g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
1108da668aa1SThomas Huth     g_test_add_data_func("/qga/get-memory-block-info", &fix,
1109da668aa1SThomas Huth                          test_qga_get_memory_block_info);
1110da668aa1SThomas Huth     g_test_add_data_func("/qga/get-memory-blocks", &fix,
1111da668aa1SThomas Huth                          test_qga_get_memory_blocks);
1112da668aa1SThomas Huth     g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
1113da668aa1SThomas Huth     g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
1114da668aa1SThomas Huth     g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
1115da668aa1SThomas Huth     g_test_add_data_func("/qga/id", &fix, test_qga_id);
1116da668aa1SThomas Huth     g_test_add_data_func("/qga/invalid-oob", &fix, test_qga_invalid_oob);
1117da668aa1SThomas Huth     g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
1118da668aa1SThomas Huth     g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args);
1119da668aa1SThomas Huth     g_test_add_data_func("/qga/fsfreeze-status", &fix,
1120da668aa1SThomas Huth                          test_qga_fsfreeze_status);
1121da668aa1SThomas Huth 
1122ebf70554SThomas Huth     g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs);
1123fcd1ab3aSKonstantin Kostiuk     g_test_add_data_func("/qga/allowedrpcs", NULL, test_qga_allowedrpcs);
1124da668aa1SThomas Huth     g_test_add_data_func("/qga/config", NULL, test_qga_config);
1125da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
1126c7d74f27SDaniel Xu     g_test_add_data_func("/qga/guest-exec-separated", &fix,
1127c7d74f27SDaniel Xu                          test_qga_guest_exec_separated);
1128c7d74f27SDaniel Xu     g_test_add_data_func("/qga/guest-exec-merged", &fix,
1129c7d74f27SDaniel Xu                          test_qga_guest_exec_merged);
1130da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-exec-invalid", &fix,
1131da668aa1SThomas Huth                          test_qga_guest_exec_invalid);
1132da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-get-osinfo", &fix,
1133da668aa1SThomas Huth                          test_qga_guest_get_osinfo);
1134da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-get-host-name", &fix,
1135da668aa1SThomas Huth                          test_qga_guest_get_host_name);
1136da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-get-timezone", &fix,
1137da668aa1SThomas Huth                          test_qga_guest_get_timezone);
1138da668aa1SThomas Huth     g_test_add_data_func("/qga/guest-get-users", &fix,
1139da668aa1SThomas Huth                          test_qga_guest_get_users);
1140da668aa1SThomas Huth 
1141da668aa1SThomas Huth     ret = g_test_run();
1142da668aa1SThomas Huth 
1143da668aa1SThomas Huth     fixture_tear_down(&fix, NULL);
1144da668aa1SThomas Huth 
1145da668aa1SThomas Huth     return ret;
1146da668aa1SThomas Huth }
1147