xref: /qemu/tests/unit/test-yank.c (revision 935a867c)
1d3a0bb77SLukas Straub /*
2d3a0bb77SLukas Straub  * Tests for QEMU yank feature
3d3a0bb77SLukas Straub  *
4d3a0bb77SLukas Straub  * Copyright (c) Lukas Straub <lukasstraub2@web.de>
5d3a0bb77SLukas Straub  *
6d3a0bb77SLukas Straub  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7d3a0bb77SLukas Straub  * See the COPYING file in the top-level directory.
8d3a0bb77SLukas Straub  */
9d3a0bb77SLukas Straub 
10d3a0bb77SLukas Straub #include "qemu/osdep.h"
11d3a0bb77SLukas Straub #include <glib/gstdio.h>
12d3a0bb77SLukas Straub 
13d3a0bb77SLukas Straub #include "qemu/config-file.h"
14d3a0bb77SLukas Straub #include "qemu/module.h"
15d3a0bb77SLukas Straub #include "qemu/option.h"
16d3a0bb77SLukas Straub #include "chardev/char-fe.h"
17d3a0bb77SLukas Straub #include "sysemu/sysemu.h"
18d3a0bb77SLukas Straub #include "qapi/error.h"
19d3a0bb77SLukas Straub #include "qapi/qapi-commands-char.h"
20d3a0bb77SLukas Straub #include "qapi/qapi-types-char.h"
21d3a0bb77SLukas Straub #include "qapi/qapi-commands-yank.h"
22d3a0bb77SLukas Straub #include "qapi/qapi-types-yank.h"
23d3a0bb77SLukas Straub #include "io/channel-socket.h"
24d3a0bb77SLukas Straub #include "socket-helpers.h"
25d3a0bb77SLukas Straub 
26d3a0bb77SLukas Straub typedef struct {
27d3a0bb77SLukas Straub     SocketAddress *addr;
28d3a0bb77SLukas Straub     bool old_yank;
29d3a0bb77SLukas Straub     bool new_yank;
30d3a0bb77SLukas Straub     bool fail;
31d3a0bb77SLukas Straub } CharChangeTestConfig;
32d3a0bb77SLukas Straub 
chardev_change(void * opaque)33d3a0bb77SLukas Straub static int chardev_change(void *opaque)
34d3a0bb77SLukas Straub {
35d3a0bb77SLukas Straub     return 0;
36d3a0bb77SLukas Straub }
37d3a0bb77SLukas Straub 
is_yank_instance_registered(void)38d3a0bb77SLukas Straub static bool is_yank_instance_registered(void)
39d3a0bb77SLukas Straub {
40d3a0bb77SLukas Straub     YankInstanceList *list;
41d3a0bb77SLukas Straub     bool ret;
42d3a0bb77SLukas Straub 
43d3a0bb77SLukas Straub     list = qmp_query_yank(&error_abort);
44d3a0bb77SLukas Straub 
45d3a0bb77SLukas Straub     ret = !!list;
46d3a0bb77SLukas Straub 
47d3a0bb77SLukas Straub     qapi_free_YankInstanceList(list);
48d3a0bb77SLukas Straub 
49d3a0bb77SLukas Straub     return ret;
50d3a0bb77SLukas Straub }
51d3a0bb77SLukas Straub 
accept_thread(gpointer data)52d3a0bb77SLukas Straub static gpointer accept_thread(gpointer data)
53d3a0bb77SLukas Straub {
54d3a0bb77SLukas Straub     QIOChannelSocket *ioc = data;
55d3a0bb77SLukas Straub     QIOChannelSocket *cioc;
56d3a0bb77SLukas Straub 
57d3a0bb77SLukas Straub     cioc = qio_channel_socket_accept(ioc, &error_abort);
58d3a0bb77SLukas Straub     object_unref(OBJECT(cioc));
59d3a0bb77SLukas Straub 
60d3a0bb77SLukas Straub     return NULL;
61d3a0bb77SLukas Straub }
62d3a0bb77SLukas Straub 
char_change_test(gconstpointer opaque)63d3a0bb77SLukas Straub static void char_change_test(gconstpointer opaque)
64d3a0bb77SLukas Straub {
65d3a0bb77SLukas Straub     CharChangeTestConfig *conf = (gpointer) opaque;
66d3a0bb77SLukas Straub     SocketAddress *addr;
67d3a0bb77SLukas Straub     Chardev *chr;
68d3a0bb77SLukas Straub     CharBackend be;
69d3a0bb77SLukas Straub     ChardevReturn *ret;
70d3a0bb77SLukas Straub     QIOChannelSocket *ioc;
71d3a0bb77SLukas Straub     QemuThread thread;
72d3a0bb77SLukas Straub 
73d3a0bb77SLukas Straub     /*
74d3a0bb77SLukas Straub      * Setup a listener socket and determine its address
75d3a0bb77SLukas Straub      * so we know the TCP port for the client later
76d3a0bb77SLukas Straub      */
77d3a0bb77SLukas Straub     ioc = qio_channel_socket_new();
78d3a0bb77SLukas Straub     g_assert_nonnull(ioc);
79d3a0bb77SLukas Straub     qio_channel_socket_listen_sync(ioc, conf->addr, 1, &error_abort);
80d3a0bb77SLukas Straub     addr = qio_channel_socket_get_local_address(ioc, &error_abort);
81d3a0bb77SLukas Straub     g_assert_nonnull(addr);
82d3a0bb77SLukas Straub 
83d3a0bb77SLukas Straub     ChardevBackend backend[2] = {
84d3a0bb77SLukas Straub         /* doesn't support yank */
85d3a0bb77SLukas Straub         { .type = CHARDEV_BACKEND_KIND_NULL },
86d3a0bb77SLukas Straub         /* supports yank */
87d3a0bb77SLukas Straub         {
88d3a0bb77SLukas Straub             .type = CHARDEV_BACKEND_KIND_SOCKET,
89d3a0bb77SLukas Straub             .u.socket.data = &(ChardevSocket) {
90d3a0bb77SLukas Straub                 .addr = &(SocketAddressLegacy) {
91*935a867cSMarkus Armbruster                     .type = SOCKET_ADDRESS_TYPE_INET,
92d3a0bb77SLukas Straub                     .u.inet.data = &addr->u.inet
93d3a0bb77SLukas Straub                 },
94d3a0bb77SLukas Straub                 .has_server = true,
95d3a0bb77SLukas Straub                 .server = false
96d3a0bb77SLukas Straub             }
97d3a0bb77SLukas Straub         } };
98d3a0bb77SLukas Straub 
99d3a0bb77SLukas Straub     ChardevBackend fail_backend[2] = {
100d3a0bb77SLukas Straub         /* doesn't support yank */
101d3a0bb77SLukas Straub         {
102d3a0bb77SLukas Straub             .type = CHARDEV_BACKEND_KIND_UDP,
103d3a0bb77SLukas Straub             .u.udp.data = &(ChardevUdp) {
104d3a0bb77SLukas Straub                 .remote = &(SocketAddressLegacy) {
105*935a867cSMarkus Armbruster                     .type = SOCKET_ADDRESS_TYPE_UNIX,
106d3a0bb77SLukas Straub                     .u.q_unix.data = &(UnixSocketAddress) {
107d3a0bb77SLukas Straub                         .path = (char *)""
108d3a0bb77SLukas Straub                     }
109d3a0bb77SLukas Straub                 }
110d3a0bb77SLukas Straub             }
111d3a0bb77SLukas Straub         },
112d3a0bb77SLukas Straub         /* supports yank */
113d3a0bb77SLukas Straub         {
114d3a0bb77SLukas Straub             .type = CHARDEV_BACKEND_KIND_SOCKET,
115d3a0bb77SLukas Straub             .u.socket.data = &(ChardevSocket) {
116d3a0bb77SLukas Straub                 .addr = &(SocketAddressLegacy) {
117*935a867cSMarkus Armbruster                     .type = SOCKET_ADDRESS_TYPE_INET,
118d3a0bb77SLukas Straub                     .u.inet.data = &(InetSocketAddress) {
119d3a0bb77SLukas Straub                         .host = (char *)"127.0.0.1",
120d3a0bb77SLukas Straub                         .port = (char *)"0"
121d3a0bb77SLukas Straub                     }
122d3a0bb77SLukas Straub                 },
123d3a0bb77SLukas Straub                 .has_server = true,
124d3a0bb77SLukas Straub                 .server = false
125d3a0bb77SLukas Straub             }
126d3a0bb77SLukas Straub         } };
127d3a0bb77SLukas Straub 
128d3a0bb77SLukas Straub     g_assert(!is_yank_instance_registered());
129d3a0bb77SLukas Straub 
130d3a0bb77SLukas Straub     if (conf->old_yank) {
131d3a0bb77SLukas Straub         qemu_thread_create(&thread, "accept", accept_thread,
132d3a0bb77SLukas Straub                            ioc, QEMU_THREAD_JOINABLE);
133d3a0bb77SLukas Straub     }
134d3a0bb77SLukas Straub 
135d3a0bb77SLukas Straub     ret = qmp_chardev_add("chardev", &backend[conf->old_yank], &error_abort);
136d3a0bb77SLukas Straub     qapi_free_ChardevReturn(ret);
137d3a0bb77SLukas Straub     chr = qemu_chr_find("chardev");
138d3a0bb77SLukas Straub     g_assert_nonnull(chr);
139d3a0bb77SLukas Straub 
140d3a0bb77SLukas Straub     g_assert(is_yank_instance_registered() == conf->old_yank);
141d3a0bb77SLukas Straub 
142d3a0bb77SLukas Straub     qemu_chr_wait_connected(chr, &error_abort);
143d3a0bb77SLukas Straub     if (conf->old_yank) {
144d3a0bb77SLukas Straub         qemu_thread_join(&thread);
145d3a0bb77SLukas Straub     }
146d3a0bb77SLukas Straub 
147d3a0bb77SLukas Straub     qemu_chr_fe_init(&be, chr, &error_abort);
148d3a0bb77SLukas Straub     /* allow chardev-change */
149d3a0bb77SLukas Straub     qemu_chr_fe_set_handlers(&be, NULL, NULL,
150d3a0bb77SLukas Straub                              NULL, chardev_change, NULL, NULL, true);
151d3a0bb77SLukas Straub 
152d3a0bb77SLukas Straub     if (conf->fail) {
153d3a0bb77SLukas Straub         g_setenv("QTEST_SILENT_ERRORS", "1", 1);
154d3a0bb77SLukas Straub         ret = qmp_chardev_change("chardev", &fail_backend[conf->new_yank],
155d3a0bb77SLukas Straub                                  NULL);
156d3a0bb77SLukas Straub         g_assert_null(ret);
157d3a0bb77SLukas Straub         g_assert(be.chr == chr);
158d3a0bb77SLukas Straub         g_assert(is_yank_instance_registered() == conf->old_yank);
159d3a0bb77SLukas Straub         g_unsetenv("QTEST_SILENT_ERRORS");
160d3a0bb77SLukas Straub     } else {
161d3a0bb77SLukas Straub         if (conf->new_yank) {
162d3a0bb77SLukas Straub                 qemu_thread_create(&thread, "accept", accept_thread,
163d3a0bb77SLukas Straub                                    ioc, QEMU_THREAD_JOINABLE);
164d3a0bb77SLukas Straub         }
165d3a0bb77SLukas Straub         ret = qmp_chardev_change("chardev", &backend[conf->new_yank],
166d3a0bb77SLukas Straub                                  &error_abort);
167d3a0bb77SLukas Straub         if (conf->new_yank) {
168d3a0bb77SLukas Straub             qemu_thread_join(&thread);
169d3a0bb77SLukas Straub         }
170d3a0bb77SLukas Straub         g_assert_nonnull(ret);
171d3a0bb77SLukas Straub         g_assert(be.chr != chr);
172d3a0bb77SLukas Straub         g_assert(is_yank_instance_registered() == conf->new_yank);
173d3a0bb77SLukas Straub     }
174d3a0bb77SLukas Straub 
175d3a0bb77SLukas Straub     object_unparent(OBJECT(be.chr));
176d3a0bb77SLukas Straub     object_unref(OBJECT(ioc));
177d3a0bb77SLukas Straub     qapi_free_ChardevReturn(ret);
178d3a0bb77SLukas Straub     qapi_free_SocketAddress(addr);
179d3a0bb77SLukas Straub }
180d3a0bb77SLukas Straub 
181d3a0bb77SLukas Straub static SocketAddress tcpaddr = {
182d3a0bb77SLukas Straub     .type = SOCKET_ADDRESS_TYPE_INET,
183d3a0bb77SLukas Straub     .u.inet.host = (char *)"127.0.0.1",
184d3a0bb77SLukas Straub     .u.inet.port = (char *)"0",
185d3a0bb77SLukas Straub };
186d3a0bb77SLukas Straub 
main(int argc,char ** argv)187d3a0bb77SLukas Straub int main(int argc, char **argv)
188d3a0bb77SLukas Straub {
189d3a0bb77SLukas Straub     bool has_ipv4, has_ipv6;
190d3a0bb77SLukas Straub 
191d3a0bb77SLukas Straub     qemu_init_main_loop(&error_abort);
192d3a0bb77SLukas Straub     socket_init();
193d3a0bb77SLukas Straub 
194d3a0bb77SLukas Straub     g_test_init(&argc, &argv, NULL);
195d3a0bb77SLukas Straub 
196d3a0bb77SLukas Straub     if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
197d3a0bb77SLukas Straub         g_printerr("socket_check_protocol_support() failed\n");
198d3a0bb77SLukas Straub         goto end;
199d3a0bb77SLukas Straub     }
200d3a0bb77SLukas Straub 
201d3a0bb77SLukas Straub     if (!has_ipv4) {
202d3a0bb77SLukas Straub         goto end;
203d3a0bb77SLukas Straub     }
204d3a0bb77SLukas Straub 
205d3a0bb77SLukas Straub     module_call_init(MODULE_INIT_QOM);
206d3a0bb77SLukas Straub     qemu_add_opts(&qemu_chardev_opts);
207d3a0bb77SLukas Straub 
208d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/success/to_yank",
209d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
210d3a0bb77SLukas Straub                                                    .old_yank = false,
211d3a0bb77SLukas Straub                                                    .new_yank = true,
212d3a0bb77SLukas Straub                                                    .fail = false },
213d3a0bb77SLukas Straub                          char_change_test);
214d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/fail/to_yank",
215d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
216d3a0bb77SLukas Straub                                                    .old_yank = false,
217d3a0bb77SLukas Straub                                                    .new_yank = true,
218d3a0bb77SLukas Straub                                                    .fail = true },
219d3a0bb77SLukas Straub                          char_change_test);
220d3a0bb77SLukas Straub 
221d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/success/yank_to_yank",
222d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
223d3a0bb77SLukas Straub                                                    .old_yank = true,
224d3a0bb77SLukas Straub                                                    .new_yank = true,
225d3a0bb77SLukas Straub                                                    .fail = false },
226d3a0bb77SLukas Straub                          char_change_test);
227d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/fail/yank_to_yank",
228d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
229d3a0bb77SLukas Straub                                                    .old_yank = true,
230d3a0bb77SLukas Straub                                                    .new_yank = true,
231d3a0bb77SLukas Straub                                                    .fail = true },
232d3a0bb77SLukas Straub                          char_change_test);
233d3a0bb77SLukas Straub 
234d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/success/from_yank",
235d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
236d3a0bb77SLukas Straub                                                    .old_yank = true,
237d3a0bb77SLukas Straub                                                    .new_yank = false,
238d3a0bb77SLukas Straub                                                    .fail = false },
239d3a0bb77SLukas Straub                          char_change_test);
240d3a0bb77SLukas Straub     g_test_add_data_func("/yank/char_change/fail/from_yank",
241d3a0bb77SLukas Straub                          &(CharChangeTestConfig) { .addr = &tcpaddr,
242d3a0bb77SLukas Straub                                                    .old_yank = true,
243d3a0bb77SLukas Straub                                                    .new_yank = false,
244d3a0bb77SLukas Straub                                                    .fail = true },
245d3a0bb77SLukas Straub                          char_change_test);
246d3a0bb77SLukas Straub 
247d3a0bb77SLukas Straub end:
248d3a0bb77SLukas Straub     return g_test_run();
249d3a0bb77SLukas Straub }
250