tests: Add MetaOrientationManager tests via SensorsProxy mock
Create a test system bus and use it to run all the tests, add a mock SensorsProxy (via dbusmock template) server that implements the net.hadess.SensorProxy interface. To make testing easier, the service is created on request of a proxy for it, whose lifetime controls the mock service lifetime as well. This is done using a further mock service that is used to manage the others, using python-dbusmock to simplify the handling. Add basic tests for the orientation manager. As per the usage dbusmock, we're now launching all the tests under such wrapper, so that local dbus environment won't ever considered, and there's no risk that it may affect the tests results both locally and in CI. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1233>
This commit is contained in:
parent
58fb865a7c
commit
bf54a16f92
14 changed files with 912 additions and 3 deletions
|
@ -16,8 +16,16 @@ variables:
|
|||
.mutter.fedora:34@common:
|
||||
variables:
|
||||
FDO_DISTRIBUTION_VERSION: 34
|
||||
BASE_TAG: '2021-08-25.0'
|
||||
FDO_DISTRIBUTION_PACKAGES: 'gdm gnome-shell xorg-x11-server-Xvfb sassc gcovr clang uncrustify'
|
||||
BASE_TAG: '2021-09-04.0'
|
||||
FDO_DISTRIBUTION_PACKAGES:
|
||||
clang
|
||||
gcovr
|
||||
gdm
|
||||
gnome-shell
|
||||
python3-dbusmock
|
||||
sassc
|
||||
uncrustify
|
||||
xorg-x11-server-Xvfb
|
||||
|
||||
FDO_DISTRIBUTION_EXEC: |
|
||||
dnf install -y 'dnf-command(builddep)' &&
|
||||
|
|
11
meson.build
11
meson.build
|
@ -295,11 +295,22 @@ if have_tests
|
|||
have_clutter_tests = get_option('clutter_tests')
|
||||
have_installed_tests = get_option('installed_tests')
|
||||
|
||||
meta_dbus_runner = find_program('src/tests/meta-dbus-runner.py')
|
||||
default_test_wrappers = [
|
||||
meta_dbus_runner,
|
||||
]
|
||||
|
||||
add_test_setup('default',
|
||||
is_default: true,
|
||||
exe_wrapper: default_test_wrappers,
|
||||
)
|
||||
|
||||
add_test_setup('CI',
|
||||
env: [
|
||||
'MUTTER_DEBUG_DUMMY_MODE_SPECS=800x600@10.0',
|
||||
],
|
||||
exe_wrapper: [
|
||||
default_test_wrappers,
|
||||
find_program('catchsegv'),
|
||||
find_program('xvfb-run'), '-a', '-s', '+iglx -noreset',
|
||||
],
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "core/util-private.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_ORIENTATION_UNDEFINED,
|
||||
|
@ -35,11 +37,15 @@ typedef enum
|
|||
#define META_N_ORIENTATIONS (META_ORIENTATION_RIGHT_UP + 1)
|
||||
|
||||
#define META_TYPE_ORIENTATION_MANAGER (meta_orientation_manager_get_type ())
|
||||
|
||||
META_EXPORT_TEST
|
||||
G_DECLARE_FINAL_TYPE (MetaOrientationManager, meta_orientation_manager,
|
||||
META, ORIENTATION_MANAGER, GObject)
|
||||
|
||||
META_EXPORT_TEST
|
||||
MetaOrientation meta_orientation_manager_get_orientation (MetaOrientationManager *self);
|
||||
|
||||
META_EXPORT_TEST
|
||||
gboolean meta_orientation_manager_has_accelerometer (MetaOrientationManager *self);
|
||||
|
||||
#endif /* META_ORIENTATION_MANAGER_H */
|
||||
|
|
204
src/tests/dbusmock-templates/iio-sensors-proxy.py
Normal file
204
src/tests/dbusmock-templates/iio-sensors-proxy.py
Normal file
|
@ -0,0 +1,204 @@
|
|||
'''sensors proxy mock template
|
||||
'''
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License, or (at your option) any
|
||||
# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
|
||||
# of the license.
|
||||
|
||||
__author__ = 'Marco Trevisan'
|
||||
__copyright__ = '(c) 2021 Canonical Ltd.'
|
||||
|
||||
import re
|
||||
|
||||
import dbus
|
||||
from dbusmock import MOCK_IFACE
|
||||
|
||||
BUS_NAME = 'net.hadess.SensorProxy'
|
||||
MAIN_OBJ = '/net/hadess/SensorProxy'
|
||||
MAIN_IFACE = 'net.hadess.SensorProxy'
|
||||
COMPASS_IFACE = 'net.hadess.SensorProxy.Compass'
|
||||
SYSTEM_BUS = True
|
||||
|
||||
CAMEL_TO_SNAKE_CASE_RE = re.compile(r'(?<!^)(?=[A-Z])')
|
||||
|
||||
|
||||
def load(mock, parameters=None):
|
||||
mock.has_accelerometer = False
|
||||
mock.accelerometer_owners = dict()
|
||||
mock.accelerometer_orientation = 'undefined'
|
||||
mock.has_ambient_light = False
|
||||
mock.ambient_light_owners = dict()
|
||||
mock.light_level_unit = 'lux'
|
||||
mock.light_level = 0.0
|
||||
mock.has_proximity = False
|
||||
mock.proximity_near = False
|
||||
mock.proximity_owners = dict()
|
||||
mock.has_compass = False
|
||||
mock.compass_owners = dict()
|
||||
mock.compass_heading = -1.0
|
||||
|
||||
if parameters:
|
||||
for p, v in parameters.items():
|
||||
setattr(mock, p, v)
|
||||
|
||||
for iface in [MAIN_IFACE, COMPASS_IFACE]:
|
||||
mock.AddProperties(iface, mock.GetAll(iface))
|
||||
|
||||
|
||||
def emit_signal_to_destination(mock, interface, name, signature, destination, *args):
|
||||
# We need to do this manually, could be made easier via
|
||||
# https://gitlab.freedesktop.org/dbus/dbus-python/-/merge_requests/13
|
||||
message = dbus.lowlevel.SignalMessage(mock.path, interface, name)
|
||||
if destination:
|
||||
message.set_destination(destination)
|
||||
message.append(signature=signature, *args)
|
||||
for location in mock.locations:
|
||||
location[0].send_message(message)
|
||||
|
||||
|
||||
def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None,
|
||||
destination=None):
|
||||
if properties is None:
|
||||
properties = mock.GetAll(interface)
|
||||
elif isinstance(properties, str):
|
||||
properties = [properties]
|
||||
|
||||
if isinstance(properties, (list, set)):
|
||||
properties = {p: mock.Get(interface, p) for p in properties}
|
||||
elif not isinstance(properties, dict):
|
||||
raise TypeError('Unsupported properties type')
|
||||
|
||||
emit_signal_to_destination(mock, dbus.PROPERTIES_IFACE, 'PropertiesChanged',
|
||||
'sa{sv}as', destination, interface, properties, [])
|
||||
|
||||
|
||||
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
|
||||
out_signature='a{sv}')
|
||||
def GetAll(self, interface):
|
||||
if interface == MAIN_IFACE:
|
||||
return {
|
||||
'HasAccelerometer': dbus.Boolean(self.has_accelerometer),
|
||||
'AccelerometerOrientation': dbus.String(self.accelerometer_orientation),
|
||||
'HasAmbientLight': dbus.Boolean(self.has_ambient_light),
|
||||
'LightLevelUnit': dbus.String(self.light_level_unit),
|
||||
'LightLevel': dbus.Double(self.light_level),
|
||||
'HasProximity': dbus.Boolean(self.has_proximity),
|
||||
'ProximityNear': dbus.Boolean(self.proximity_near),
|
||||
}
|
||||
if interface == COMPASS_IFACE:
|
||||
return {
|
||||
'HasCompass': dbus.Boolean(self.has_compass),
|
||||
'CompassHeading': dbus.Double(self.compass_heading),
|
||||
}
|
||||
return dbus.Dictionary({}, signature='sv')
|
||||
|
||||
|
||||
def register_owner(self, owners_dict, name):
|
||||
if name in owners_dict:
|
||||
return
|
||||
|
||||
def name_cb(unique_name):
|
||||
if unique_name:
|
||||
return
|
||||
owners_dict.pop(name).cancel()
|
||||
|
||||
owners_dict[name] = self.connection.watch_name_owner(name, name_cb)
|
||||
|
||||
|
||||
def unregister_owner(owners_dict, name):
|
||||
watcher = owners_dict.pop(name, None)
|
||||
if watcher:
|
||||
watcher.cancel()
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ClaimAccelerometer(self, sender):
|
||||
register_owner(self, self.accelerometer_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ReleaseAccelerometer(self, sender):
|
||||
unregister_owner(self.accelerometer_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ClaimLight(self, sender):
|
||||
register_owner(self, self.ambient_light_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ReleaseLight(self, sender):
|
||||
unregister_owner(self.ambient_light_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ClaimProximity(self, sender):
|
||||
register_owner(self, self.proximity_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ReleaseProximity(self, sender):
|
||||
unregister_owner(self.proximity_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ClaimCompass(self, sender):
|
||||
register_owner(self, self.compass_owners, sender)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, sender_keyword='sender')
|
||||
def ReleaseCompass(self, sender):
|
||||
unregister_owner(self.compass_owners, sender)
|
||||
|
||||
|
||||
def sensor_to_attribute(sensor):
|
||||
if sensor == 'light':
|
||||
return 'ambient_light'
|
||||
return sensor
|
||||
|
||||
|
||||
def is_valid_sensor_for_interface(sensor, interface):
|
||||
if interface == 'net.hadess.SensorProxy':
|
||||
return sensor in ['accelerometer', 'ambient_light', 'proximity']
|
||||
|
||||
if interface == 'net.hadess.SensorProxy.Compass':
|
||||
return sensor == 'compass'
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@dbus.service.method(MOCK_IFACE, in_signature='ssv')
|
||||
def SetInternalProperty(self, interface, property_name, value):
|
||||
property_attribute = CAMEL_TO_SNAKE_CASE_RE.sub('_', property_name).lower()
|
||||
sensor = sensor_to_attribute(property_attribute.split('_')[0])
|
||||
|
||||
owners = None
|
||||
if is_valid_sensor_for_interface(sensor, interface):
|
||||
|
||||
if not getattr(self, 'has_{}'.format(sensor)):
|
||||
raise Exception('No {} sensor available'.format(sensor))
|
||||
|
||||
owners = getattr(self, '{}_owners'.format(sensor))
|
||||
# We allow setting a property from any client here, even if not claiming
|
||||
# but only owners, if any, will be notified about sensors changes
|
||||
|
||||
pre_value = getattr(self, property_attribute)
|
||||
if pre_value != value:
|
||||
setattr(self, property_attribute, value)
|
||||
if owners:
|
||||
for owner in owners.keys():
|
||||
emit_properties_changed(self, interface, property_name, owner)
|
||||
elif owners is None:
|
||||
emit_properties_changed(self, interface, property_name, None)
|
||||
|
||||
|
||||
@dbus.service.method(MOCK_IFACE, in_signature='s')
|
||||
def GetInternalProperty(self, property_name):
|
||||
property_attribute = CAMEL_TO_SNAKE_CASE_RE.sub('_', property_name).lower()
|
||||
value = getattr(self, property_attribute)
|
||||
|
||||
if property_name.endswith('Owners'):
|
||||
return dbus.Array(value.keys(), signature='s')
|
||||
return value
|
83
src/tests/dbusmock-templates/meta-mocks-manager.py
Normal file
83
src/tests/dbusmock-templates/meta-mocks-manager.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License, or (at your option) any
|
||||
# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
|
||||
# of the license.
|
||||
|
||||
__author__ = 'Marco Trevisan'
|
||||
__copyright__ = '(c) 2021 Canonical Ltd.'
|
||||
|
||||
import dbus
|
||||
import fcntl
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from collections import OrderedDict
|
||||
from dbusmock import DBusTestCase
|
||||
|
||||
BUS_NAME = 'org.gnome.Mutter.TestDBusMocksManager'
|
||||
MAIN_OBJ = '/org/gnome/Mutter/TestDBusMocksManager'
|
||||
MAIN_IFACE = 'org.gnome.Mutter.TestDBusMocksManager'
|
||||
SYSTEM_BUS = True
|
||||
|
||||
|
||||
def load(mock, parameters):
|
||||
mock.mocks = OrderedDict()
|
||||
DBusTestCase.setUpClass()
|
||||
mock.dbus_mock = DBusTestCase()
|
||||
mock.dbus_mock.setUp()
|
||||
mock.templates_dir = parameters['templates-dir']
|
||||
|
||||
|
||||
def set_nonblock(fd):
|
||||
'''Set a file object to non-blocking'''
|
||||
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, in_signature='s')
|
||||
def StartFromTemplate(self, template):
|
||||
if template in self.mocks.keys():
|
||||
raise KeyError('Template {} already started'.format(template))
|
||||
|
||||
mock_server, mock_obj = self.dbus_mock.spawn_server_template(template, {},
|
||||
stdout=subprocess.PIPE)
|
||||
set_nonblock(mock_server.stdout)
|
||||
|
||||
self.mocks[template] = (mock_server, mock_obj)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, in_signature='s')
|
||||
def StartFromLocalTemplate(self, template):
|
||||
path = os.path.join(self.templates_dir, template + '.py')
|
||||
return self.StartFromTemplate(path)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, in_signature='s')
|
||||
def StopTemplate(self, template):
|
||||
(mock_server, mock_obj) = self.mocks.pop(template)
|
||||
mock_server.terminate()
|
||||
mock_server.wait()
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, in_signature='s')
|
||||
def StopLocalTemplate(self, template):
|
||||
path = os.path.join(self.templates_dir, template + '.py')
|
||||
return self.StopTemplate(path)
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE)
|
||||
def Cleanup(self):
|
||||
for (mock_server, mock_obj) in reversed(self.mocks.values()):
|
||||
mock_server.terminate()
|
||||
mock_server.wait()
|
||||
|
||||
self.dbus_mock.tearDown()
|
||||
DBusTestCase.tearDownClass()
|
||||
|
||||
|
||||
@dbus.service.method(MAIN_IFACE, out_signature='as')
|
||||
def ListRunningTemplates(self):
|
||||
return list(self.mocks.keys())
|
||||
|
|
@ -6,6 +6,8 @@ mutter_test_sources = [
|
|||
'meta-gpu-test.h',
|
||||
'meta-monitor-manager-test.c',
|
||||
'meta-monitor-manager-test.h',
|
||||
'meta-sensors-proxy-mock.c',
|
||||
'meta-sensors-proxy-mock.h',
|
||||
'monitor-test-utils.c',
|
||||
'monitor-test-utils.h',
|
||||
'meta-test-utils.c',
|
||||
|
@ -115,6 +117,15 @@ test_runner = executable('mutter-test-runner',
|
|||
install_dir: mutter_installed_tests_libexecdir,
|
||||
)
|
||||
|
||||
if have_installed_tests
|
||||
install_data('meta-dbus-runner.py',
|
||||
install_dir: mutter_installed_tests_libexecdir,
|
||||
)
|
||||
install_subdir('dbusmock-templates',
|
||||
install_dir: mutter_installed_tests_libexecdir,
|
||||
)
|
||||
endif
|
||||
|
||||
unit_tests = executable('mutter-test-unit-tests',
|
||||
sources: [
|
||||
'unit-tests.c',
|
||||
|
@ -122,6 +133,8 @@ unit_tests = executable('mutter-test-unit-tests',
|
|||
'boxes-tests.h',
|
||||
'meta-wayland-test-driver.c',
|
||||
'meta-wayland-test-driver.h',
|
||||
'meta-gpu-test.c',
|
||||
'meta-gpu-test.h',
|
||||
'monitor-config-migration-unit-tests.c',
|
||||
'monitor-config-migration-unit-tests.h',
|
||||
'monitor-store-unit-tests.c',
|
||||
|
@ -131,6 +144,7 @@ unit_tests = executable('mutter-test-unit-tests',
|
|||
'monitor-transform-tests.c',
|
||||
'monitor-transform-tests.h',
|
||||
'monitor-unit-tests.c',
|
||||
'orientation-manager-unit-tests.c',
|
||||
'monitor-unit-tests.h',
|
||||
'wayland-unit-tests.c',
|
||||
'wayland-unit-tests.h',
|
||||
|
|
125
src/tests/meta-dbus-runner.py
Executable file
125
src/tests/meta-dbus-runner.py
Executable file
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import dbus
|
||||
import sys
|
||||
import os
|
||||
import fcntl
|
||||
import subprocess
|
||||
from collections import OrderedDict
|
||||
from dbusmock import DBusTestCase
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
|
||||
|
||||
def set_nonblock(fd):
|
||||
'''Set a file object to non-blocking'''
|
||||
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
|
||||
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')
|
||||
|
||||
|
||||
class MutterDBusTestCase(DBusTestCase):
|
||||
@classmethod
|
||||
def setUpClass(klass):
|
||||
klass.mocks = OrderedDict()
|
||||
|
||||
DBusTestCase.setUpClass()
|
||||
klass.start_session_bus()
|
||||
klass.start_system_bus()
|
||||
|
||||
(klass.mocks_manager, klass.mock_obj) = klass.start_from_local_template(
|
||||
'meta-mocks-manager', {'templates-dir': get_templates_dir()})
|
||||
|
||||
klass.start_from_template('logind')
|
||||
|
||||
klass.system_bus_con = klass.get_dbus(system_bus=True)
|
||||
klass.session_bus_con = klass.get_dbus(system_bus=False)
|
||||
|
||||
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,
|
||||
stdout=subprocess.PIPE)
|
||||
set_nonblock(mock_server.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=subprocess.PIPE)
|
||||
set_nonblock(mock_server.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
|
||||
|
||||
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)
|
||||
self.assertEqual(p.wait(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
MutterDBusTestCase.setUpClass()
|
||||
test_case = MutterDBusTestCase()
|
||||
test_case.assertGreater(len(sys.argv), 1)
|
||||
test_case.wrap_call(sys.argv[1:])
|
||||
MutterDBusTestCase.tearDownClass()
|
|
@ -23,6 +23,7 @@
|
|||
#include "backends/meta-crtc.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "backends/meta-output.h"
|
||||
#include "core/util-private.h"
|
||||
|
||||
typedef struct _MetaMonitorTestSetup
|
||||
{
|
||||
|
@ -65,6 +66,7 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerTest, meta_monitor_manager_test,
|
|||
META_EXPORT
|
||||
void meta_monitor_manager_test_init_test_setup (CreateTestSetupFunc func);
|
||||
|
||||
META_EXPORT
|
||||
void meta_monitor_manager_test_read_current (MetaMonitorManager *manager);
|
||||
|
||||
META_EXPORT
|
||||
|
|
255
src/tests/meta-sensors-proxy-mock.c
Normal file
255
src/tests/meta-sensors-proxy-mock.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2020 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-sensors-proxy-mock.h"
|
||||
|
||||
#define SENSORS_MOCK_TEMPLATE "iio-sensors-proxy"
|
||||
|
||||
static MetaSensorsProxyMock *sensors_proxy_mock = NULL;
|
||||
|
||||
static const char *
|
||||
orientation_to_string (MetaOrientation orientation)
|
||||
{
|
||||
const char *orientation_str = "undefined";
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case META_ORIENTATION_UNDEFINED:
|
||||
orientation_str = "undefined";
|
||||
break;
|
||||
case META_ORIENTATION_NORMAL:
|
||||
orientation_str = "normal";
|
||||
break;
|
||||
case META_ORIENTATION_BOTTOM_UP:
|
||||
orientation_str = "bottom-up";
|
||||
break;
|
||||
case META_ORIENTATION_LEFT_UP:
|
||||
orientation_str = "left-up";
|
||||
break;
|
||||
case META_ORIENTATION_RIGHT_UP:
|
||||
orientation_str = "right-up";
|
||||
break;
|
||||
}
|
||||
|
||||
return orientation_str;
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_call_cb (GObject *object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
GVariant **ret = user_data;
|
||||
|
||||
*ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (ret);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
get_internal_property_value (MetaSensorsProxyMock *proxy,
|
||||
const char *property_name)
|
||||
{
|
||||
g_autoptr (GVariant) ret = NULL;
|
||||
|
||||
g_dbus_proxy_call (proxy, "GetInternalProperty",
|
||||
g_variant_new ("(s)", property_name),
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL,
|
||||
on_proxy_call_cb, &ret);
|
||||
|
||||
while (!ret)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return g_variant_get_child_value (ret, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_property (MetaSensorsProxyMock *proxy,
|
||||
const char *property_name,
|
||||
GVariant *expected_value)
|
||||
{
|
||||
g_autoptr (GVariant) value = NULL;
|
||||
g_autoptr (GVariant) expected = NULL;
|
||||
gboolean equal_properties;
|
||||
|
||||
value = get_internal_property_value (proxy, property_name);
|
||||
|
||||
if (!g_variant_is_of_type (value, G_VARIANT_TYPE_VARIANT))
|
||||
{
|
||||
g_autoptr (GVariant) tmp = g_variant_ref (value);
|
||||
value = g_variant_new ("v", tmp);
|
||||
}
|
||||
|
||||
if (g_variant_is_of_type (expected_value, G_VARIANT_TYPE_VARIANT))
|
||||
expected = g_variant_ref (expected_value);
|
||||
else
|
||||
expected = g_variant_new ("v", expected_value);
|
||||
|
||||
equal_properties = g_variant_equal (expected, value);
|
||||
|
||||
if (!equal_properties)
|
||||
{
|
||||
g_autofree char *actual_str = g_variant_print (value, TRUE);
|
||||
g_autofree char *expected_str = g_variant_print (expected, TRUE);
|
||||
|
||||
g_debug ("Property: %s", property_name);
|
||||
g_debug ("Expected: %s", expected_str);
|
||||
g_debug ("Actual: %s", actual_str);
|
||||
}
|
||||
|
||||
g_assert_true (equal_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_sensors_mock (GDBusConnection *connection)
|
||||
{
|
||||
g_autoptr (GVariant) ret = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
ret = g_dbus_connection_call_sync (connection,
|
||||
"org.gnome.Mutter.TestDBusMocksManager",
|
||||
"/org/gnome/Mutter/TestDBusMocksManager",
|
||||
"org.gnome.Mutter.TestDBusMocksManager",
|
||||
"StopLocalTemplate",
|
||||
g_variant_new ("(s)", SENSORS_MOCK_TEMPLATE),
|
||||
NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
|
||||
NULL, &error);
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
start_sensors_mock (void)
|
||||
{
|
||||
g_autoptr (GDBusConnection) connection = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (GVariant) ret = NULL;
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
ret = g_dbus_connection_call_sync (connection,
|
||||
"org.gnome.Mutter.TestDBusMocksManager",
|
||||
"/org/gnome/Mutter/TestDBusMocksManager",
|
||||
"org.gnome.Mutter.TestDBusMocksManager",
|
||||
"StartFromLocalTemplate",
|
||||
g_variant_new ("(s)", SENSORS_MOCK_TEMPLATE),
|
||||
NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
|
||||
NULL, &error);
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_removed (gpointer data)
|
||||
{
|
||||
g_autoptr (GDBusConnection) connection = data;
|
||||
|
||||
stop_sensors_mock (connection);
|
||||
}
|
||||
|
||||
MetaSensorsProxyMock *
|
||||
meta_sensors_proxy_mock_get (void)
|
||||
{
|
||||
GDBusProxy *proxy = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (sensors_proxy_mock)
|
||||
return g_object_ref (sensors_proxy_mock);
|
||||
|
||||
start_sensors_mock ();
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
||||
NULL,
|
||||
"net.hadess.SensorProxy",
|
||||
"/net/hadess/SensorProxy",
|
||||
"org.freedesktop.DBus.Mock",
|
||||
NULL, &error);
|
||||
g_assert_true (G_IS_DBUS_PROXY (proxy));
|
||||
g_assert_no_error (error);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_autoptr (GVariant) ret = NULL;
|
||||
size_t n_owners = 0;
|
||||
|
||||
ret = get_internal_property_value (proxy, "AccelerometerOwners");
|
||||
if (g_variant_get_strv (ret, &n_owners) && n_owners)
|
||||
{
|
||||
g_assert_cmpuint (n_owners, ==, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sensors_proxy_mock = proxy;
|
||||
g_object_add_weak_pointer (G_OBJECT (sensors_proxy_mock),
|
||||
(gpointer *) &sensors_proxy_mock);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (proxy), "proxy-data",
|
||||
g_object_ref (g_dbus_proxy_get_connection (proxy)),
|
||||
on_proxy_removed);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
void
|
||||
meta_sensors_proxy_mock_set_property (MetaSensorsProxyMock *proxy,
|
||||
const gchar *property_name,
|
||||
GVariant *value)
|
||||
{
|
||||
g_autoptr (GVariant) ret = NULL;
|
||||
g_autoptr (GVariant) reffed_value = g_variant_ref (value);
|
||||
|
||||
g_dbus_proxy_call (proxy, "SetInternalProperty",
|
||||
g_variant_new ("(ssv)",
|
||||
"net.hadess.SensorProxy",
|
||||
property_name,
|
||||
reffed_value),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, NULL, on_proxy_call_cb, &ret);
|
||||
|
||||
while (!ret)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
g_assert_nonnull (ret);
|
||||
|
||||
ensure_property (proxy, property_name, value);
|
||||
}
|
||||
|
||||
void
|
||||
meta_sensors_proxy_mock_set_orientation (MetaSensorsProxyMock *proxy,
|
||||
MetaOrientation orientation)
|
||||
{
|
||||
const char *orientation_str;
|
||||
|
||||
meta_sensors_proxy_mock_set_property (proxy, "HasAccelerometer",
|
||||
g_variant_new_boolean (TRUE));
|
||||
|
||||
orientation_str = orientation_to_string (orientation);
|
||||
meta_sensors_proxy_mock_set_property (proxy, "AccelerometerOrientation",
|
||||
g_variant_new_string (orientation_str));
|
||||
}
|
41
src/tests/meta-sensors-proxy-mock.h
Normal file
41
src/tests/meta-sensors-proxy-mock.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2020 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*/
|
||||
|
||||
#ifndef META_SENSORS_PROXY_MOCK_H
|
||||
#define META_SENSORS_PROXY_MOCK_H
|
||||
|
||||
#include "backends/meta-orientation-manager.h"
|
||||
|
||||
typedef GDBusProxy MetaSensorsProxyMock;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaSensorsProxyMock, g_object_unref)
|
||||
|
||||
META_EXPORT
|
||||
MetaSensorsProxyMock * meta_sensors_proxy_mock_get (void);
|
||||
|
||||
META_EXPORT
|
||||
void meta_sensors_proxy_mock_set_property (MetaSensorsProxyMock *proxy,
|
||||
const gchar *property_name,
|
||||
GVariant *value);
|
||||
|
||||
META_EXPORT
|
||||
void meta_sensors_proxy_mock_set_orientation (MetaSensorsProxyMock *proxy,
|
||||
MetaOrientation orientation);
|
||||
|
||||
#endif /* META_SENSORS_PROXY_MOCK_H */
|
|
@ -1,6 +1,6 @@
|
|||
[Test]
|
||||
Description=All Mutter tests
|
||||
TestEnvironment=GSETTINGS_BACKEND=memory;
|
||||
Exec=sh -c 'env XDG_RUNTIME_DIR="$(mktemp -d -t mutter-@apiversion@-all-tests-XXXXXX)" dbus-run-session -- xvfb-run -a -s "+iglx -noreset" -- @libexecdir@/installed-tests/mutter-@apiversion@/mutter-test-runner --all'
|
||||
Exec=sh -c 'env 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'
|
||||
Type=session
|
||||
Output=TAP
|
||||
|
|
131
src/tests/orientation-manager-unit-tests.c
Normal file
131
src/tests/orientation-manager-unit-tests.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2020 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "orientation-manager-unit-tests.h"
|
||||
|
||||
#include "tests/meta-sensors-proxy-mock.h"
|
||||
|
||||
static void
|
||||
meta_test_orientation_manager_no_daemon (void)
|
||||
{
|
||||
g_autoptr (MetaOrientationManager) manager = NULL;
|
||||
|
||||
manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
|
||||
g_assert_false (meta_orientation_manager_has_accelerometer (manager));
|
||||
g_assert_cmpuint (meta_orientation_manager_get_orientation (manager),
|
||||
==,
|
||||
META_ORIENTATION_UNDEFINED);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_orientation_manager_no_device (void)
|
||||
{
|
||||
g_autoptr (MetaOrientationManager) manager = NULL;
|
||||
MetaSensorsProxyMock* orientation_mock = NULL;
|
||||
|
||||
orientation_mock = meta_sensors_proxy_mock_get ();
|
||||
manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
|
||||
g_assert_false (meta_orientation_manager_has_accelerometer (manager));
|
||||
g_assert_cmpuint (meta_orientation_manager_get_orientation (manager),
|
||||
==,
|
||||
META_ORIENTATION_UNDEFINED);
|
||||
|
||||
g_object_unref (orientation_mock);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_orientation_manager_has_accelerometer (void)
|
||||
{
|
||||
g_autoptr (MetaOrientationManager) manager = NULL;
|
||||
g_autoptr (MetaSensorsProxyMock) orientation_mock = NULL;
|
||||
|
||||
manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
|
||||
orientation_mock = meta_sensors_proxy_mock_get ();
|
||||
|
||||
meta_sensors_proxy_mock_set_property (orientation_mock,
|
||||
"HasAccelerometer",
|
||||
g_variant_new_boolean (TRUE));
|
||||
|
||||
g_debug ("Checking whether accelerometer is present");
|
||||
g_assert_true (meta_orientation_manager_has_accelerometer (manager));
|
||||
g_assert_cmpuint (meta_orientation_manager_get_orientation (manager),
|
||||
==,
|
||||
META_ORIENTATION_UNDEFINED);
|
||||
}
|
||||
|
||||
static void
|
||||
orientation_changed_cb (MetaOrientationManager *manager,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean *changed_called = user_data;
|
||||
|
||||
*changed_called = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_orientation_manager_accelerometer_orientations (void)
|
||||
{
|
||||
g_autoptr (MetaOrientationManager) manager = NULL;
|
||||
g_autoptr (MetaSensorsProxyMock) orientation_mock = NULL;
|
||||
|
||||
manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
|
||||
orientation_mock = meta_sensors_proxy_mock_get ();
|
||||
|
||||
MetaOrientation initial;
|
||||
gboolean changed_called;
|
||||
unsigned i;
|
||||
|
||||
g_signal_connect (manager, "orientation-changed",
|
||||
G_CALLBACK (orientation_changed_cb),
|
||||
&changed_called);
|
||||
|
||||
initial = meta_orientation_manager_get_orientation (manager);
|
||||
|
||||
for (i = initial + 1; i != initial; i = (i + 1) % META_N_ORIENTATIONS)
|
||||
{
|
||||
changed_called = FALSE;
|
||||
meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
|
||||
|
||||
g_debug ("Checking orientation %d", i);
|
||||
g_assert_cmpuint (meta_orientation_manager_get_orientation (manager),
|
||||
==,
|
||||
i);
|
||||
|
||||
if (i != META_ORIENTATION_UNDEFINED)
|
||||
g_assert_true (changed_called);
|
||||
else
|
||||
g_assert_false (changed_called);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init_orientation_manager_tests (void)
|
||||
{
|
||||
g_test_add_func ("/backends/orientation-manager/no-daemon",
|
||||
meta_test_orientation_manager_no_daemon);
|
||||
g_test_add_func ("/backends/orientation-manager/no-device",
|
||||
meta_test_orientation_manager_no_device);
|
||||
g_test_add_func ("/backends/orientation-manager/has-accelerometer",
|
||||
meta_test_orientation_manager_has_accelerometer);
|
||||
g_test_add_func ("/backends/orientation-manager/accelerometer-orientations",
|
||||
meta_test_orientation_manager_accelerometer_orientations);
|
||||
}
|
26
src/tests/orientation-manager-unit-tests.h
Normal file
26
src/tests/orientation-manager-unit-tests.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2020 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*/
|
||||
|
||||
#ifndef ORIENTATION_MANAGER_UNIT_TESTS_H
|
||||
#define ORIENTATION_MANAGER_UNIT_TESTS_H
|
||||
|
||||
void init_orientation_manager_tests (void);
|
||||
|
||||
#endif /* ORIENTATION_MANAGER_UNIT_TESTS_H */
|
|
@ -35,6 +35,8 @@
|
|||
#include "tests/monitor-unit-tests.h"
|
||||
#include "tests/monitor-store-unit-tests.h"
|
||||
#include "tests/monitor-transform-tests.h"
|
||||
#include "tests/meta-test-utils.h"
|
||||
#include "tests/orientation-manager-unit-tests.h"
|
||||
#include "tests/wayland-unit-tests.h"
|
||||
|
||||
MetaContext *test_context;
|
||||
|
@ -232,6 +234,7 @@ init_tests (void)
|
|||
init_boxes_tests ();
|
||||
init_wayland_tests ();
|
||||
init_monitor_transform_tests ();
|
||||
init_orientation_manager_tests ();
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in a new issue