xref: /qemu/tests/qtest/dbus-display-test.c (revision b4dd5b6a60eb525437c8d315d0d59dc25d4e4cb1)
1*b4dd5b6aSMarc-André Lureau #include "qemu/osdep.h"
2*b4dd5b6aSMarc-André Lureau #include "qemu/dbus.h"
3*b4dd5b6aSMarc-André Lureau #include <gio/gio.h>
4*b4dd5b6aSMarc-André Lureau #include <gio/gunixfdlist.h>
5*b4dd5b6aSMarc-André Lureau #include "libqos/libqtest.h"
6*b4dd5b6aSMarc-André Lureau #include "qemu-common.h"
7*b4dd5b6aSMarc-André Lureau #include "dbus-display1.h"
8*b4dd5b6aSMarc-André Lureau 
9*b4dd5b6aSMarc-André Lureau static GDBusConnection*
10*b4dd5b6aSMarc-André Lureau test_dbus_p2p_from_fd(int fd)
11*b4dd5b6aSMarc-André Lureau {
12*b4dd5b6aSMarc-André Lureau     g_autoptr(GError) err = NULL;
13*b4dd5b6aSMarc-André Lureau     g_autoptr(GSocket) socket = NULL;
14*b4dd5b6aSMarc-André Lureau     g_autoptr(GSocketConnection) socketc = NULL;
15*b4dd5b6aSMarc-André Lureau     GDBusConnection *conn;
16*b4dd5b6aSMarc-André Lureau 
17*b4dd5b6aSMarc-André Lureau     socket = g_socket_new_from_fd(fd, &err);
18*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
19*b4dd5b6aSMarc-André Lureau 
20*b4dd5b6aSMarc-André Lureau     socketc = g_socket_connection_factory_create_connection(socket);
21*b4dd5b6aSMarc-André Lureau     g_assert(socketc != NULL);
22*b4dd5b6aSMarc-André Lureau 
23*b4dd5b6aSMarc-André Lureau     conn = g_dbus_connection_new_sync(
24*b4dd5b6aSMarc-André Lureau         G_IO_STREAM(socketc), NULL,
25*b4dd5b6aSMarc-André Lureau         G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
26*b4dd5b6aSMarc-André Lureau         G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
27*b4dd5b6aSMarc-André Lureau         NULL, NULL, &err);
28*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
29*b4dd5b6aSMarc-André Lureau 
30*b4dd5b6aSMarc-André Lureau     return conn;
31*b4dd5b6aSMarc-André Lureau }
32*b4dd5b6aSMarc-André Lureau 
33*b4dd5b6aSMarc-André Lureau static void
34*b4dd5b6aSMarc-André Lureau test_setup(QTestState **qts, GDBusConnection **conn)
35*b4dd5b6aSMarc-André Lureau {
36*b4dd5b6aSMarc-André Lureau     int pair[2];
37*b4dd5b6aSMarc-André Lureau 
38*b4dd5b6aSMarc-André Lureau     *qts = qtest_init("-display dbus,p2p=yes -name dbus-test");
39*b4dd5b6aSMarc-André Lureau 
40*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
41*b4dd5b6aSMarc-André Lureau 
42*b4dd5b6aSMarc-André Lureau     qtest_qmp_add_client(*qts, "@dbus-display", pair[1]);
43*b4dd5b6aSMarc-André Lureau 
44*b4dd5b6aSMarc-André Lureau     *conn = test_dbus_p2p_from_fd(pair[0]);
45*b4dd5b6aSMarc-André Lureau     g_dbus_connection_start_message_processing(*conn);
46*b4dd5b6aSMarc-André Lureau }
47*b4dd5b6aSMarc-André Lureau 
48*b4dd5b6aSMarc-André Lureau static void
49*b4dd5b6aSMarc-André Lureau test_dbus_display_vm(void)
50*b4dd5b6aSMarc-André Lureau {
51*b4dd5b6aSMarc-André Lureau     g_autoptr(GError) err = NULL;
52*b4dd5b6aSMarc-André Lureau     g_autoptr(GDBusConnection) conn = NULL;
53*b4dd5b6aSMarc-André Lureau     g_autoptr(QemuDBusDisplay1VMProxy) vm = NULL;
54*b4dd5b6aSMarc-André Lureau     QTestState *qts = NULL;
55*b4dd5b6aSMarc-André Lureau 
56*b4dd5b6aSMarc-André Lureau     test_setup(&qts, &conn);
57*b4dd5b6aSMarc-André Lureau 
58*b4dd5b6aSMarc-André Lureau     vm = QEMU_DBUS_DISPLAY1_VM_PROXY(
59*b4dd5b6aSMarc-André Lureau         qemu_dbus_display1_vm_proxy_new_sync(
60*b4dd5b6aSMarc-André Lureau             conn,
61*b4dd5b6aSMarc-André Lureau             G_DBUS_PROXY_FLAGS_NONE,
62*b4dd5b6aSMarc-André Lureau             NULL,
63*b4dd5b6aSMarc-André Lureau             DBUS_DISPLAY1_ROOT "/VM",
64*b4dd5b6aSMarc-André Lureau             NULL,
65*b4dd5b6aSMarc-André Lureau             &err));
66*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
67*b4dd5b6aSMarc-André Lureau 
68*b4dd5b6aSMarc-André Lureau     g_assert_cmpstr(
69*b4dd5b6aSMarc-André Lureau         qemu_dbus_display1_vm_get_name(QEMU_DBUS_DISPLAY1_VM(vm)),
70*b4dd5b6aSMarc-André Lureau         ==,
71*b4dd5b6aSMarc-André Lureau         "dbus-test");
72*b4dd5b6aSMarc-André Lureau     qtest_quit(qts);
73*b4dd5b6aSMarc-André Lureau }
74*b4dd5b6aSMarc-André Lureau 
75*b4dd5b6aSMarc-André Lureau typedef struct TestDBusConsoleRegister {
76*b4dd5b6aSMarc-André Lureau     GMainLoop *loop;
77*b4dd5b6aSMarc-André Lureau     GThread *thread;
78*b4dd5b6aSMarc-André Lureau     GDBusConnection *listener_conn;
79*b4dd5b6aSMarc-André Lureau     GDBusObjectManagerServer *server;
80*b4dd5b6aSMarc-André Lureau } TestDBusConsoleRegister;
81*b4dd5b6aSMarc-André Lureau 
82*b4dd5b6aSMarc-André Lureau static gboolean listener_handle_scanout(
83*b4dd5b6aSMarc-André Lureau     QemuDBusDisplay1Listener *object,
84*b4dd5b6aSMarc-André Lureau     GDBusMethodInvocation *invocation,
85*b4dd5b6aSMarc-André Lureau     guint arg_width,
86*b4dd5b6aSMarc-André Lureau     guint arg_height,
87*b4dd5b6aSMarc-André Lureau     guint arg_stride,
88*b4dd5b6aSMarc-André Lureau     guint arg_pixman_format,
89*b4dd5b6aSMarc-André Lureau     GVariant *arg_data,
90*b4dd5b6aSMarc-André Lureau     TestDBusConsoleRegister *test)
91*b4dd5b6aSMarc-André Lureau {
92*b4dd5b6aSMarc-André Lureau     g_main_loop_quit(test->loop);
93*b4dd5b6aSMarc-André Lureau 
94*b4dd5b6aSMarc-André Lureau     return DBUS_METHOD_INVOCATION_HANDLED;
95*b4dd5b6aSMarc-André Lureau }
96*b4dd5b6aSMarc-André Lureau 
97*b4dd5b6aSMarc-André Lureau static void
98*b4dd5b6aSMarc-André Lureau test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
99*b4dd5b6aSMarc-André Lureau {
100*b4dd5b6aSMarc-André Lureau     g_autoptr(GDBusObjectSkeleton) listener = NULL;
101*b4dd5b6aSMarc-André Lureau     g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL;
102*b4dd5b6aSMarc-André Lureau 
103*b4dd5b6aSMarc-André Lureau     test->server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT);
104*b4dd5b6aSMarc-André Lureau     listener = g_dbus_object_skeleton_new(DBUS_DISPLAY1_ROOT "/Listener");
105*b4dd5b6aSMarc-André Lureau     iface = QEMU_DBUS_DISPLAY1_LISTENER_SKELETON(
106*b4dd5b6aSMarc-André Lureau         qemu_dbus_display1_listener_skeleton_new());
107*b4dd5b6aSMarc-André Lureau     g_object_connect(iface,
108*b4dd5b6aSMarc-André Lureau                      "signal::handle-scanout", listener_handle_scanout, test,
109*b4dd5b6aSMarc-André Lureau                      NULL);
110*b4dd5b6aSMarc-André Lureau     g_dbus_object_skeleton_add_interface(listener,
111*b4dd5b6aSMarc-André Lureau                                          G_DBUS_INTERFACE_SKELETON(iface));
112*b4dd5b6aSMarc-André Lureau     g_dbus_object_manager_server_export(test->server, listener);
113*b4dd5b6aSMarc-André Lureau     g_dbus_object_manager_server_set_connection(test->server,
114*b4dd5b6aSMarc-André Lureau                                                 test->listener_conn);
115*b4dd5b6aSMarc-André Lureau 
116*b4dd5b6aSMarc-André Lureau     g_dbus_connection_start_message_processing(test->listener_conn);
117*b4dd5b6aSMarc-André Lureau }
118*b4dd5b6aSMarc-André Lureau 
119*b4dd5b6aSMarc-André Lureau static void
120*b4dd5b6aSMarc-André Lureau test_dbus_console_registered(GObject *source_object,
121*b4dd5b6aSMarc-André Lureau                              GAsyncResult *res,
122*b4dd5b6aSMarc-André Lureau                              gpointer user_data)
123*b4dd5b6aSMarc-André Lureau {
124*b4dd5b6aSMarc-André Lureau     TestDBusConsoleRegister *test = user_data;
125*b4dd5b6aSMarc-André Lureau     g_autoptr(GError) err = NULL;
126*b4dd5b6aSMarc-André Lureau 
127*b4dd5b6aSMarc-André Lureau     qemu_dbus_display1_console_call_register_listener_finish(
128*b4dd5b6aSMarc-André Lureau         QEMU_DBUS_DISPLAY1_CONSOLE(source_object),
129*b4dd5b6aSMarc-André Lureau         NULL, res, &err);
130*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
131*b4dd5b6aSMarc-André Lureau 
132*b4dd5b6aSMarc-André Lureau     test->listener_conn = g_thread_join(test->thread);
133*b4dd5b6aSMarc-André Lureau     test_dbus_console_setup_listener(test);
134*b4dd5b6aSMarc-André Lureau }
135*b4dd5b6aSMarc-André Lureau 
136*b4dd5b6aSMarc-André Lureau static gpointer
137*b4dd5b6aSMarc-André Lureau test_dbus_p2p_server_setup_thread(gpointer data)
138*b4dd5b6aSMarc-André Lureau {
139*b4dd5b6aSMarc-André Lureau     return test_dbus_p2p_from_fd(GPOINTER_TO_INT(data));
140*b4dd5b6aSMarc-André Lureau }
141*b4dd5b6aSMarc-André Lureau 
142*b4dd5b6aSMarc-André Lureau static void
143*b4dd5b6aSMarc-André Lureau test_dbus_display_console(void)
144*b4dd5b6aSMarc-André Lureau {
145*b4dd5b6aSMarc-André Lureau     g_autoptr(GError) err = NULL;
146*b4dd5b6aSMarc-André Lureau     g_autoptr(GDBusConnection) conn = NULL;
147*b4dd5b6aSMarc-André Lureau     g_autoptr(QemuDBusDisplay1ConsoleProxy) console = NULL;
148*b4dd5b6aSMarc-André Lureau     g_autoptr(GUnixFDList) fd_list = NULL;
149*b4dd5b6aSMarc-André Lureau     g_autoptr(GMainLoop) loop = NULL;
150*b4dd5b6aSMarc-André Lureau     QTestState *qts = NULL;
151*b4dd5b6aSMarc-André Lureau     int pair[2], idx;
152*b4dd5b6aSMarc-André Lureau     TestDBusConsoleRegister test;
153*b4dd5b6aSMarc-André Lureau 
154*b4dd5b6aSMarc-André Lureau     test_setup(&qts, &conn);
155*b4dd5b6aSMarc-André Lureau 
156*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
157*b4dd5b6aSMarc-André Lureau     fd_list = g_unix_fd_list_new();
158*b4dd5b6aSMarc-André Lureau     idx = g_unix_fd_list_append(fd_list, pair[1], NULL);
159*b4dd5b6aSMarc-André Lureau 
160*b4dd5b6aSMarc-André Lureau     console = QEMU_DBUS_DISPLAY1_CONSOLE_PROXY(
161*b4dd5b6aSMarc-André Lureau         qemu_dbus_display1_console_proxy_new_sync(
162*b4dd5b6aSMarc-André Lureau             conn,
163*b4dd5b6aSMarc-André Lureau             G_DBUS_PROXY_FLAGS_NONE,
164*b4dd5b6aSMarc-André Lureau             NULL,
165*b4dd5b6aSMarc-André Lureau             "/org/qemu/Display1/Console_0",
166*b4dd5b6aSMarc-André Lureau             NULL,
167*b4dd5b6aSMarc-André Lureau             &err));
168*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
169*b4dd5b6aSMarc-André Lureau 
170*b4dd5b6aSMarc-André Lureau     test.loop = loop = g_main_loop_new(NULL, FALSE);
171*b4dd5b6aSMarc-André Lureau     test.thread = g_thread_new(NULL, test_dbus_p2p_server_setup_thread,
172*b4dd5b6aSMarc-André Lureau                                GINT_TO_POINTER(pair[0]));
173*b4dd5b6aSMarc-André Lureau 
174*b4dd5b6aSMarc-André Lureau     qemu_dbus_display1_console_call_register_listener(
175*b4dd5b6aSMarc-André Lureau         QEMU_DBUS_DISPLAY1_CONSOLE(console),
176*b4dd5b6aSMarc-André Lureau         g_variant_new_handle(idx),
177*b4dd5b6aSMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
178*b4dd5b6aSMarc-André Lureau         -1,
179*b4dd5b6aSMarc-André Lureau         fd_list,
180*b4dd5b6aSMarc-André Lureau         NULL,
181*b4dd5b6aSMarc-André Lureau         test_dbus_console_registered,
182*b4dd5b6aSMarc-André Lureau         &test);
183*b4dd5b6aSMarc-André Lureau 
184*b4dd5b6aSMarc-André Lureau     g_main_loop_run(loop);
185*b4dd5b6aSMarc-André Lureau 
186*b4dd5b6aSMarc-André Lureau     g_clear_object(&test.server);
187*b4dd5b6aSMarc-André Lureau     g_clear_object(&test.listener_conn);
188*b4dd5b6aSMarc-André Lureau     qtest_quit(qts);
189*b4dd5b6aSMarc-André Lureau }
190*b4dd5b6aSMarc-André Lureau 
191*b4dd5b6aSMarc-André Lureau static void
192*b4dd5b6aSMarc-André Lureau test_dbus_display_keyboard(void)
193*b4dd5b6aSMarc-André Lureau {
194*b4dd5b6aSMarc-André Lureau     g_autoptr(GError) err = NULL;
195*b4dd5b6aSMarc-André Lureau     g_autoptr(GDBusConnection) conn = NULL;
196*b4dd5b6aSMarc-André Lureau     g_autoptr(QemuDBusDisplay1KeyboardProxy) keyboard = NULL;
197*b4dd5b6aSMarc-André Lureau     QTestState *qts = NULL;
198*b4dd5b6aSMarc-André Lureau 
199*b4dd5b6aSMarc-André Lureau     test_setup(&qts, &conn);
200*b4dd5b6aSMarc-André Lureau 
201*b4dd5b6aSMarc-André Lureau     keyboard = QEMU_DBUS_DISPLAY1_KEYBOARD_PROXY(
202*b4dd5b6aSMarc-André Lureau         qemu_dbus_display1_keyboard_proxy_new_sync(
203*b4dd5b6aSMarc-André Lureau             conn,
204*b4dd5b6aSMarc-André Lureau             G_DBUS_PROXY_FLAGS_NONE,
205*b4dd5b6aSMarc-André Lureau             NULL,
206*b4dd5b6aSMarc-André Lureau             "/org/qemu/Display1/Console_0",
207*b4dd5b6aSMarc-André Lureau             NULL,
208*b4dd5b6aSMarc-André Lureau             &err));
209*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
210*b4dd5b6aSMarc-André Lureau 
211*b4dd5b6aSMarc-André Lureau 
212*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 0);
213*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0);
214*b4dd5b6aSMarc-André Lureau 
215*b4dd5b6aSMarc-André Lureau     qemu_dbus_display1_keyboard_call_press_sync(
216*b4dd5b6aSMarc-André Lureau         QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard),
217*b4dd5b6aSMarc-André Lureau         0x1C, /* qnum enter */
218*b4dd5b6aSMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
219*b4dd5b6aSMarc-André Lureau         -1,
220*b4dd5b6aSMarc-André Lureau         NULL,
221*b4dd5b6aSMarc-André Lureau         &err);
222*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
223*b4dd5b6aSMarc-André Lureau 
224*b4dd5b6aSMarc-André Lureau     /* may be should wait for interrupt? */
225*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1);
226*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */
227*b4dd5b6aSMarc-André Lureau 
228*b4dd5b6aSMarc-André Lureau     qemu_dbus_display1_keyboard_call_release_sync(
229*b4dd5b6aSMarc-André Lureau         QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard),
230*b4dd5b6aSMarc-André Lureau         0x1C, /* qnum enter */
231*b4dd5b6aSMarc-André Lureau         G_DBUS_CALL_FLAGS_NONE,
232*b4dd5b6aSMarc-André Lureau         -1,
233*b4dd5b6aSMarc-André Lureau         NULL,
234*b4dd5b6aSMarc-André Lureau         &err);
235*b4dd5b6aSMarc-André Lureau     g_assert_no_error(err);
236*b4dd5b6aSMarc-André Lureau 
237*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1);
238*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0xF0); /* scan code 2 release */
239*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */
240*b4dd5b6aSMarc-André Lureau 
241*b4dd5b6aSMarc-André Lureau     g_assert_cmpint(qemu_dbus_display1_keyboard_get_modifiers(
242*b4dd5b6aSMarc-André Lureau                         QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard)), ==, 0);
243*b4dd5b6aSMarc-André Lureau 
244*b4dd5b6aSMarc-André Lureau     qtest_quit(qts);
245*b4dd5b6aSMarc-André Lureau }
246*b4dd5b6aSMarc-André Lureau 
247*b4dd5b6aSMarc-André Lureau int
248*b4dd5b6aSMarc-André Lureau main(int argc, char **argv)
249*b4dd5b6aSMarc-André Lureau {
250*b4dd5b6aSMarc-André Lureau     g_test_init(&argc, &argv, NULL);
251*b4dd5b6aSMarc-André Lureau 
252*b4dd5b6aSMarc-André Lureau     qtest_add_func("/dbus-display/vm", test_dbus_display_vm);
253*b4dd5b6aSMarc-André Lureau     qtest_add_func("/dbus-display/console", test_dbus_display_console);
254*b4dd5b6aSMarc-André Lureau     qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard);
255*b4dd5b6aSMarc-André Lureau 
256*b4dd5b6aSMarc-André Lureau     return g_test_run();
257*b4dd5b6aSMarc-André Lureau }
258