#!/usr/bin/python3 # iio-sensor-proxy integration test suite # # Run in built tree to test local built binaries, or from anywhere else to test # system installed binaries. # # Copyright: (C) 2011 Martin Pitt # (C) 2021 Bastien Nocera # # 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. import os import sys import dbus import dbusmock import gi import tempfile import psutil import subprocess import unittest import time try: from gi.repository import GLib from gi.repository import Gio except ImportError as e: sys.stderr.write('PyGobject not available for Python 3, or missing GI typelibs: %s\n' % str(e)) sys.exit(1) try: gi.require_version('UMockdev', '1.0') from gi.repository import UMockdev except ImportError: sys.stderr.write('umockdev not available (https://github.com/martinpitt/umockdev)\n') sys.exit(1) SP = 'net.hadess.SensorProxy' SP_PATH = '/net/hadess/SensorProxy' SP_COMPASS = 'net.hadess.SensorProxy.Compass' SP_COMPASS_PATH = '/net/hadess/SensorProxy/Compass' class Tests(dbusmock.DBusTestCase): @classmethod def setUpClass(cls): # run from local build tree if we are in one, otherwise use system instance builddir = os.getenv('top_builddir', '.') if os.access(os.path.join(builddir, 'src', 'iio-sensor-proxy'), os.X_OK): cls.daemon_path = os.path.join(builddir, 'src', 'iio-sensor-proxy') cls.monitor_sensor_path = os.path.join(builddir, 'src', 'monitor-sensor') print('Testing binaries from local build tree (%s)' % cls.daemon_path) elif os.environ.get('UNDER_JHBUILD', False): jhbuild_prefix = os.environ['JHBUILD_PREFIX'] cls.daemon_path = os.path.join(jhbuild_prefix, 'libexec', 'iio-sensor-proxy') cls.monitor_sensor_path = os.path.join(jhbuild_prefix, 'bin', 'monitor-sensor') print('Testing binaries from JHBuild (%s)' % cls.daemon_path) else: cls.daemon_path = None with open('/usr/lib/systemd/system/iio-sensor-proxy.service') as f: for line in f: if line.startswith('ExecStart='): cls.daemon_path = line.split('=', 1)[1].strip() break assert cls.daemon_path, 'could not determine daemon path from systemd .service file' cls.monitor_sensor_path = '/usr/bin/monitor-sensor' print('Testing installed system binary (%s)' % cls.daemon_path) # fail on CRITICALs on client and server side GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING | GLib.LogLevelFlags.LEVEL_ERROR | GLib.LogLevelFlags.LEVEL_CRITICAL) os.environ['G_DEBUG'] = 'fatal_warnings' # set up a fake system D-BUS cls.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE) cls.test_bus.up() try: del os.environ['DBUS_SESSION_BUS_ADDRESS'] except KeyError: pass os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = cls.test_bus.get_bus_address() cls.dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) cls.dbus_con = cls.get_dbus(True) @classmethod def tearDownClass(cls): cls.test_bus.down() dbusmock.DBusTestCase.tearDownClass() def setUp(self): '''Set up a local umockdev testbed. The testbed is initially empty. ''' self.testbed = UMockdev.Testbed.new() self.polkitd, obj_polkit = self.spawn_server_template( 'polkitd', {}, stdout=subprocess.PIPE) obj_polkit.SetAllowed(['net.hadess.SensorProxy.claim-sensor']) self.proxy = None self.log = None self.daemon = None def tearDown(self): del self.testbed self.stop_daemon() if self.polkitd: try: self.polkitd.kill() except OSError: pass self.polkitd.wait() self.polkitd = None # on failures, print daemon log errors = [x[1] for x in self._outcome.errors if x[1]] if errors and self.log: with open(self.log.name) as f: sys.stderr.write('\n-------------- daemon log: ----------------\n') sys.stderr.write(f.read()) sys.stderr.write('------------------------------\n') # # Daemon control and D-BUS I/O # def start_daemon(self, env = None, wrapper = None): '''Start daemon and create DBus proxy. When done, this sets self.proxy as the Gio.DBusProxy for power-profiles-daemon. ''' if not env: env = os.environ.copy() env['G_DEBUG'] = 'fatal-criticals' env['G_MESSAGES_DEBUG'] = 'all' env['UMOCKDEV_DEBUG'] = 'all' # note: Python doesn't propagate the setenv from Testbed.new(), so we # have to do that ourselves env['UMOCKDEV_DIR'] = self.testbed.get_root_dir() self.log = tempfile.NamedTemporaryFile() timeout_multiplier = 1 if wrapper: daemon_path = wrapper + [ self.daemon_path ] else: daemon_path = [ self.daemon_path ] if os.getenv('VALGRIND') != None: daemon_path = ['valgrind'] + daemon_path + ['-v'] timeout_multiplier = 10 else: daemon_path = daemon_path + ['-v'] self.daemon = subprocess.Popen(daemon_path, env=env, stdout=self.log, stderr=subprocess.STDOUT) # wait until the daemon gets online timeout = 100 * timeout_multiplier while timeout > 0: time.sleep(0.1) timeout -= 1 try: self.get_dbus_property('HasAccelerometer') break except GLib.GError: pass else: self.fail('daemon did not start in 10 seconds') self.proxy = Gio.DBusProxy.new_sync( self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP, SP_PATH, SP, None) self.assertEqual(self.daemon.poll(), None, 'daemon crashed') def stop_daemon(self): '''Stop the daemon if it is running.''' if self.daemon: try: for child in psutil.Process(self.daemon.pid).children(recursive=True): child.kill() self.daemon.kill() except OSError: pass self.daemon.wait() self.daemon = None self.proxy = None def get_dbus_property(self, name): '''Get property value from daemon D-Bus interface.''' proxy = Gio.DBusProxy.new_sync( self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP, SP_PATH, 'org.freedesktop.DBus.Properties', None) return proxy.Get('(ss)', SP, name) def get_compass_dbus_property(self, name): '''Get property value from daemon compass D-Bus interface.''' proxy = Gio.DBusProxy.new_sync( self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP, SP_COMPASS_PATH, 'org.freedesktop.DBus.Properties', None) return proxy.Get('(ss)', SP_COMPASS, name) def have_text_in_log(self, text): return self.count_text_in_log(text) > 0 def count_text_in_log(self, text): with open(self.log.name) as f: return f.read().count(text) def read_sysfs_attr(self, device, attribute): with open(os.path.join(self.testbed.get_root_dir() + device, attribute), 'rb') as f: return f.read() return None def read_file(self, path): with open(path, 'rb') as f: return f.read() return None def assertEventually(self, condition, message=None, timeout=50): '''Assert that condition function eventually returns True. Timeout is in deciseconds, defaulting to 50 (5 seconds). message is printed on failure. ''' while timeout >= 0: context = GLib.MainContext.default() while context.iteration(False): pass if condition(): break timeout -= 1 time.sleep(0.1) else: self.fail(message or 'timed out waiting for ' + str(condition)) # # Actual test cases # def test_hwmon_light(self): '''hwmon light''' hwmon = self.testbed.add_device('platform', 'hwmon-als', None, ['light', '(128,128)'], ['IIO_SENSOR_PROXY_TYPE', 'hwmon-als'] ) self.start_daemon() self.assertEqual(self.get_dbus_property('HasAmbientLight'), True) self.assertEqual(self.get_dbus_property('HasAccelerometer'), False) # Default values self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') self.assertEqual(self.get_dbus_property('LightLevel'), 0) self.proxy.ClaimLight() self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 50) self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'vendor') self.testbed.set_attribute(hwmon, 'light', '(255,255)') # DEFAULT_POLL_TIME time.sleep(0.5) self.assertEventually(lambda: self.get_dbus_property('LightLevel') == 100) # process = subprocess.Popen(['gdbus', 'introspect', '--system', '--dest', 'net.hadess.SensorProxy', '--object-path', '/net/hadess/SensorProxy']) # print (self.get_dbus_property('Foo')) self.stop_daemon() def test_fake_light(self): '''fake light''' self.testbed.add_device('input', 'fake-light', None, [], ['NAME', '"Power Button"'] ) env = os.environ.copy() env['FAKE_LIGHT_SENSOR'] = '1' self.start_daemon(env) self.assertEqual(self.get_dbus_property('HasAmbientLight'), True) self.assertEqual(self.get_dbus_property('HasAccelerometer'), False) # Default values self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') self.assertEqual(self.get_dbus_property('LightLevel'), 0) self.proxy.ClaimLight() self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 1.0) self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 2.0) self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') # process = subprocess.Popen(['gdbus', 'introspect', '--system', '--dest', 'net.hadess.SensorProxy', '--object-path', '/net/hadess/SensorProxy']) # print (self.get_dbus_property('Foo')) self.stop_daemon() def test_fake_compass(self): '''fake compass''' self.testbed.add_device('input', 'fake-compass', None, [], ['NAME', '"Power Button"'] ) env = os.environ.copy() env['FAKE_COMPASS'] = '1' self.start_daemon(env) self.assertEqual(self.get_dbus_property('HasAmbientLight'), False) self.assertEqual(self.get_compass_dbus_property('HasCompass'), True) # Default values compass_proxy = Gio.DBusProxy.new_sync( self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP, SP_COMPASS_PATH, SP_COMPASS, None) compass_proxy.ClaimCompass() self.assertEventually(lambda: int(self.get_compass_dbus_property('CompassHeading')) == 10) self.assertEventually(lambda: int(self.get_compass_dbus_property('CompassHeading')) == 20) self.stop_daemon() def test_iio_accel_base_location(self): '''iio accel base location''' self.testbed.add_device('iio', 'iio-accel', None, ['in_accel_x_raw', '0', 'in_accel_y_raw', '-25.6', 'in_accel_z_raw', '0', 'in_accel_scale', '10', 'label', 'accel-base', 'sampling_frequency', '5.2', 'name', 'IIO Test Accelerometer'], ['NAME', '"IIO Accelerometer"', 'IIO_SENSOR_PROXY_TYPE', 'iio-poll-accel'] ) self.testbed.add_device('input', 'fake-compass', None, [], ['NAME', '"Power Button"'] ) env = os.environ.copy() env['FAKE_COMPASS'] = '1' self.start_daemon(env) self.assertEqual(self.get_compass_dbus_property('HasCompass'), True) self.assertEqual(self.get_dbus_property('HasAccelerometer'), False) self.stop_daemon() def test_iio_poll_accel(self): '''iio poll accel''' accel = self.testbed.add_device('iio', 'iio-accel', None, ['in_accel_x_raw', '0', 'in_accel_y_raw', '-25.6', 'in_accel_z_raw', '0', 'in_accel_scale', '10', 'sampling_frequency', '5.2', 'name', 'IIO Test Accelerometer'], ['NAME', '"IIO Accelerometer"', 'IIO_SENSOR_PROXY_TYPE', 'iio-poll-accel'] ) self.start_daemon() self.assertEqual(self.get_dbus_property('HasAmbientLight'), False) self.assertEqual(self.get_dbus_property('HasAccelerometer'), True) # Default values self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'undefined') self.assertEqual(self.read_sysfs_attr(accel, 'sampling_frequency'), b'10') self.proxy.ClaimAccelerometer() self.assertEventually(lambda: self.get_dbus_property('AccelerometerOrientation') == 'normal') self.testbed.set_attribute(accel, 'in_accel_x_raw', '-25.6') self.testbed.set_attribute(accel, 'in_accel_y_raw', '0') self.assertEventually(lambda: self.get_dbus_property('AccelerometerOrientation') == 'right-up') self.stop_daemon() def test_iio_poll_light(self): '''iio poll light''' iio = self.testbed.add_device('iio', 'iio-als', None, ['integration_time', '1', 'in_illuminance_input', '10', 'in_illuminance_scale', '1.0'], ['NAME', '"IIO Light Sensor"', 'IIO_SENSOR_PROXY_TYPE', 'iio-poll-als'] ) self.start_daemon() self.assertEqual(self.get_dbus_property('HasAmbientLight'), True) self.assertEqual(self.get_dbus_property('HasAccelerometer'), False) # Default values self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') self.assertEqual(self.get_dbus_property('LightLevel'), 0) self.proxy.ClaimLight() self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 10) self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux') self.testbed.set_attribute(iio, 'in_illuminance_input', '30') self.assertEventually(lambda: self.get_dbus_property('LightLevel') == 30) self.stop_daemon() def test_iio_poll_proximity(self): '''iio poll proximity''' prox = self.testbed.add_device('iio', 'iio-proximity', None, ['in_proximity_nearlevel', '128', 'in_proximity_raw', '256', 'name', 'IIO Test Proximity Sensor'], ['NAME', '"IIO Proximity Sensor"', 'IIO_SENSOR_PROXY_TYPE', 'iio-poll-proximity'] ) self.start_daemon() self.assertEqual(self.get_dbus_property('HasAmbientLight'), False) self.assertEqual(self.get_dbus_property('HasAccelerometer'), False) self.assertEqual(self.get_dbus_property('HasProximity'), True) # Default values self.assertEqual(self.get_dbus_property('ProximityNear'), False) self.proxy.ClaimProximity() self.assertEventually(lambda: self.get_dbus_property('ProximityNear') == True) self.testbed.set_attribute(prox, 'in_proximity_raw', '0') self.assertEventually(lambda: self.get_dbus_property('ProximityNear') == False) self.testbed.set_attribute(prox, 'in_proximity_raw', '129') self.assertEventually(lambda: self.get_dbus_property('ProximityNear') == True) # Test margin self.testbed.set_attribute(prox, 'in_proximity_raw', '127') self.assertEventually(lambda: self.get_dbus_property('ProximityNear') == True) self.stop_daemon() def test_input_accel(self): '''input accelerometer''' top_srcdir = os.getenv('top_srcdir', '.') script = ['umockdev-run', '-d', top_srcdir + '/tests/input-accel-device', '-i', '/dev/input/event4=%s/tests/input-accel-capture.ioctl' % (top_srcdir), '--'] self.start_daemon(wrapper=script) self.assertEqual(self.get_dbus_property('HasAccelerometer'), True) self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'normal') self.stop_daemon() def test_iio_buffer_accel(self): '''iio buffer accel''' top_srcdir = os.getenv('top_srcdir', '.') mock_dev_data = self.testbed.get_root_dir() + '/iio-dev-data.bin' accel = self.testbed.add_device('iio', 'iio-buffer-accel0', None, ['name', 'IIO Test Accelerometer', 'buffer/enable', '0', 'trigger/current_trigger', '', 'scan_elements/in_accel_x_en', '0', 'scan_elements/in_accel_x_index', '0', 'scan_elements/in_accel_x_type', 'le:s16/32>>0', 'scan_elements/in_accel_y_en', '0', 'scan_elements/in_accel_y_index', '1', 'scan_elements/in_accel_y_type', 'le:s16/32>>0', 'scan_elements/in_accel_z_en', '0', 'scan_elements/in_accel_z_index', '2', 'scan_elements/in_accel_z_type', 'le:s16/32>>0', 'scan_elements/in_timestamp_en', '1', 'scan_elements/in_timestamp_index', '3', 'scan_elements/in_timestamp_type', 'le:s64/64>>0'], ['NAME', '"IIO Accelerometer"', 'DEVNAME', '/dev/iio-buffer-accel-test', 'IIO_SENSOR_PROXY_TYPE', 'iio-buffer-accel'] ) trigger = self.testbed.add_device('iio', 'trigger0', None, ['name', 'accel_3d-dev0'], [] ) self.start_daemon() self.assertEqual(self.get_dbus_property('HasAmbientLight'), False) self.assertEqual(self.get_dbus_property('HasAccelerometer'), True) # Default values self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'undefined') self.assertEqual(self.read_sysfs_attr(accel, 'buffer/enable'), b'1') self.assertEqual(self.read_sysfs_attr(accel, 'scan_elements/in_accel_x_en'), b'1') self.assertEqual(self.read_sysfs_attr(accel, 'scan_elements/in_accel_y_en'), b'1') self.assertEqual(self.read_sysfs_attr(accel, 'scan_elements/in_accel_z_en'), b'1') data = self.read_file(top_srcdir + '/tests/iio-buffer-accel-data/orientation-normal.bin') with open(mock_dev_data,'wb') as mock_file: mock_file.write(data) self.proxy.ClaimAccelerometer() time.sleep(1) self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'normal') os.remove(mock_dev_data) time.sleep(1) self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'normal') data = self.read_file(top_srcdir + '/tests/iio-buffer-accel-data/orientation-left-up.bin') with open(mock_dev_data,'wb') as mock_file: mock_file.write(data) time.sleep(1) self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'left-up') os.remove(mock_dev_data) data = self.read_file(top_srcdir + '/tests/iio-buffer-accel-data/orientation-normal.bin') with open(mock_dev_data,'wb') as mock_file: mock_file.write(data) time.sleep(1) self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 'normal') os.remove(mock_dev_data) self.stop_daemon() def test_unrequested_readings(self): '''unrequested property updates''' self.testbed.add_device('input', 'fake-light', None, [], ['NAME', '"Power Button"'] ) env = os.environ.copy() env['FAKE_LIGHT_SENSOR'] = '1' self.start_daemon(env) self.assertEqual(self.get_dbus_property('HasAmbientLight'), True) ctx = GLib.main_context_default() self.proxy.ClaimLight() self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 1.0) self.proxy.ReleaseLight() self.assertEqual(self.get_dbus_property('LightLevel'), 1.0) monitor = subprocess.Popen(self.monitor_sensor_path) self.assertEventually(lambda: int(self.get_dbus_property('LightLevel')) == 2.0) monitor.kill() # Catch up with main loop signals while ctx.pending(): ctx.iteration(True) # We shouldn't have received light level properties updates res = self.proxy.get_cached_property('LightLevel') self.assertEqual(res.unpack(), 1.0) self.assertTrue(int(self.get_dbus_property('LightLevel') > 1.0)) self.stop_daemon() def test_iio_scale_decimal_separator(self): '''scale decimal separator''' top_srcdir = os.getenv('top_srcdir', '.') mock_dev_data = self.testbed.get_root_dir() + '/iio-dev-data.bin' accel = self.testbed.add_device('iio', 'iio-buffer-accel0', None, ['name', 'IIO Test Accelerometer', 'buffer/enable', '0', 'trigger/current_trigger', '', 'in_accel_scale', '0.000010\n', 'in_accel_offset', '0.0\n', 'in_accel_mount_matrix', '1, 0, 0; 0, 1, 0; 0, 0, 1\n', 'scan_elements/in_accel_x_en', '0', 'scan_elements/in_accel_x_index', '0', 'scan_elements/in_accel_x_type', 'le:s16/32>>0', 'scan_elements/in_accel_y_en', '0', 'scan_elements/in_accel_y_index', '1', 'scan_elements/in_accel_y_type', 'le:s16/32>>0', 'scan_elements/in_accel_z_en', '0', 'scan_elements/in_accel_z_index', '2', 'scan_elements/in_accel_z_type', 'le:s16/32>>0', 'scan_elements/in_timestamp_en', '1', 'scan_elements/in_timestamp_index', '3', 'scan_elements/in_timestamp_type', 'le:s64/64>>0'], ['NAME', '"IIO Accelerometer"', 'DEVNAME', '/dev/iio-buffer-accel-test', 'IIO_SENSOR_PROXY_TYPE', 'iio-buffer-accel'] ) trigger = self.testbed.add_device('iio', 'trigger0', None, ['name', 'accel_3d-dev0'], [] ) env = os.environ.copy() env['LC_NUMERIC'] = 'fr_FR.UTF-8' self.start_daemon(env=env) self.assertEqual(self.get_dbus_property('HasAccelerometer'), True) data = self.read_file(top_srcdir + '/tests/iio-buffer-accel-data/orientation-normal.bin') with open(mock_dev_data,'wb') as mock_file: mock_file.write(data) self.proxy.ClaimAccelerometer() self.assertEventually(lambda: self.have_text_in_log('Accel sent by driver')) # If the 2nd test fails, it's likely that fr_FR.UTF-8 locale isn't supported self.assertEqual(self.have_text_in_log('scale: 0,000000,0,000000,0,000000'), False) self.assertEqual(self.have_text_in_log('scale: 0,000010,0,000010,0,000010'), True) self.stop_daemon() def test_iio_scale_decimal_separator_offset(self): '''scale decimal separator with specific offset''' top_srcdir = os.getenv('top_srcdir', '.') mock_dev_data = self.testbed.get_root_dir() + '/iio-dev-data.bin' accel = self.testbed.add_device('iio', 'iio-buffer-accel0', None, ['name', 'IIO Test Accelerometer', 'buffer/enable', '0', 'trigger/current_trigger', '', 'in_accel_scale', '0.000010\n', 'in_accel_x_offset', '0.0\n', 'in_accel_mount_matrix', '1, 0, 0; 0, 1, 0; 0, 0, 1\n', 'scan_elements/in_accel_x_en', '0', 'scan_elements/in_accel_x_index', '0', 'scan_elements/in_accel_x_type', 'le:s16/32>>0', 'scan_elements/in_accel_y_en', '0', 'scan_elements/in_accel_y_index', '1', 'scan_elements/in_accel_y_type', 'le:s16/32>>0', 'scan_elements/in_accel_z_en', '0', 'scan_elements/in_accel_z_index', '2', 'scan_elements/in_accel_z_type', 'le:s16/32>>0', 'scan_elements/in_timestamp_en', '1', 'scan_elements/in_timestamp_index', '3', 'scan_elements/in_timestamp_type', 'le:s64/64>>0'], ['NAME', '"IIO Accelerometer"', 'DEVNAME', '/dev/iio-buffer-accel-test', 'IIO_SENSOR_PROXY_TYPE', 'iio-buffer-accel'] ) trigger = self.testbed.add_device('iio', 'trigger0', None, ['name', 'accel_3d-dev0'], [] ) env = os.environ.copy() env['LC_NUMERIC'] = 'fr_FR.UTF-8' self.start_daemon(env=env) self.assertEqual(self.get_dbus_property('HasAccelerometer'), True) self.stop_daemon() def test_iio_scale_decimal_separator2(self): '''scale decimal separator polling''' accel = self.testbed.add_device('iio', 'iio-accel', None, ['in_accel_x_raw', '0', 'in_accel_y_raw', '-256000000', 'in_accel_z_raw', '0', 'in_accel_scale', '0.000001', 'sampling_frequency', '5.2', 'name', 'IIO Test Accelerometer'], ['NAME', '"IIO Accelerometer"', 'IIO_SENSOR_PROXY_TYPE', 'iio-poll-accel'] ) env = os.environ.copy() env['LC_NUMERIC'] = 'fr_FR.UTF-8' self.start_daemon(env=env) self.proxy.ClaimAccelerometer() self.assertEventually(lambda: self.have_text_in_log('Accel read from IIO on')) # If the 2nd test fails, it's likely that fr_FR.UTF-8 locale isn't supported self.assertEqual(self.have_text_in_log('scale 1,000000,1,000000,1,000000'), False) self.assertEqual(self.have_text_in_log('scale 0,000001,0,000001,0,000001'), True) self.assertEventually(lambda: self.get_dbus_property('AccelerometerOrientation') == 'normal') self.testbed.set_attribute(accel, 'in_accel_x_raw', '-256000000') self.testbed.set_attribute(accel, 'in_accel_y_raw', '0') self.assertEventually(lambda: self.get_dbus_property('AccelerometerOrientation') == 'right-up') self.stop_daemon() # # Helper methods # @classmethod def _props_to_str(cls, properties): '''Convert a properties dictionary to uevent text representation.''' prop_str = '' if properties: for k, v in properties.items(): prop_str += '%s=%s\n' % (k, v) return prop_str if __name__ == '__main__': # run ourselves under umockdev if 'umockdev' not in os.environ.get('LD_PRELOAD', ''): os.execvp('umockdev-wrapper', ['umockdev-wrapper'] + sys.argv) unittest.main()