[gtk/test-text-buffer-undo: 2/5] Use headless mutter for input tests
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/test-text-buffer-undo: 2/5] Use headless mutter for input tests
- Date: Wed, 26 May 2021 10:08:42 +0000 (UTC)
commit 0e1de8d9d1c1d0b9d6f5372a8b165246f9303e9e
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Mar 21 08:31:25 2021 -0400
Use headless mutter for input tests
Add some input tests that are using headless
mutter, and python with our in-tree gir files.
So far, test that we can roundtrip key events,
and move the pointer around.
tests/headless-input-tests.py | 293 ++++++++++++++++++++++++++++++++++++++
tests/run-headless-input-tests.sh | 27 ++++
2 files changed, 320 insertions(+)
---
diff --git a/tests/headless-input-tests.py b/tests/headless-input-tests.py
new file mode 100644
index 0000000000..807eff41e0
--- /dev/null
+++ b/tests/headless-input-tests.py
@@ -0,0 +1,293 @@
+import sys
+import subprocess
+import gi
+
+gi.require_version('Gdk', '4.0')
+gi.require_version('Gtk', '4.0')
+
+from gi.repository import GLib, Gdk, Gtk
+from pydbus import SessionBus
+
+verbose = False
+
+remote_desktop = None
+screen_cast = None
+session = None
+stream_path = None
+done = False
+
+def terminate():
+ sys.exit(1)
+
+loop = None
+
+def quit_cb(loop):
+ loop.quit()
+
+def wait(millis):
+ global loop
+ loop = GLib.MainLoop()
+ GLib.timeout_add(millis, quit_cb, loop)
+ loop.run()
+
+display = None
+window = None
+expected_change = None
+
+def key_pressed_cb (controller, keyval, keycode, state):
+ global expected_change
+ global loop
+
+ if verbose:
+ print(f'got key press: {keyval}, state {state}')
+ assert expected_change != None, "Unexpected key press"
+ assert expected_change['type'] == 'press', "Key press event expected"
+ assert keyval == expected_change['keyval'], "Unexpected keyval in key press event"
+ assert state == expected_change['state'], "Unexpected state in key press event"
+
+ expected_change = None
+ loop.quit()
+
+def key_released_cb (controller, keyval, keycode, state):
+ global expected_change
+ global loop
+
+ if verbose:
+ print(f'got key release: {keyval}, state {state}')
+ assert expected_change != None, "Unexpected key release"
+ assert expected_change['type'] == 'release', "Key release event expected"
+ assert keyval == expected_change['keyval'], "Unexpected keyval in key release event"
+ assert state == expected_change['state'], "Unexpected state in key release event"
+
+ expected_change = None
+ loop.quit()
+
+def motion_cb (controller, x, y):
+ global expected_change
+ global loop
+
+ if verbose:
+ print(f'got motion: {x}, {y}')
+ assert expected_change != None, "Unexpected motion"
+ assert expected_change['type'] == 'motion', "Motion event expected"
+ assert x == expected_change['x'], "Unexpected x coord in motion event"
+ assert y == expected_change['y'], "Unexpected y coord in motion event"
+
+ expected_change = None
+ loop.quit()
+
+def enter_cb (controller, x, y):
+ global expected_change
+ global loop
+
+ if verbose:
+ print(f'got enter: {x}, {y}')
+ assert expected_change != None, "Unexpected enter"
+ assert expected_change['type'] == 'enter', "Enter event expected"
+ assert x == expected_change['x'], "Unexpected x coord in enter event"
+ assert y == expected_change['y'], "Unexpected y coord in enter event"
+
+ expected_change = None
+ loop.quit()
+
+def expect_key_press(keyval, state, timeout):
+ global expected_change
+ expected_change = {
+ 'type' : 'press',
+ 'keyval' : keyval,
+ 'state' : state
+ }
+ wait(timeout)
+ assert expected_change == None, "Expected event did not happen"
+
+def expect_key_release(keyval, state, timeout):
+ global expected_change
+ expected_change = {
+ 'type' : 'release',
+ 'keyval' : keyval,
+ 'state' : state
+ }
+ wait(timeout)
+ assert expected_change == None, "Expected event did not happen"
+
+def expect_motion(x, y, timeout):
+ global expected_change
+ expected_change = {
+ 'type' : 'motion',
+ 'x' : x,
+ 'y' : y
+ }
+ wait(timeout)
+ assert expected_change == None, "Expected event did not happen"
+
+def expect_enter(x, y, timeout):
+ global expected_change
+ expected_change = {
+ 'type' : 'enter',
+ 'x' : x,
+ 'y' : y
+ }
+ wait(timeout)
+ assert expected_change == None, "Expected event did not happen"
+
+def got_active(object, pspec):
+ global loop
+ loop.quit()
+
+def launch_observer():
+ global display
+ global window
+
+ if verbose:
+ print('launch observer')
+
+ if display == None:
+ Gdk.set_allowed_backends('wayland')
+ display = Gdk.Display.open('gtk-test')
+
+ window = Gtk.Window.new()
+ window.set_display(display)
+
+ controller = Gtk.EventControllerKey.new()
+ controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
+ controller.connect('key-pressed', key_pressed_cb)
+ controller.connect('key-released', key_released_cb)
+ window.add_controller(controller)
+
+ controller = Gtk.EventControllerMotion.new()
+ controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
+ controller.connect('enter', enter_cb)
+ controller.connect('motion', motion_cb)
+ window.add_controller(controller)
+
+ window.connect('notify::is-active', got_active)
+ window.maximize()
+ window.present()
+
+ wait(500)
+
+ assert window.is_active(), "Observer not active"
+ assert window.get_width() == 1024, "Window not maximized"
+ assert window.get_height() == 768, "Window not maximized"
+
+ # we need to wait out the map animation, or pointer coords will be off
+ wait(1000)
+
+def stop_observer():
+ global window
+ window.destroy()
+ window = None
+
+def key_press(keyval):
+ if verbose:
+ print(f'press key {keyval}')
+ session.NotifyKeyboardKeysym(keyval, True)
+
+def key_release(keyval):
+ if verbose:
+ print(f'release key {keyval}')
+ session.NotifyKeyboardKeysym(keyval, False)
+
+def pointer_move(x, y):
+ if verbose:
+ print(f'pointer move {x} {y}')
+ session.NotifyPointerMotionAbsolute(stream_path, x, y)
+
+def basic_keyboard_tests():
+ try:
+ launch_observer()
+
+ key_press(Gdk.KEY_a)
+ expect_key_press(keyval=Gdk.KEY_a, state=0, timeout=100)
+
+ key_release(Gdk.KEY_a)
+ expect_key_release(keyval=Gdk.KEY_a, state=0, timeout=100)
+
+ key_press(Gdk.KEY_Control_L)
+ expect_key_press(keyval=Gdk.KEY_Control_L, state=0, timeout=100)
+
+ key_press(Gdk.KEY_x)
+ expect_key_press(keyval=Gdk.KEY_x, state=Gdk.ModifierType.CONTROL_MASK, timeout=100)
+
+ key_release(Gdk.KEY_Control_L)
+ expect_key_release(keyval=Gdk.KEY_Control_L, state=Gdk.ModifierType.CONTROL_MASK, timeout=100)
+
+ key_release(Gdk.KEY_x)
+ expect_key_release(keyval=Gdk.KEY_x, state=0, timeout=100)
+
+ stop_observer()
+ except AssertionError as e:
+ print("Error in basic_keyboard_tests: {0}".format(e))
+ terminate()
+
+def basic_pointer_tests():
+ try:
+ pointer_move(-100.0, -100.0)
+ launch_observer()
+
+ # observer window is maximized, so window coords == global coords
+ pointer_move(500.0, 300.0)
+ expect_enter(x=500, y=300, timeout=200)
+
+ pointer_move(200.0, 200.0)
+ expect_motion(x=200, y=200, timeout=200)
+
+ stop_observer()
+ except AssertionError as e:
+ print("Error in basic_pointer_tests: {0}".format(e))
+ terminate()
+
+def session_closed_cb():
+ print('Session closed')
+
+def mutter_appeared(name):
+ global remote_desktop
+ global session
+ global stream_path
+ global done
+
+ if verbose:
+ print("mutter appeared on the bus")
+
+ remote_desktop = bus.get('org.gnome.Mutter.RemoteDesktop',
+ '/org/gnome/Mutter/RemoteDesktop')
+ device_types = remote_desktop.Get('org.gnome.Mutter.RemoteDesktop', 'SupportedDeviceTypes')
+ assert device_types & 1 == 1, "No keyboard"
+ assert device_types & 2 == 2, "No pointer"
+
+ screen_cast = bus.get('org.gnome.Mutter.ScreenCast',
+ '/org/gnome/Mutter/ScreenCast')
+
+ session_path = remote_desktop.CreateSession()
+ session = bus.get('org.gnome.Mutter.RemoteDesktop', session_path)
+ session.onClosed = session_closed_cb
+
+ screen_cast_session_path = screen_cast.CreateSession({ 'remote-desktop-session-id' : GLib.Variant('s',
session.SessionId)})
+ screen_cast_session = bus.get('org.gnome.Mutter.ScreenCast', screen_cast_session_path)
+
+ stream_path = screen_cast_session.RecordMonitor('Meta-0', {})
+
+ session.Start()
+
+ basic_keyboard_tests()
+ basic_pointer_tests()
+
+ session.Stop()
+
+ done = True
+
+def mutter_vanished():
+ global done
+ if remote_desktop != None:
+ if verbose:
+ print("mutter left the bus")
+ done = True
+
+bus = SessionBus()
+bus.watch_name('org.gnome.Mutter.RemoteDesktop', 0, mutter_appeared, mutter_vanished)
+
+try:
+ while not done:
+ GLib.MainContext.default().iteration(True)
+except KeyboardInterrupt:
+ print('Interrupted')
diff --git a/tests/run-headless-input-tests.sh b/tests/run-headless-input-tests.sh
new file mode 100755
index 0000000000..87b206de34
--- /dev/null
+++ b/tests/run-headless-input-tests.sh
@@ -0,0 +1,27 @@
+#! /bin/sh
+
+builddir=$(pwd)/build
+
+dbus-run-session sh <<EOF
+
+# echo DBUS_SESSION_BUS_ADDRESS=\$DBUS_SESSION_BUS_ADDRESS
+# echo WAYLAND_DISPLAY=gtk-test
+
+mutter --headless --virtual-monitor 1024x768 --no-x11 --wayland-display gtk-test >&mutter.log &
+pid=\$!
+
+export WAYLAND_DISPLAY=gtk-test
+export GDK_BACKEND=wayland
+#export WAYLAND_DEBUG=1
+
+export GI_TYPELIB_PATH=$builddir/gtk:/usr/lib64/girepository-1.0
+export LD_PRELOAD=$builddir/gtk/libgtk-4.so
+
+python tests/headless-input-tests.py
+status=\$?
+
+kill \$pid
+
+exit \$status
+
+EOF
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]