-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cover basic display interface usage. More cases to be added to cover disconnections, multiple connections, corner cases. At this point, they would be better written in Rust or Python though. The proxy also covers reading the properties, since they are automatically loaded at creation. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
- Loading branch information
Showing
2 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
#include "qemu/osdep.h" | ||
#include "qemu/dbus.h" | ||
#include <gio/gio.h> | ||
#include <gio/gunixfdlist.h> | ||
#include "libqos/libqtest.h" | ||
#include "qemu-common.h" | ||
#include "dbus-display1.h" | ||
|
||
static GDBusConnection* | ||
test_dbus_p2p_from_fd(int fd) | ||
{ | ||
g_autoptr(GError) err = NULL; | ||
g_autoptr(GSocket) socket = NULL; | ||
g_autoptr(GSocketConnection) socketc = NULL; | ||
GDBusConnection *conn; | ||
|
||
socket = g_socket_new_from_fd(fd, &err); | ||
g_assert_no_error(err); | ||
|
||
socketc = g_socket_connection_factory_create_connection(socket); | ||
g_assert(socketc != NULL); | ||
|
||
conn = g_dbus_connection_new_sync( | ||
G_IO_STREAM(socketc), NULL, | ||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | | ||
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING, | ||
NULL, NULL, &err); | ||
g_assert_no_error(err); | ||
|
||
return conn; | ||
} | ||
|
||
static void | ||
test_setup(QTestState **qts, GDBusConnection **conn) | ||
{ | ||
int pair[2]; | ||
|
||
*qts = qtest_init("-display dbus,p2p=yes -name dbus-test"); | ||
|
||
g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); | ||
|
||
qtest_qmp_add_client(*qts, "@dbus-display", pair[1]); | ||
|
||
*conn = test_dbus_p2p_from_fd(pair[0]); | ||
g_dbus_connection_start_message_processing(*conn); | ||
} | ||
|
||
static void | ||
test_dbus_display_vm(void) | ||
{ | ||
g_autoptr(GError) err = NULL; | ||
g_autoptr(GDBusConnection) conn = NULL; | ||
g_autoptr(QemuDBusDisplay1VMProxy) vm = NULL; | ||
QTestState *qts = NULL; | ||
|
||
test_setup(&qts, &conn); | ||
|
||
vm = QEMU_DBUS_DISPLAY1_VM_PROXY( | ||
qemu_dbus_display1_vm_proxy_new_sync( | ||
conn, | ||
G_DBUS_PROXY_FLAGS_NONE, | ||
NULL, | ||
DBUS_DISPLAY1_ROOT "/VM", | ||
NULL, | ||
&err)); | ||
g_assert_no_error(err); | ||
|
||
g_assert_cmpstr( | ||
qemu_dbus_display1_vm_get_name(QEMU_DBUS_DISPLAY1_VM(vm)), | ||
==, | ||
"dbus-test"); | ||
qtest_quit(qts); | ||
} | ||
|
||
typedef struct TestDBusConsoleRegister { | ||
GMainLoop *loop; | ||
GThread *thread; | ||
GDBusConnection *listener_conn; | ||
GDBusObjectManagerServer *server; | ||
} TestDBusConsoleRegister; | ||
|
||
static gboolean listener_handle_scanout( | ||
QemuDBusDisplay1Listener *object, | ||
GDBusMethodInvocation *invocation, | ||
guint arg_width, | ||
guint arg_height, | ||
guint arg_stride, | ||
guint arg_pixman_format, | ||
GVariant *arg_data, | ||
TestDBusConsoleRegister *test) | ||
{ | ||
g_main_loop_quit(test->loop); | ||
|
||
return DBUS_METHOD_INVOCATION_HANDLED; | ||
} | ||
|
||
static void | ||
test_dbus_console_setup_listener(TestDBusConsoleRegister *test) | ||
{ | ||
g_autoptr(GDBusObjectSkeleton) listener = NULL; | ||
g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL; | ||
|
||
test->server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT); | ||
listener = g_dbus_object_skeleton_new(DBUS_DISPLAY1_ROOT "/Listener"); | ||
iface = QEMU_DBUS_DISPLAY1_LISTENER_SKELETON( | ||
qemu_dbus_display1_listener_skeleton_new()); | ||
g_object_connect(iface, | ||
"signal::handle-scanout", listener_handle_scanout, test, | ||
NULL); | ||
g_dbus_object_skeleton_add_interface(listener, | ||
G_DBUS_INTERFACE_SKELETON(iface)); | ||
g_dbus_object_manager_server_export(test->server, listener); | ||
g_dbus_object_manager_server_set_connection(test->server, | ||
test->listener_conn); | ||
|
||
g_dbus_connection_start_message_processing(test->listener_conn); | ||
} | ||
|
||
static void | ||
test_dbus_console_registered(GObject *source_object, | ||
GAsyncResult *res, | ||
gpointer user_data) | ||
{ | ||
TestDBusConsoleRegister *test = user_data; | ||
g_autoptr(GError) err = NULL; | ||
|
||
qemu_dbus_display1_console_call_register_listener_finish( | ||
QEMU_DBUS_DISPLAY1_CONSOLE(source_object), | ||
NULL, res, &err); | ||
g_assert_no_error(err); | ||
|
||
test->listener_conn = g_thread_join(test->thread); | ||
test_dbus_console_setup_listener(test); | ||
} | ||
|
||
static gpointer | ||
test_dbus_p2p_server_setup_thread(gpointer data) | ||
{ | ||
return test_dbus_p2p_from_fd(GPOINTER_TO_INT(data)); | ||
} | ||
|
||
static void | ||
test_dbus_display_console(void) | ||
{ | ||
g_autoptr(GError) err = NULL; | ||
g_autoptr(GDBusConnection) conn = NULL; | ||
g_autoptr(QemuDBusDisplay1ConsoleProxy) console = NULL; | ||
g_autoptr(GUnixFDList) fd_list = NULL; | ||
g_autoptr(GMainLoop) loop = NULL; | ||
QTestState *qts = NULL; | ||
int pair[2], idx; | ||
TestDBusConsoleRegister test; | ||
|
||
test_setup(&qts, &conn); | ||
|
||
g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); | ||
fd_list = g_unix_fd_list_new(); | ||
idx = g_unix_fd_list_append(fd_list, pair[1], NULL); | ||
|
||
console = QEMU_DBUS_DISPLAY1_CONSOLE_PROXY( | ||
qemu_dbus_display1_console_proxy_new_sync( | ||
conn, | ||
G_DBUS_PROXY_FLAGS_NONE, | ||
NULL, | ||
"/org/qemu/Display1/Console_0", | ||
NULL, | ||
&err)); | ||
g_assert_no_error(err); | ||
|
||
test.loop = loop = g_main_loop_new(NULL, FALSE); | ||
test.thread = g_thread_new(NULL, test_dbus_p2p_server_setup_thread, | ||
GINT_TO_POINTER(pair[0])); | ||
|
||
qemu_dbus_display1_console_call_register_listener( | ||
QEMU_DBUS_DISPLAY1_CONSOLE(console), | ||
g_variant_new_handle(idx), | ||
G_DBUS_CALL_FLAGS_NONE, | ||
-1, | ||
fd_list, | ||
NULL, | ||
test_dbus_console_registered, | ||
&test); | ||
|
||
g_main_loop_run(loop); | ||
|
||
g_clear_object(&test.server); | ||
g_clear_object(&test.listener_conn); | ||
qtest_quit(qts); | ||
} | ||
|
||
static void | ||
test_dbus_display_keyboard(void) | ||
{ | ||
g_autoptr(GError) err = NULL; | ||
g_autoptr(GDBusConnection) conn = NULL; | ||
g_autoptr(QemuDBusDisplay1KeyboardProxy) keyboard = NULL; | ||
QTestState *qts = NULL; | ||
|
||
test_setup(&qts, &conn); | ||
|
||
keyboard = QEMU_DBUS_DISPLAY1_KEYBOARD_PROXY( | ||
qemu_dbus_display1_keyboard_proxy_new_sync( | ||
conn, | ||
G_DBUS_PROXY_FLAGS_NONE, | ||
NULL, | ||
"/org/qemu/Display1/Console_0", | ||
NULL, | ||
&err)); | ||
g_assert_no_error(err); | ||
|
||
|
||
g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 0); | ||
g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0); | ||
|
||
qemu_dbus_display1_keyboard_call_press_sync( | ||
QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard), | ||
0x1C, /* qnum enter */ | ||
G_DBUS_CALL_FLAGS_NONE, | ||
-1, | ||
NULL, | ||
&err); | ||
g_assert_no_error(err); | ||
|
||
/* may be should wait for interrupt? */ | ||
g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1); | ||
g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */ | ||
|
||
qemu_dbus_display1_keyboard_call_release_sync( | ||
QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard), | ||
0x1C, /* qnum enter */ | ||
G_DBUS_CALL_FLAGS_NONE, | ||
-1, | ||
NULL, | ||
&err); | ||
g_assert_no_error(err); | ||
|
||
g_assert_cmpint(qtest_inb(qts, 0x64) & 0x1, ==, 1); | ||
g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0xF0); /* scan code 2 release */ | ||
g_assert_cmpint(qtest_inb(qts, 0x60), ==, 0x5A); /* scan code 2 enter */ | ||
|
||
g_assert_cmpint(qemu_dbus_display1_keyboard_get_modifiers( | ||
QEMU_DBUS_DISPLAY1_KEYBOARD(keyboard)), ==, 0); | ||
|
||
qtest_quit(qts); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
g_test_init(&argc, &argv, NULL); | ||
|
||
qtest_add_func("/dbus-display/vm", test_dbus_display_vm); | ||
qtest_add_func("/dbus-display/console", test_dbus_display_console); | ||
qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard); | ||
|
||
return g_test_run(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters