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:
Marco Trevisan (Treviño) 2020-05-04 19:22:35 +02:00 committed by Jonas Ådahl
parent 58fb865a7c
commit bf54a16f92
14 changed files with 912 additions and 3 deletions

View File

@ -16,8 +16,16 @@ variables:
.mutter.fedora:34@common: .mutter.fedora:34@common:
variables: variables:
FDO_DISTRIBUTION_VERSION: 34 FDO_DISTRIBUTION_VERSION: 34
BASE_TAG: '2021-08-25.0' BASE_TAG: '2021-09-04.0'
FDO_DISTRIBUTION_PACKAGES: 'gdm gnome-shell xorg-x11-server-Xvfb sassc gcovr clang uncrustify' FDO_DISTRIBUTION_PACKAGES:
clang
gcovr
gdm
gnome-shell
python3-dbusmock
sassc
uncrustify
xorg-x11-server-Xvfb
FDO_DISTRIBUTION_EXEC: | FDO_DISTRIBUTION_EXEC: |
dnf install -y 'dnf-command(builddep)' && dnf install -y 'dnf-command(builddep)' &&

View File

@ -295,11 +295,22 @@ if have_tests
have_clutter_tests = get_option('clutter_tests') have_clutter_tests = get_option('clutter_tests')
have_installed_tests = get_option('installed_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', add_test_setup('CI',
env: [ env: [
'MUTTER_DEBUG_DUMMY_MODE_SPECS=800x600@10.0', 'MUTTER_DEBUG_DUMMY_MODE_SPECS=800x600@10.0',
], ],
exe_wrapper: [ exe_wrapper: [
default_test_wrappers,
find_program('catchsegv'), find_program('catchsegv'),
find_program('xvfb-run'), '-a', '-s', '+iglx -noreset', find_program('xvfb-run'), '-a', '-s', '+iglx -noreset',
], ],

View File

@ -24,6 +24,8 @@
#include <glib-object.h> #include <glib-object.h>
#include "core/util-private.h"
typedef enum typedef enum
{ {
META_ORIENTATION_UNDEFINED, META_ORIENTATION_UNDEFINED,
@ -35,11 +37,15 @@ typedef enum
#define META_N_ORIENTATIONS (META_ORIENTATION_RIGHT_UP + 1) #define META_N_ORIENTATIONS (META_ORIENTATION_RIGHT_UP + 1)
#define META_TYPE_ORIENTATION_MANAGER (meta_orientation_manager_get_type ()) #define META_TYPE_ORIENTATION_MANAGER (meta_orientation_manager_get_type ())
META_EXPORT_TEST
G_DECLARE_FINAL_TYPE (MetaOrientationManager, meta_orientation_manager, G_DECLARE_FINAL_TYPE (MetaOrientationManager, meta_orientation_manager,
META, ORIENTATION_MANAGER, GObject) META, ORIENTATION_MANAGER, GObject)
META_EXPORT_TEST
MetaOrientation meta_orientation_manager_get_orientation (MetaOrientationManager *self); MetaOrientation meta_orientation_manager_get_orientation (MetaOrientationManager *self);
META_EXPORT_TEST
gboolean meta_orientation_manager_has_accelerometer (MetaOrientationManager *self); gboolean meta_orientation_manager_has_accelerometer (MetaOrientationManager *self);
#endif /* META_ORIENTATION_MANAGER_H */ #endif /* META_ORIENTATION_MANAGER_H */

View 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

View 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())

View File

@ -6,6 +6,8 @@ mutter_test_sources = [
'meta-gpu-test.h', 'meta-gpu-test.h',
'meta-monitor-manager-test.c', 'meta-monitor-manager-test.c',
'meta-monitor-manager-test.h', 'meta-monitor-manager-test.h',
'meta-sensors-proxy-mock.c',
'meta-sensors-proxy-mock.h',
'monitor-test-utils.c', 'monitor-test-utils.c',
'monitor-test-utils.h', 'monitor-test-utils.h',
'meta-test-utils.c', 'meta-test-utils.c',
@ -115,6 +117,15 @@ test_runner = executable('mutter-test-runner',
install_dir: mutter_installed_tests_libexecdir, 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', unit_tests = executable('mutter-test-unit-tests',
sources: [ sources: [
'unit-tests.c', 'unit-tests.c',
@ -122,6 +133,8 @@ unit_tests = executable('mutter-test-unit-tests',
'boxes-tests.h', 'boxes-tests.h',
'meta-wayland-test-driver.c', 'meta-wayland-test-driver.c',
'meta-wayland-test-driver.h', 'meta-wayland-test-driver.h',
'meta-gpu-test.c',
'meta-gpu-test.h',
'monitor-config-migration-unit-tests.c', 'monitor-config-migration-unit-tests.c',
'monitor-config-migration-unit-tests.h', 'monitor-config-migration-unit-tests.h',
'monitor-store-unit-tests.c', 'monitor-store-unit-tests.c',
@ -131,6 +144,7 @@ unit_tests = executable('mutter-test-unit-tests',
'monitor-transform-tests.c', 'monitor-transform-tests.c',
'monitor-transform-tests.h', 'monitor-transform-tests.h',
'monitor-unit-tests.c', 'monitor-unit-tests.c',
'orientation-manager-unit-tests.c',
'monitor-unit-tests.h', 'monitor-unit-tests.h',
'wayland-unit-tests.c', 'wayland-unit-tests.c',
'wayland-unit-tests.h', 'wayland-unit-tests.h',

125
src/tests/meta-dbus-runner.py Executable file
View 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()

View File

@ -23,6 +23,7 @@
#include "backends/meta-crtc.h" #include "backends/meta-crtc.h"
#include "backends/meta-monitor-manager-private.h" #include "backends/meta-monitor-manager-private.h"
#include "backends/meta-output.h" #include "backends/meta-output.h"
#include "core/util-private.h"
typedef struct _MetaMonitorTestSetup typedef struct _MetaMonitorTestSetup
{ {
@ -65,6 +66,7 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerTest, meta_monitor_manager_test,
META_EXPORT META_EXPORT
void meta_monitor_manager_test_init_test_setup (CreateTestSetupFunc func); void meta_monitor_manager_test_init_test_setup (CreateTestSetupFunc func);
META_EXPORT
void meta_monitor_manager_test_read_current (MetaMonitorManager *manager); void meta_monitor_manager_test_read_current (MetaMonitorManager *manager);
META_EXPORT META_EXPORT

View 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));
}

View 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 */

View File

@ -1,6 +1,6 @@
[Test] [Test]
Description=All Mutter tests Description=All Mutter tests
TestEnvironment=GSETTINGS_BACKEND=memory; 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 Type=session
Output=TAP Output=TAP

View 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);
}

View 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 */

View File

@ -35,6 +35,8 @@
#include "tests/monitor-unit-tests.h" #include "tests/monitor-unit-tests.h"
#include "tests/monitor-store-unit-tests.h" #include "tests/monitor-store-unit-tests.h"
#include "tests/monitor-transform-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" #include "tests/wayland-unit-tests.h"
MetaContext *test_context; MetaContext *test_context;
@ -232,6 +234,7 @@ init_tests (void)
init_boxes_tests (); init_boxes_tests ();
init_wayland_tests (); init_wayland_tests ();
init_monitor_transform_tests (); init_monitor_transform_tests ();
init_orientation_manager_tests ();
} }
int int