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