[mutter] tests: Extract D-Bus runner as reusable python module
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] tests: Extract D-Bus runner as reusable python module
- Date: Fri, 2 Sep 2022 17:51:59 +0000 (UTC)
commit b1cc591ef5b7f9351f0f0346e2844c37868caea8
Author: Jonas Ã…dahl <jadahl gmail com>
Date: Tue Aug 16 15:50:33 2022 +0200
tests: Extract D-Bus runner as reusable python module
The D-Bus runner used by tests, including installed tests, is made to be
reusable from GNOME Shell. To do this, install it and the templates in
the pkgdatadir (e.g. /usr/share/mutter-APIVERSION/tests/), generate a
custom runner for the installed tests that uses the installed script and
templates, and change the non-installed original runner to use the
non-installed templates.
The end goal is to reuse the D-Bus session runner and templates used for
mutter when test running GNOME Shell.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1354>
src/tests/meson.build | 20 ++-
src/tests/meta-dbus-runner.py | 189 +----------------------
src/tests/mutter-all.test.in | 2 +-
src/tests/mutter-installed-dbus-session.py.in | 11 ++
src/tests/mutter_dbusrunner.py | 208 ++++++++++++++++++++++++++
5 files changed, 238 insertions(+), 192 deletions(-)
---
diff --git a/src/tests/meson.build b/src/tests/meson.build
index 1787a9c194..74de095245 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -68,6 +68,7 @@ pkg.generate(libmutter_test,
version: meson.project_version(),
variables: [
'apiversion=' + libmutter_api_version,
+ 'tests_datadir=${prefix}/share/mutter-' + libmutter_api_version + '/tests',
],
install_dir: pcdir,
)
@@ -148,11 +149,22 @@ test_runner = executable('mutter-test-runner',
meta_dbus_runner = find_program('meta-dbus-runner.py')
+tests_datadir = join_paths(pkgdatadir, 'tests')
+
+install_data('mutter_dbusrunner.py',
+ install_dir: tests_datadir,
+)
+install_subdir('dbusmock-templates',
+ install_dir: tests_datadir,
+)
+
if have_installed_tests
- install_data('meta-dbus-runner.py',
- install_dir: mutter_installed_tests_libexecdir,
- )
- install_subdir('dbusmock-templates',
+ configure_file(
+ input: 'mutter-installed-dbus-session.py.in',
+ output: 'mutter-installed-dbus-session.py',
+ configuration: {'tests_datadir': tests_datadir},
+ install: true,
+ install_mode: 'rwxr-xr-x',
install_dir: mutter_installed_tests_libexecdir,
)
endif
diff --git a/src/tests/meta-dbus-runner.py b/src/tests/meta-dbus-runner.py
index 9c4ce00a63..a2cebea76b 100755
--- a/src/tests/meta-dbus-runner.py
+++ b/src/tests/meta-dbus-runner.py
@@ -1,194 +1,9 @@
#!/usr/bin/env python3
-import dbus
import sys
-import os
-import fcntl
-import subprocess
-import getpass
-import argparse
-from collections import OrderedDict
-from dbusmock import DBusTestCase
-from dbus.mainloop.glib import DBusGMainLoop
-
-DBusGMainLoop(set_as_default=True)
-
-
-def get_templates_dir():
- return os.path.join(os.path.dirname(__file__), 'dbusmock-templates')
-
-def get_template_path(template_name):
- return os.path.join(get_templates_dir(), template_name + '.py')
-
-def get_subprocess_stdout():
- if os.getenv('META_DBUS_RUNNER_VERBOSE') == '1':
- return sys.stderr
- else:
- return subprocess.DEVNULL;
-
-
-class MutterDBusTestCase(DBusTestCase):
- @classmethod
- def setUpClass(klass, enable_kvm):
- klass.mocks = OrderedDict()
-
- print('Starting D-Bus daemons (session & system)...', file=sys.stderr)
- DBusTestCase.setUpClass()
- klass.start_session_bus()
- klass.start_system_bus()
-
- print('Starting mocked services...', file=sys.stderr)
- (klass.mocks_manager, klass.mock_obj) = klass.start_from_local_template(
- 'meta-mocks-manager', {'templates-dir': get_templates_dir()})
-
- klass.start_from_local_template('localed')
- klass.start_from_local_template('colord')
- klass.start_from_local_template('gsd-color')
-
- klass.system_bus_con = klass.get_dbus(system_bus=True)
- klass.session_bus_con = klass.get_dbus(system_bus=False)
-
- klass.init_logind(enable_kvm)
-
- if klass.session_bus_con.name_has_owner('org.gnome.Mutter.DisplayConfig'):
- raise Exception(
- 'org.gnome.Mutter.DisplayConfig already has owner on the session bus, bailing')
-
- @classmethod
- def tearDownClass(klass):
- klass.mock_obj.Cleanup()
-
- for (mock_server, mock_obj) in reversed(klass.mocks.values()):
- mock_server.terminate()
- mock_server.wait()
-
- DBusTestCase.tearDownClass()
-
- @classmethod
- def start_from_template(klass, template, params={}):
- mock_server, mock_obj = \
- klass.spawn_server_template(template,
- params,
- get_subprocess_stdout())
-
- mocks = (mock_server, mock_obj)
- assert klass.mocks.setdefault(template, mocks) == mocks
- return mocks
-
- @classmethod
- def start_from_local_template(klass, template_file_name, params={}):
- template = get_template_path(template_file_name)
- return klass.start_from_template(template, params)
-
- @classmethod
- def start_from_template_managed(klass, template):
- klass.mock_obj.StartFromTemplate(template)
-
- @classmethod
- def start_from_local_template_managed(klass, template_file_name):
- template = get_template_path(template_file_name)
- klass.mock_obj.StartFromLocalTemplate(template)
-
- @classmethod
- def start_from_class(klass, mock_class, params={}):
- mock_server = \
- klass.spawn_server(mock_class.BUS_NAME,
- mock_class.MAIN_OBJ,
- mock_class.MAIN_IFACE,
- mock_class.SYSTEM_BUS,
- stdout=get_subprocess_stdout())
-
- bus = klass.get_dbus(system_bus=mock_class.SYSTEM_BUS)
- mock_obj = bus.get_object(mock_class.BUS_NAME, mock_class.MAIN_OBJ)
- mock_class.load(mock_obj, params)
-
- mocks = (mock_server, mock_obj)
- assert klass.mocks.setdefault(mock_class, mocks) == mocks
- return mocks
-
- @classmethod
- def init_logind_kvm(klass, session_path):
- session_obj = klass.system_bus_con.get_object('org.freedesktop.login1', session_path)
- session_obj.AddMethod('org.freedesktop.login1.Session',
- 'TakeDevice',
- 'uu', 'hb',
-'''
-import re
-
-major = args[0]
-minor = args[1]
-
-sysfs_uevent_path = '/sys/dev/char/{}:{}/uevent'.format(major, minor)
-sysfs_uevent = open(sysfs_uevent_path, 'r')
-devname = None
-for line in sysfs_uevent.readlines():
- match = re.match('DEVNAME=(.*)', line)
- if match:
- devname = match[1]
- break
-sysfs_uevent.close()
-if not devname:
- raise dbus.exceptions.DBusException(f'Device file {major}:{minor} doesn\\\'t exist',
- major=major, minor=minor)
-fd = os.open('/dev/' + devname, os.O_RDWR | os.O_CLOEXEC)
-unix_fd = dbus.types.UnixFd(fd)
-os.close(fd)
-ret = (unix_fd, False)
-''')
- session_obj.AddMethods('org.freedesktop.login1.Session', [
- ('ReleaseDevice', 'uu', '', ''),
- ('TakeControl', 'b', '', ''),
- ])
-
- @classmethod
- def init_logind(klass, enable_kvm):
- logind = klass.start_from_template('logind')
-
- [p_mock, obj] = logind
-
- mock_iface = 'org.freedesktop.DBus.Mock'
- obj.AddSeat('seat0', dbus_interface=mock_iface)
- session_path = obj.AddSession('dummy', 'seat0',
- dbus.types.UInt32(os.getuid()),
- getpass.getuser(),
- True,
- dbus_interface=mock_iface)
-
- if enable_kvm:
- klass.init_logind_kvm(session_path)
-
- def wrap_call(self, args):
- env = {}
- env.update(os.environ)
- env['NO_AT_BRIDGE'] = '1'
- env['GSETTINGS_BACKEND'] = 'memory'
-
- wrapper = env.get('META_DBUS_RUNNER_WRAPPER')
- if wrapper == 'gdb':
- args = ['gdb', '-ex', 'r', '-ex', 'bt full', '--args'] + args
- elif wrapper:
- args = wrapper.split(' ') + args
-
- p = subprocess.Popen(args, env=env)
- return p.wait()
+from mutter_dbusrunner import MutterDBusRunner, meta_run
if __name__ == '__main__':
- parser = argparse.ArgumentParser()
- parser.add_argument('--kvm', action='store_true', default=False)
- (args, rest) = parser.parse_known_args(sys.argv)
-
- rest.pop(0)
- if rest[0] == '--':
- rest.pop(0)
-
- MutterDBusTestCase.setUpClass(args.kvm)
- test_case = MutterDBusTestCase()
- test_case.assertGreater(len(rest), 0)
- result = 1
- try:
- print('Running test case...', file=sys.stderr)
- result = test_case.wrap_call(rest)
- finally:
- MutterDBusTestCase.tearDownClass()
+ result = meta_run(MutterDBusRunner)
sys.exit(result)
diff --git a/src/tests/mutter-all.test.in b/src/tests/mutter-all.test.in
index f99dc29da3..12536c11bf 100644
--- a/src/tests/mutter-all.test.in
+++ b/src/tests/mutter-all.test.in
@@ -4,6 +4,6 @@ Description=All Mutter tests
# a solution for
# https://gitlab.gnome.org/GNOME/gnome-desktop-testing/-/issues/1,
# and anyway that wouldn't be sufficient to handle XDG_RUNTIME_DIR
-Exec=sh -ec 'env GSETTINGS_BACKEND=memory XDG_RUNTIME_DIR="$(mktemp -d -t
mutter-@apiversion@-all-tests-XXXXXX)" @libexecdir@/installed-tests/mutter-@apiversion@/meta-dbus-runner.py
xvfb-run -a -s "+iglx -noreset" -- @libexecdir@/installed-tests/mutter-@apiversion@/mutter-test-runner --all'
+Exec=sh -ec 'env GSETTINGS_BACKEND=memory XDG_RUNTIME_DIR="$(mktemp -d -t
mutter-@apiversion@-all-tests-XXXXXX)"
@libexecdir@/installed-tests/mutter-@apiversion@/mutter-installed-dbus-session.py xvfb-run -a -s "+iglx
-noreset" -- @libexecdir@/installed-tests/mutter-@apiversion@/mutter-test-runner --all'
Type=session
Output=TAP
diff --git a/src/tests/mutter-installed-dbus-session.py.in b/src/tests/mutter-installed-dbus-session.py.in
new file mode 100755
index 0000000000..fe6bbb5248
--- /dev/null
+++ b/src/tests/mutter-installed-dbus-session.py.in
@@ -0,0 +1,11 @@
+#!/usr/bin/env python3
+
+import sys
+
+sys.path.insert(1, '@tests_datadir@')
+
+from mutter_dbusrunner import MutterDBusRunner, meta_run
+
+if __name__ == '__main__':
+ result = meta_run(MutterDBusRunner)
+ sys.exit(result)
diff --git a/src/tests/mutter_dbusrunner.py b/src/tests/mutter_dbusrunner.py
new file mode 100644
index 0000000000..5f21bd2c5d
--- /dev/null
+++ b/src/tests/mutter_dbusrunner.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python3
+
+import dbus
+import sys
+import os
+import fcntl
+import subprocess
+import getpass
+import argparse
+from collections import OrderedDict
+from dbusmock import DBusTestCase
+from dbus.mainloop.glib import DBusGMainLoop
+from pathlib import Path
+
+
+def get_subprocess_stdout():
+ if os.getenv('META_DBUS_RUNNER_VERBOSE') == '1':
+ return sys.stderr
+ else:
+ return subprocess.DEVNULL;
+
+
+class MutterDBusRunner(DBusTestCase):
+ @classmethod
+ def __get_templates_dir(klass):
+ return os.path.join(os.path.dirname(__file__), 'dbusmock-templates')
+
+ @classmethod
+ def setUpClass(klass, enable_kvm):
+ klass.templates_dirs = [klass.__get_templates_dir()]
+
+ klass.mocks = OrderedDict()
+
+ print('Starting D-Bus daemons (session & system)...', file=sys.stderr)
+ DBusTestCase.setUpClass()
+ klass.start_session_bus()
+ klass.start_system_bus()
+
+ print('Starting mocked services...', file=sys.stderr)
+ (klass.mocks_manager, klass.mock_obj) = klass.start_from_local_template(
+ 'meta-mocks-manager', {'templates-dir': klass.__get_templates_dir()})
+
+ klass.start_from_local_template('localed')
+ klass.start_from_local_template('colord')
+ klass.start_from_local_template('gsd-color')
+
+ klass.system_bus_con = klass.get_dbus(system_bus=True)
+ klass.session_bus_con = klass.get_dbus(system_bus=False)
+
+ klass.init_logind(enable_kvm)
+
+ if klass.session_bus_con.name_has_owner('org.gnome.Mutter.DisplayConfig'):
+ raise Exception(
+ 'org.gnome.Mutter.DisplayConfig already has owner on the session bus, bailing')
+
+ @classmethod
+ def tearDownClass(klass):
+ klass.mock_obj.Cleanup()
+
+ for (mock_server, mock_obj) in reversed(klass.mocks.values()):
+ mock_server.terminate()
+ mock_server.wait()
+
+ DBusTestCase.tearDownClass()
+
+ @classmethod
+ def start_from_template(klass, template, params={}, system_bus=None):
+ mock_server, mock_obj = \
+ klass.spawn_server_template(template,
+ params,
+ get_subprocess_stdout(),
+ system_bus=system_bus)
+
+ mocks = (mock_server, mock_obj)
+ return mocks
+
+ @classmethod
+ def start_from_local_template(klass, template_file_name, params={}, system_bus=None):
+ template = klass.find_template(template_file_name)
+ return klass.start_from_template(template, params, system_bus=system_bus)
+
+ @classmethod
+ def start_from_template_managed(klass, template):
+ klass.mock_obj.StartFromTemplate(template)
+
+ @classmethod
+ def start_from_local_template_managed(klass, template_file_name):
+ template = klass.find_template(template_file_name)
+ klass.mock_obj.StartFromLocalTemplate(template)
+
+ @classmethod
+ def start_from_class(klass, mock_class, params={}):
+ mock_server = \
+ klass.spawn_server(mock_class.BUS_NAME,
+ mock_class.MAIN_OBJ,
+ mock_class.MAIN_IFACE,
+ mock_class.SYSTEM_BUS,
+ stdout=get_subprocess_stdout())
+
+ bus = klass.get_dbus(system_bus=mock_class.SYSTEM_BUS)
+ mock_obj = bus.get_object(mock_class.BUS_NAME, mock_class.MAIN_OBJ)
+ mock_class.load(mock_obj, params)
+
+ mocks = (mock_server, mock_obj)
+ return mocks
+
+ @classmethod
+ def init_logind_kvm(klass, session_path):
+ session_obj = klass.system_bus_con.get_object('org.freedesktop.login1', session_path)
+ session_obj.AddMethod('org.freedesktop.login1.Session',
+ 'TakeDevice',
+ 'uu', 'hb',
+'''
+import re
+
+major = args[0]
+minor = args[1]
+
+sysfs_uevent_path = '/sys/dev/char/{}:{}/uevent'.format(major, minor)
+sysfs_uevent = open(sysfs_uevent_path, 'r')
+devname = None
+for line in sysfs_uevent.readlines():
+ match = re.match('DEVNAME=(.*)', line)
+ if match:
+ devname = match[1]
+ break
+sysfs_uevent.close()
+if not devname:
+ raise dbus.exceptions.DBusException(f'Device file {major}:{minor} doesn\\\'t exist',
+ major=major, minor=minor)
+fd = os.open('/dev/' + devname, os.O_RDWR | os.O_CLOEXEC)
+unix_fd = dbus.types.UnixFd(fd)
+os.close(fd)
+ret = (unix_fd, False)
+''')
+ session_obj.AddMethods('org.freedesktop.login1.Session', [
+ ('ReleaseDevice', 'uu', '', ''),
+ ('TakeControl', 'b', '', ''),
+ ])
+
+ @classmethod
+ def init_logind(klass, enable_kvm):
+ logind = klass.start_from_template('logind')
+
+ [p_mock, obj] = logind
+
+ mock_iface = 'org.freedesktop.DBus.Mock'
+ obj.AddSeat('seat0', dbus_interface=mock_iface)
+ session_path = obj.AddSession('dummy', 'seat0',
+ dbus.types.UInt32(os.getuid()),
+ getpass.getuser(),
+ True,
+ dbus_interface=mock_iface)
+
+ if enable_kvm:
+ klass.init_logind_kvm(session_path)
+
+ @classmethod
+ def add_template_dir(klass, templates_dir):
+ klass.templates_dirs += [templates_dir]
+
+ @classmethod
+ def find_template(klass, template_name):
+ for templates_dir in klass.templates_dirs:
+ template_path = os.path.join(templates_dir, template_name + '.py')
+ template_file = Path(template_path)
+ if template_file.is_file():
+ return template_path
+ raise FileNotFoundError(f'Couldnt find a {template_name} template')
+
+ def wrap_call(self, args):
+ env = {}
+ env.update(os.environ)
+ env['NO_AT_BRIDGE'] = '1'
+ env['GSETTINGS_BACKEND'] = 'memory'
+
+ wrapper = env.get('META_DBUS_RUNNER_WRAPPER')
+ if wrapper == 'gdb':
+ args = ['gdb', '-ex', 'r', '-ex', 'bt full', '--args'] + args
+ elif wrapper:
+ args = wrapper.split(' ') + args
+
+ p = subprocess.Popen(args, env=env)
+ return p.wait()
+
+
+def meta_run(klass):
+ DBusGMainLoop(set_as_default=True)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--kvm', action='store_true', default=False)
+ (args, rest) = parser.parse_known_args(sys.argv)
+
+ rest.pop(0)
+ if rest[0] == '--':
+ rest.pop(0)
+
+ klass.setUpClass(args.kvm)
+ runner = klass()
+ runner.assertGreater(len(rest), 0)
+ result = 1
+
+ try:
+ print('Running test case...', file=sys.stderr)
+ result = runner.wrap_call(rest)
+ finally:
+ MutterDBusRunner.tearDownClass()
+ return result
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]