2 * Tests for QEMU yank feature
4 * Copyright (c) Lukas Straub <lukasstraub2@web.de>
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include <glib/gstdio.h>
13 #include "qemu/config-file.h"
14 #include "qemu/module.h"
15 #include "qemu/option.h"
16 #include "chardev/char-fe.h"
17 #include "sysemu/sysemu.h"
18 #include "qapi/error.h"
19 #include "qapi/qapi-commands-char.h"
20 #include "qapi/qapi-types-char.h"
21 #include "qapi/qapi-commands-yank.h"
22 #include "qapi/qapi-types-yank.h"
23 #include "io/channel-socket.h"
24 #include "socket-helpers.h"
31 } CharChangeTestConfig
;
33 static int chardev_change(void *opaque
)
38 static bool is_yank_instance_registered(void)
40 YankInstanceList
*list
;
43 list
= qmp_query_yank(&error_abort
);
47 qapi_free_YankInstanceList(list
);
52 static gpointer
accept_thread(gpointer data
)
54 QIOChannelSocket
*ioc
= data
;
55 QIOChannelSocket
*cioc
;
57 cioc
= qio_channel_socket_accept(ioc
, &error_abort
);
58 object_unref(OBJECT(cioc
));
63 static void char_change_test(gconstpointer opaque
)
65 CharChangeTestConfig
*conf
= (gpointer
) opaque
;
70 QIOChannelSocket
*ioc
;
74 * Setup a listener socket and determine its address
75 * so we know the TCP port for the client later
77 ioc
= qio_channel_socket_new();
78 g_assert_nonnull(ioc
);
79 qio_channel_socket_listen_sync(ioc
, conf
->addr
, 1, &error_abort
);
80 addr
= qio_channel_socket_get_local_address(ioc
, &error_abort
);
81 g_assert_nonnull(addr
);
83 ChardevBackend backend
[2] = {
84 /* doesn't support yank */
85 { .type
= CHARDEV_BACKEND_KIND_NULL
},
88 .type
= CHARDEV_BACKEND_KIND_SOCKET
,
89 .u
.socket
.data
= &(ChardevSocket
) {
90 .addr
= &(SocketAddressLegacy
) {
91 .type
= SOCKET_ADDRESS_TYPE_INET
,
92 .u
.inet
.data
= &addr
->u
.inet
99 ChardevBackend fail_backend
[2] = {
100 /* doesn't support yank */
102 .type
= CHARDEV_BACKEND_KIND_UDP
,
103 .u
.udp
.data
= &(ChardevUdp
) {
104 .remote
= &(SocketAddressLegacy
) {
105 .type
= SOCKET_ADDRESS_TYPE_UNIX
,
106 .u
.q_unix
.data
= &(UnixSocketAddress
) {
114 .type
= CHARDEV_BACKEND_KIND_SOCKET
,
115 .u
.socket
.data
= &(ChardevSocket
) {
116 .addr
= &(SocketAddressLegacy
) {
117 .type
= SOCKET_ADDRESS_TYPE_INET
,
118 .u
.inet
.data
= &(InetSocketAddress
) {
119 .host
= (char *)"127.0.0.1",
128 g_assert(!is_yank_instance_registered());
130 if (conf
->old_yank
) {
131 qemu_thread_create(&thread
, "accept", accept_thread
,
132 ioc
, QEMU_THREAD_JOINABLE
);
135 ret
= qmp_chardev_add("chardev", &backend
[conf
->old_yank
], &error_abort
);
136 qapi_free_ChardevReturn(ret
);
137 chr
= qemu_chr_find("chardev");
138 g_assert_nonnull(chr
);
140 g_assert(is_yank_instance_registered() == conf
->old_yank
);
142 qemu_chr_wait_connected(chr
, &error_abort
);
143 if (conf
->old_yank
) {
144 qemu_thread_join(&thread
);
147 qemu_chr_fe_init(&be
, chr
, &error_abort
);
148 /* allow chardev-change */
149 qemu_chr_fe_set_handlers(&be
, NULL
, NULL
,
150 NULL
, chardev_change
, NULL
, NULL
, true);
153 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
154 ret
= qmp_chardev_change("chardev", &fail_backend
[conf
->new_yank
],
157 g_assert(be
.chr
== chr
);
158 g_assert(is_yank_instance_registered() == conf
->old_yank
);
159 g_unsetenv("QTEST_SILENT_ERRORS");
161 if (conf
->new_yank
) {
162 qemu_thread_create(&thread
, "accept", accept_thread
,
163 ioc
, QEMU_THREAD_JOINABLE
);
165 ret
= qmp_chardev_change("chardev", &backend
[conf
->new_yank
],
167 if (conf
->new_yank
) {
168 qemu_thread_join(&thread
);
170 g_assert_nonnull(ret
);
171 g_assert(be
.chr
!= chr
);
172 g_assert(is_yank_instance_registered() == conf
->new_yank
);
175 object_unparent(OBJECT(be
.chr
));
176 object_unref(OBJECT(ioc
));
177 qapi_free_ChardevReturn(ret
);
178 qapi_free_SocketAddress(addr
);
181 static SocketAddress tcpaddr
= {
182 .type
= SOCKET_ADDRESS_TYPE_INET
,
183 .u
.inet
.host
= (char *)"127.0.0.1",
184 .u
.inet
.port
= (char *)"0",
187 int main(int argc
, char **argv
)
189 bool has_ipv4
, has_ipv6
;
191 qemu_init_main_loop(&error_abort
);
194 g_test_init(&argc
, &argv
, NULL
);
196 if (socket_check_protocol_support(&has_ipv4
, &has_ipv6
) < 0) {
197 g_printerr("socket_check_protocol_support() failed\n");
205 module_call_init(MODULE_INIT_QOM
);
206 qemu_add_opts(&qemu_chardev_opts
);
208 g_test_add_data_func("/yank/char_change/success/to_yank",
209 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,
214 g_test_add_data_func("/yank/char_change/fail/to_yank",
215 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,
221 g_test_add_data_func("/yank/char_change/success/yank_to_yank",
222 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,
227 g_test_add_data_func("/yank/char_change/fail/yank_to_yank",
228 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,
234 g_test_add_data_func("/yank/char_change/success/from_yank",
235 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,
240 g_test_add_data_func("/yank/char_change/fail/from_yank",
241 &(CharChangeTestConfig
) { .addr
= &tcpaddr
,