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