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