1 #include "qemu/osdep.h"
2 #include <glib/gstdio.h>
4 #include "libqos/libqtest.h"
5 #include "qemu-common.h"
6 #include "dbus-vmstate1.h"
7 #include "migration-helpers.h"
11 typedef struct TestServerId
{
17 static const TestServerId idA
= {
18 "idA", "I'am\0idA!", sizeof("I'am\0idA!")
21 static const TestServerId idB
= {
22 "idB", "I'am\0idB!", sizeof("I'am\0idB!")
25 typedef struct TestServer
{
26 const TestServerId
*id
;
44 vmstate_load(VMState1
*object
, GDBusMethodInvocation
*invocation
,
45 const gchar
*arg_data
, gpointer user_data
)
47 TestServer
*h
= user_data
;
48 g_autoptr(GVariant
) var
= NULL
;
53 args
= g_dbus_method_invocation_get_parameters(invocation
);
54 var
= g_variant_get_child_value(args
, 0);
55 data
= g_variant_get_fixed_array(var
, &size
, sizeof(char));
56 g_assert_cmpuint(size
, ==, h
->id
->size
);
57 g_assert(!memcmp(data
, h
->id
->data
, h
->id
->size
));
58 h
->load_called
= true;
60 g_dbus_method_invocation_return_value(invocation
, g_variant_new("()"));
65 vmstate_save(VMState1
*object
, GDBusMethodInvocation
*invocation
,
68 TestServer
*h
= user_data
;
71 var
= g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE
,
72 h
->id
->data
, h
->id
->size
, sizeof(char));
73 g_dbus_method_invocation_return_value(invocation
,
74 g_variant_new("(@ay)", var
));
75 h
->save_called
= true;
80 typedef struct WaitNamed
{
86 named_cb(GDBusConnection
*connection
,
90 WaitNamed
*t
= user_data
;
93 g_main_loop_quit(t
->loop
);
96 static GDBusConnection
*
97 get_connection(Test
*test
, guint
*ownid
)
99 g_autofree gchar
*addr
= NULL
;
104 wait
= g_new0(WaitNamed
, 1);
105 wait
->loop
= test
->loop
;
106 addr
= g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION
, NULL
, &err
);
107 g_assert_no_error(err
);
109 c
= g_dbus_connection_new_for_address_sync(
111 G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION
|
112 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT
,
114 g_assert_no_error(err
);
115 *ownid
= g_bus_own_name_on_connection(c
, "org.qemu.VMState1",
116 G_BUS_NAME_OWNER_FLAGS_NONE
,
117 named_cb
, named_cb
, wait
, g_free
);
119 g_main_loop_run(wait
->loop
);
125 static GDBusObjectManagerServer
*
126 get_server(GDBusConnection
*conn
, TestServer
*s
, const TestServerId
*id
)
128 g_autoptr(GDBusObjectSkeleton
) sk
= NULL
;
129 g_autoptr(VMState1Skeleton
) v
= NULL
;
130 GDBusObjectManagerServer
*os
;
133 os
= g_dbus_object_manager_server_new("/org/qemu");
134 sk
= g_dbus_object_skeleton_new("/org/qemu/VMState1");
136 v
= VMSTATE1_SKELETON(vmstate1_skeleton_new());
137 g_object_set(v
, "id", id
->name
, NULL
);
139 g_signal_connect(v
, "handle-load", G_CALLBACK(vmstate_load
), s
);
140 g_signal_connect(v
, "handle-save", G_CALLBACK(vmstate_save
), s
);
142 g_dbus_object_skeleton_add_interface(sk
, G_DBUS_INTERFACE_SKELETON(v
));
143 g_dbus_object_manager_server_export(os
, sk
);
144 g_dbus_object_manager_server_set_connection(os
, conn
);
150 set_id_list(Test
*test
, QTestState
*s
)
152 if (!test
->id_list
) {
156 g_assert(!qmp_rsp_is_err(qtest_qmp(s
,
157 "{ 'execute': 'qom-set', 'arguments': "
158 "{ 'path': '/objects/dv', 'property': 'id-list', 'value': %s } }",
163 dbus_vmstate_thread(gpointer data
)
165 GMainLoop
*loop
= data
;
167 g_main_loop_run(loop
);
173 test_dbus_vmstate(Test
*test
)
175 g_autofree
char *src_qemu_args
= NULL
;
176 g_autofree
char *dst_qemu_args
= NULL
;
177 g_autoptr(GTestDBus
) srcbus
= NULL
;
178 g_autoptr(GTestDBus
) dstbus
= NULL
;
179 g_autoptr(GDBusConnection
) srcconnA
= NULL
;
180 g_autoptr(GDBusConnection
) srcconnB
= NULL
;
181 g_autoptr(GDBusConnection
) dstconnA
= NULL
;
182 g_autoptr(GDBusConnection
) dstconnB
= NULL
;
183 g_autoptr(GDBusObjectManagerServer
) srcserverA
= NULL
;
184 g_autoptr(GDBusObjectManagerServer
) srcserverB
= NULL
;
185 g_autoptr(GDBusObjectManagerServer
) dstserverA
= NULL
;
186 g_autoptr(GDBusObjectManagerServer
) dstserverB
= NULL
;
187 g_auto(GStrv
) srcaddr
= NULL
;
188 g_auto(GStrv
) dstaddr
= NULL
;
189 g_autoptr(GThread
) thread
= NULL
;
190 g_autoptr(GMainLoop
) loop
= NULL
;
191 g_autofree
char *uri
= NULL
;
192 QTestState
*src_qemu
= NULL
, *dst_qemu
= NULL
;
193 guint ownsrcA
, ownsrcB
, owndstA
, owndstB
;
195 uri
= g_strdup_printf("unix:%s/migsocket", workdir
);
197 loop
= g_main_loop_new(NULL
, FALSE
);
200 srcbus
= g_test_dbus_new(G_TEST_DBUS_NONE
);
201 g_test_dbus_up(srcbus
);
202 srcconnA
= get_connection(test
, &ownsrcA
);
203 srcserverA
= get_server(srcconnA
, &test
->srcA
, &idA
);
204 srcconnB
= get_connection(test
, &ownsrcB
);
205 srcserverB
= get_server(srcconnB
, &test
->srcB
, &idB
);
207 /* remove ,guid=foo part */
208 srcaddr
= g_strsplit(g_test_dbus_get_bus_address(srcbus
), ",", 2);
210 g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s", srcaddr
[0]);
212 dstbus
= g_test_dbus_new(G_TEST_DBUS_NONE
);
213 g_test_dbus_up(dstbus
);
214 dstconnA
= get_connection(test
, &owndstA
);
215 dstserverA
= get_server(dstconnA
, &test
->dstA
, &idA
);
216 if (!test
->without_dst_b
) {
217 dstconnB
= get_connection(test
, &owndstB
);
218 dstserverB
= get_server(dstconnB
, &test
->dstB
, &idB
);
221 dstaddr
= g_strsplit(g_test_dbus_get_bus_address(dstbus
), ",", 2);
223 g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s -incoming %s",
226 src_qemu
= qtest_init(src_qemu_args
);
227 dst_qemu
= qtest_init(dst_qemu_args
);
228 set_id_list(test
, src_qemu
);
229 set_id_list(test
, dst_qemu
);
231 thread
= g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread
, loop
);
233 migrate_qmp(src_qemu
, uri
, "{}");
234 test
->src_qemu
= src_qemu
;
235 if (test
->migrate_fail
) {
236 wait_for_migration_fail(src_qemu
, true);
237 qtest_set_expected_status(dst_qemu
, 1);
239 wait_for_migration_complete(src_qemu
);
242 qtest_quit(dst_qemu
);
243 qtest_quit(src_qemu
);
244 g_bus_unown_name(ownsrcA
);
245 g_bus_unown_name(ownsrcB
);
246 g_bus_unown_name(owndstA
);
247 if (!test
->without_dst_b
) {
248 g_bus_unown_name(owndstB
);
251 g_main_loop_quit(test
->loop
);
255 check_not_migrated(TestServer
*s
, TestServer
*d
)
257 assert(!s
->save_called
);
258 assert(!s
->load_called
);
259 assert(!d
->save_called
);
260 assert(!d
->load_called
);
264 check_migrated(TestServer
*s
, TestServer
*d
)
266 assert(s
->save_called
);
267 assert(!s
->load_called
);
268 assert(!d
->save_called
);
269 assert(d
->load_called
);
273 test_dbus_vmstate_without_list(void)
277 test_dbus_vmstate(&test
);
279 check_migrated(&test
.srcA
, &test
.dstA
);
280 check_migrated(&test
.srcB
, &test
.dstB
);
284 test_dbus_vmstate_with_list(void)
286 Test test
= { .id_list
= "idA,idB" };
288 test_dbus_vmstate(&test
);
290 check_migrated(&test
.srcA
, &test
.dstA
);
291 check_migrated(&test
.srcB
, &test
.dstB
);
295 test_dbus_vmstate_only_a(void)
297 Test test
= { .id_list
= "idA" };
299 test_dbus_vmstate(&test
);
301 check_migrated(&test
.srcA
, &test
.dstA
);
302 check_not_migrated(&test
.srcB
, &test
.dstB
);
306 test_dbus_vmstate_missing_src(void)
308 Test test
= { .id_list
= "idA,idC", .migrate_fail
= true };
310 /* run in subprocess to silence QEMU error reporting */
311 if (g_test_subprocess()) {
312 test_dbus_vmstate(&test
);
313 check_not_migrated(&test
.srcA
, &test
.dstA
);
314 check_not_migrated(&test
.srcB
, &test
.dstB
);
318 g_test_trap_subprocess(NULL
, 0, 0);
319 g_test_trap_assert_passed();
323 test_dbus_vmstate_missing_dst(void)
325 Test test
= { .id_list
= "idA,idB",
326 .without_dst_b
= true,
327 .migrate_fail
= true };
329 /* run in subprocess to silence QEMU error reporting */
330 if (g_test_subprocess()) {
331 test_dbus_vmstate(&test
);
332 assert(test
.srcA
.save_called
);
333 assert(test
.srcB
.save_called
);
334 assert(!test
.dstB
.save_called
);
338 g_test_trap_subprocess(NULL
, 0, 0);
339 g_test_trap_assert_passed();
343 main(int argc
, char **argv
)
346 g_autofree
char *dbus_daemon
= NULL
;
349 dbus_daemon
= g_build_filename(G_STRINGIFY(SRCDIR
),
351 "dbus-vmstate-daemon.sh",
353 g_setenv("G_TEST_DBUS_DAEMON", dbus_daemon
, true);
355 g_test_init(&argc
, &argv
, NULL
);
357 workdir
= g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err
);
359 g_error("Unable to create temporary dir: %s\n", err
->message
);
363 g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir
, true);
365 qtest_add_func("/dbus-vmstate/without-list",
366 test_dbus_vmstate_without_list
);
367 qtest_add_func("/dbus-vmstate/with-list",
368 test_dbus_vmstate_with_list
);
369 qtest_add_func("/dbus-vmstate/only-a",
370 test_dbus_vmstate_only_a
);
371 qtest_add_func("/dbus-vmstate/missing-src",
372 test_dbus_vmstate_missing_src
);
373 qtest_add_func("/dbus-vmstate/missing-dst",
374 test_dbus_vmstate_missing_dst
);