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