1310 lines
56 KiB
Python
Executable file
1310 lines
56 KiB
Python
Executable file
#!/usr/bin/python3 -u
|
|
'''GNOME settings daemon tests for power plugin.'''
|
|
|
|
__author__ = 'Martin Pitt <martin.pitt@ubuntu.com>'
|
|
__copyright__ = '(C) 2013 Canonical Ltd.'
|
|
__license__ = 'GPL v2 or later'
|
|
|
|
import unittest
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import math
|
|
import os
|
|
import os.path
|
|
import signal
|
|
|
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
builddir = os.environ.get('BUILDDIR', os.path.dirname(__file__))
|
|
|
|
sys.path.insert(0, os.path.join(project_root, 'tests'))
|
|
sys.path.insert(0, builddir)
|
|
import gsdtestcase
|
|
import gsdpowerconstants
|
|
import gsdpowerenums
|
|
from output_checker import OutputChecker
|
|
|
|
import dbus
|
|
from dbus.mainloop.glib import DBusGMainLoop
|
|
|
|
DBusGMainLoop(set_as_default=True)
|
|
|
|
import gi
|
|
gi.require_version('UPowerGlib', '1.0')
|
|
gi.require_version('UMockdev', '1.0')
|
|
|
|
from gi.repository import Gio
|
|
from gi.repository import GLib
|
|
from gi.repository import UPowerGlib
|
|
from gi.repository import UMockdev
|
|
|
|
# There must be a better way to do a version comparison ... but this works
|
|
mutter_version = subprocess.run(['mutter', '--version'], stdout=subprocess.PIPE).stdout.decode().strip()
|
|
assert mutter_version.startswith('mutter ')
|
|
mutter_version = mutter_version[7:].split('.')
|
|
|
|
def mutter_at_least(version):
|
|
global mutter_version
|
|
version = version.split('.')
|
|
|
|
for i in range(max(len(mutter_version), len(version))):
|
|
m = mutter_version[i]
|
|
try:
|
|
m = int(m)
|
|
except:
|
|
pass
|
|
|
|
v = version[i]
|
|
try:
|
|
v = int(v)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
if m > v:
|
|
return True
|
|
elif m < v:
|
|
return False
|
|
except TypeError:
|
|
# String is smaller than integer
|
|
if isinstance(m, str):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
# assume equal
|
|
return True
|
|
|
|
class PowerPluginBase(gsdtestcase.GSDTestCase):
|
|
'''Test the power plugin'''
|
|
|
|
gsd_plugin = 'power'
|
|
gsd_plugin_case = 'Power'
|
|
|
|
COMMON_SUSPEND_METHODS=['Suspend', 'Hibernate', 'SuspendThenHibernate']
|
|
|
|
def setUp(self):
|
|
self.mock_external_monitor_file = os.path.join(self.workdir, 'GSD_MOCK_EXTERNAL_MONITOR')
|
|
os.environ['GSD_MOCK_EXTERNAL_MONITOR_FILE'] = self.mock_external_monitor_file
|
|
self.addCleanup(self.delete_external_monitor_file)
|
|
|
|
self.check_logind_gnome_session()
|
|
self.start_logind()
|
|
self.addCleanup(self.stop_logind)
|
|
|
|
# Setup umockdev testbed
|
|
self.testbed = UMockdev.Testbed.new()
|
|
self.addCleanup(self.cleanup_testbed)
|
|
os.environ['UMOCKDEV_DIR'] = self.testbed.get_root_dir()
|
|
|
|
# Create a mock backlight device
|
|
# Note that this function creates a different or even no backlight
|
|
# device based on the name of the test.
|
|
self.add_backlight()
|
|
|
|
if 'HAVE_SYSFS_BACKLIGHT' in os.environ and os.environ['HAVE_SYSFS_BACKLIGHT'] == '1':
|
|
self.skip_sysfs_backlight = False
|
|
else:
|
|
self.skip_sysfs_backlight = True
|
|
|
|
# start mock upowerd
|
|
(self.upowerd, self.obj_upower) = self.spawn_server_template(
|
|
'upower', {'DaemonVersion': '0.99', 'OnBattery': True, 'LidIsClosed': False})
|
|
self.addCleanup(self.stop_process, self.upowerd)
|
|
|
|
# start mock gnome-shell screensaver
|
|
(self.screensaver, self.obj_screensaver) = self.spawn_server_template(
|
|
'gnome_screensaver')
|
|
self.addCleanup(self.stop_process, self.screensaver)
|
|
|
|
# start mock power-profiles-daemon
|
|
try:
|
|
(self.ppd, self.obj_ppd) = self.spawn_server_template('upower_power_profiles_daemon')
|
|
self.addCleanup(self.stop_process, self.ppd)
|
|
except ModuleNotFoundError:
|
|
self.ppd = None
|
|
|
|
self.start_session()
|
|
self.addCleanup(self.stop_session)
|
|
|
|
self.obj_session_mgr = self.session_bus_con.get_object(
|
|
'org.gnome.SessionManager', '/org/gnome/SessionManager')
|
|
|
|
self.start_mutter()
|
|
self.addCleanup(self.stop_mutter)
|
|
|
|
# Set up the gnome-session presence
|
|
obj_session_presence = self.session_bus_con.get_object(
|
|
'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence')
|
|
self.obj_session_presence_props = dbus.Interface(obj_session_presence, dbus.PROPERTIES_IFACE)
|
|
|
|
# ensure that our tests don't lock the screen when the screensaver
|
|
# gets active
|
|
self.settings_screensaver = Gio.Settings(schema_id='org.gnome.desktop.screensaver')
|
|
self.addCleanup(self.reset_settings, self.settings_screensaver)
|
|
self.settings_screensaver['lock-enabled'] = False
|
|
|
|
# Ensure we set up the external monitor state
|
|
self.set_has_external_monitor(False)
|
|
|
|
self.settings_gsd_power = Gio.Settings(schema_id='org.gnome.settings-daemon.plugins.power')
|
|
self.addCleanup(self.reset_settings, self.settings_gsd_power)
|
|
|
|
Gio.Settings.sync()
|
|
# avoid painfully long delays of actions for tests
|
|
env = os.environ.copy()
|
|
# Disable PulseAudio output from libcanberra
|
|
env['CANBERRA_DRIVER'] = 'null'
|
|
|
|
# Use dummy script as testing backlight helper
|
|
env['GSD_BACKLIGHT_HELPER'] = os.path.join (project_root, 'plugins', 'power', 'test-backlight-helper')
|
|
if 'POWER_LD_PRELOAD' in env:
|
|
if 'LD_PRELOAD' in env and env['LD_PRELOAD']:
|
|
env['LD_PRELOAD'] = ':'.join((env['POWER_LD_PRELOAD'], env['LD_PRELOAD']))
|
|
else:
|
|
env['LD_PRELOAD'] = env['POWER_LD_PRELOAD']
|
|
|
|
self.start_plugin(env)
|
|
self.addCleanup(self.stop_plugin)
|
|
|
|
# Store the early-init messages, some tests need them.
|
|
self.plugin_startup_msgs = self.plugin_log.check_line(b'System inhibitor fd is', timeout=10)
|
|
|
|
# always start with zero idle time
|
|
self.reset_idle_timer()
|
|
|
|
self.p_notify_log.clear()
|
|
|
|
def cleanup_testbed(self):
|
|
del self.testbed
|
|
|
|
def delete_external_monitor_file(self):
|
|
try:
|
|
os.unlink(self.mock_external_monitor_file)
|
|
except OSError:
|
|
pass
|
|
|
|
def check_logind_gnome_session(self):
|
|
'''Check that gnome-session is built with logind support'''
|
|
|
|
path = GLib.find_program_in_path ('gnome-session')
|
|
assert(path)
|
|
(success, data) = GLib.file_get_contents (path)
|
|
lines = data.split(b'\n')
|
|
new_path = None
|
|
for line in lines:
|
|
items = line.split()
|
|
if items and items[0] == b'exec':
|
|
new_path = items[1]
|
|
if not new_path:
|
|
self.fail("could not get gnome-session's real path from %s" % path)
|
|
path = new_path
|
|
ldd = subprocess.Popen(['ldd', path], stdout=subprocess.PIPE)
|
|
out = ldd.communicate()[0]
|
|
if not b'libsystemd.so.0' in out:
|
|
self.fail('gnome-session is not built with logind support')
|
|
|
|
def get_status(self):
|
|
return self.obj_session_presence_props.Get('org.gnome.SessionManager.Presence', 'status')
|
|
|
|
def backlight_defaults(self):
|
|
# Hack to modify the brightness defaults before starting gsd-power.
|
|
# The alternative would be to create two separate test files.
|
|
if 'no_backlight' in self.id():
|
|
return None, None
|
|
elif 'legacy_brightness' in self.id():
|
|
return 15, 15
|
|
else:
|
|
return 100, 50
|
|
|
|
def add_backlight(self, _type="raw"):
|
|
max_brightness, brightness = self.backlight_defaults()
|
|
|
|
if max_brightness is None:
|
|
self.backlight = None
|
|
return
|
|
|
|
# Undo mangling done in GSD
|
|
if max_brightness >= 99:
|
|
max_brightness += 1
|
|
brightness += 1
|
|
|
|
# This needs to be done before starting gsd-power!
|
|
self.backlight = self.testbed.add_device('backlight', 'mock_backlight', None,
|
|
['type', _type,
|
|
'max_brightness', str(max_brightness),
|
|
'brightness', str(brightness)],
|
|
[])
|
|
|
|
def get_brightness(self):
|
|
max_brightness = int(open(os.path.join(self.testbed.get_root_dir() + self.backlight, 'max_brightness')).read())
|
|
|
|
# self.backlight contains the leading slash, so os.path.join doesn't quite work
|
|
res = int(open(os.path.join(self.testbed.get_root_dir() + self.backlight, 'brightness')).read())
|
|
# Undo mangling done in GSD
|
|
if max_brightness >= 99:
|
|
res -= 1
|
|
return res
|
|
|
|
def set_has_external_monitor(self, external):
|
|
if external:
|
|
val = b'1'
|
|
else:
|
|
val = b'0'
|
|
GLib.file_set_contents (self.mock_external_monitor_file, val)
|
|
|
|
def set_composite_battery_discharging(self, icon='battery-good-symbolic'):
|
|
self.obj_upower.SetupDisplayDevice(
|
|
UPowerGlib.DeviceKind.BATTERY,
|
|
UPowerGlib.DeviceState.DISCHARGING,
|
|
50., 50., 100., # 50%, charge 50 of 100
|
|
0.01, 600, 0, # Discharge rate 0.01 with 600 seconds remaining, 0 time to full
|
|
True, # present
|
|
icon, UPowerGlib.DeviceLevel.NONE
|
|
)
|
|
|
|
def set_composite_battery_critical(self, icon='battery-caution-symbolic'):
|
|
self.obj_upower.SetupDisplayDevice(
|
|
UPowerGlib.DeviceKind.BATTERY,
|
|
UPowerGlib.DeviceState.DISCHARGING,
|
|
2., 2., 100., # 2%, charge 2 of 100
|
|
0.01, 60, 0, # Discharge rate 0.01 with 60 seconds remaining, 0 time to full
|
|
True, # present
|
|
icon, UPowerGlib.DeviceLevel.CRITICAL
|
|
)
|
|
|
|
def check_for_logout(self, timeout):
|
|
'''Check that logout is requested.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
self.session_log.check_line(b'GsmManager: requesting logout', timeout)
|
|
|
|
def check_no_logout(self, seconds):
|
|
'''Check that no logout is requested in the given time'''
|
|
|
|
# wait for specified time to ensure it didn't do anything
|
|
self.session_log.check_no_line(b'GsmManager: requesting logout', seconds)
|
|
|
|
def check_for_suspend(self, timeout, methods=COMMON_SUSPEND_METHODS):
|
|
'''Check that one of the given suspend methods are requested. Default
|
|
methods are Suspend() or Hibernate() but also HibernateThenSuspend()
|
|
is valid.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
|
|
needle = r'|'.join(' {} '.format(m) for m in methods)
|
|
|
|
self.logind_log.check_line_re(needle, timeout,
|
|
failmsg='timed out waiting for logind suspend call, methods: %s' % ', '.join(methods))
|
|
|
|
def check_for_lid_inhibited(self, timeout=0):
|
|
'''Check that the lid inhibitor has been added.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
self.check_plugin_log('Adding lid switch system inhibitor', timeout,
|
|
'Timed out waiting for lid inhibitor')
|
|
|
|
def check_for_lid_uninhibited(self, timeout=0):
|
|
'''Check that the lid inhibitor has been dropped.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
self.check_plugin_log('uninhibiting lid close', timeout,
|
|
'Timed out waiting for lid uninhibition')
|
|
|
|
def check_no_lid_uninhibited(self, timeout=0):
|
|
'''Check that the lid inhibitor has been dropped.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
self.plugin_log.check_no_line(b'uninhibiting lid close', wait=timeout)
|
|
|
|
def check_no_suspend(self, seconds, methods=COMMON_SUSPEND_METHODS):
|
|
'''Check that no Suspend or Hibernate is requested in the given time'''
|
|
|
|
needle = r'|'.join(' {} '.format(m) for m in methods)
|
|
|
|
self.logind_log.check_no_line_re(needle, wait=seconds)
|
|
|
|
def check_suspend_no_hibernate(self, seconds):
|
|
'''Check that Suspend was requested and not Hibernate, in the given time'''
|
|
|
|
lines = self.logind_log.check_no_line(b' Hibernate', wait=seconds)
|
|
# Check that we did suspend
|
|
for l in lines:
|
|
if b' Suspend' in l:
|
|
break
|
|
else:
|
|
self.fail('Missing Suspend request')
|
|
|
|
def check_plugin_log(self, needle, timeout=0, failmsg=None):
|
|
'''Check that needle is found in the log within the given timeout.
|
|
Returns immediately when found.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
self.plugin_log.check_line(needle, timeout=timeout, failmsg=failmsg)
|
|
|
|
def check_no_dim(self, seconds):
|
|
'''Check that mode is not set to dim in the given time'''
|
|
|
|
# wait for specified time to ensure it didn't do anything
|
|
self.plugin_log.check_no_line(b'Doing a state transition: dim', wait=seconds)
|
|
|
|
def check_dim(self, timeout):
|
|
'''Check that mode is set to dim in the given time'''
|
|
|
|
self.check_plugin_log('Doing a state transition: dim', timeout,
|
|
'timed out waiting for dim')
|
|
|
|
def check_undim(self, timeout):
|
|
'''Check that mode is set to normal in the given time'''
|
|
|
|
self.check_plugin_log('Doing a state transition: normal', timeout,
|
|
'timed out waiting for normal mode')
|
|
|
|
def check_blank(self, timeout):
|
|
'''Check that blank is requested.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
|
|
self.check_plugin_log('TESTSUITE: Blanked screen', timeout,
|
|
'timed out waiting for blank')
|
|
|
|
def check_unblank(self, timeout):
|
|
'''Check that unblank is requested.
|
|
|
|
Fail after the given timeout.
|
|
'''
|
|
|
|
self.check_plugin_log('TESTSUITE: Unblanked screen', timeout,
|
|
'timed out waiting for unblank')
|
|
|
|
def check_no_blank(self, seconds):
|
|
'''Check that no blank is requested in the given time'''
|
|
|
|
self.plugin_log.check_no_line(b'TESTSUITE: Blanked screen', wait=seconds)
|
|
|
|
def check_no_unblank(self, seconds):
|
|
'''Check that no unblank is requested in the given time'''
|
|
|
|
self.plugin_log.check_no_line(b'TESTSUITE: Unblanked screen', wait=seconds)
|
|
|
|
class PowerPluginTestScreensaver(PowerPluginBase):
|
|
def test_screensaver(self):
|
|
# Note that the screensaver mock object
|
|
# doesn't know how to get out of being active,
|
|
# be it if the lock is disabled, or not.
|
|
|
|
self.obj_screensaver.Lock()
|
|
# 0.3 second animation
|
|
time.sleep(1)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# blank is supposed to happen straight away
|
|
self.check_blank(2)
|
|
|
|
# Wait a bit for the active watch to be registered through dbus, then
|
|
# fake user activity and check that the screen is unblanked.
|
|
time.sleep(0.5)
|
|
self.reset_idle_timer()
|
|
self.check_unblank(2)
|
|
|
|
# Check for no blank before the normal blank timeout
|
|
self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# and check for blank after the blank timeout
|
|
self.check_blank(10)
|
|
|
|
# Wait a bit for the active watch to be registered through dbus, then
|
|
# fake user activity and check that the screen is unblanked.
|
|
time.sleep(0.5)
|
|
self.reset_idle_timer()
|
|
self.check_unblank(2)
|
|
|
|
# check no blank and then blank
|
|
self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
self.check_blank(10)
|
|
|
|
def test_sleep_inactive_blank(self):
|
|
'''screensaver/blank interaction'''
|
|
|
|
# create suspend inhibitor which should have no effect on the idle
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
self.obj_screensaver.SetActive(True)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# blank is supposed to happen straight away
|
|
self.check_blank(2)
|
|
|
|
# Wait a bit for the active watch to be registered through dbus, then
|
|
# fake user activity and check that the screen is unblanked.
|
|
time.sleep(0.5)
|
|
self.reset_idle_timer()
|
|
self.check_unblank(2)
|
|
if not self.skip_sysfs_backlight:
|
|
self.assertTrue(self.get_brightness() == gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS , 'incorrect unblanked brightness (%d != %d)' % (self.get_brightness(), gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS))
|
|
|
|
# Check for no blank before the normal blank timeout
|
|
self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# and check for blank after the blank timeout
|
|
self.check_blank(10)
|
|
|
|
# Drop inhibitor
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
class PowerPluginTestScreensaverNoblank(PowerPluginBase):
|
|
def test_screensaver_no_unblank(self):
|
|
'''Ensure the screensaver is not unblanked for new inhibitors.'''
|
|
|
|
# Lower idle delay a lot
|
|
self.settings_session['idle-delay'] = 1
|
|
Gio.Settings.sync()
|
|
|
|
# Bring down the screensaver
|
|
self.obj_screensaver.SetActive(True)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# Check that we blank
|
|
self.check_blank(2)
|
|
|
|
# Create the different possible inhibitors
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE | gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND | gsdpowerenums.GSM_INHIBITOR_FLAG_LOGOUT),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
self.check_no_unblank(2)
|
|
|
|
# Drop inhibitor
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
self.check_no_unblank(2)
|
|
|
|
def test_session_idle_delay(self):
|
|
'''verify that session idle delay works as expected when changed'''
|
|
|
|
# Verify that idle is set after 5 seconds
|
|
self.settings_session['idle-delay'] = 5
|
|
Gio.Settings.sync()
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
time.sleep(7)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE)
|
|
|
|
# Raise the idle delay, and see that we stop being idle
|
|
# and get idle again after the timeout
|
|
self.settings_session['idle-delay'] = 10
|
|
Gio.Settings.sync()
|
|
# Resolve possible race condition, see also https://gitlab.gnome.org/GNOME/mutter/issues/113
|
|
time.sleep(0.2)
|
|
self.reset_idle_timer()
|
|
time.sleep(5)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
time.sleep(10)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE)
|
|
|
|
# Lower the delay again, and see that we get idle as we should
|
|
self.settings_session['idle-delay'] = 5
|
|
Gio.Settings.sync()
|
|
# Resolve possible race condition, see also https://gitlab.gnome.org/GNOME/mutter/issues/113
|
|
time.sleep(0.2)
|
|
self.reset_idle_timer()
|
|
time.sleep(2)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
time.sleep(5)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE)
|
|
|
|
def test_idle_time_reset_on_resume(self):
|
|
'''Check that the IDLETIME is reset when resuming'''
|
|
|
|
self.settings_screensaver['lock-enabled'] = False
|
|
|
|
# Go idle
|
|
self.settings_session['idle-delay'] = 5
|
|
Gio.Settings.sync()
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
time.sleep(7)
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE)
|
|
|
|
# Go to sleep
|
|
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True], dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# Wake up
|
|
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False], dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# And check we're not idle
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
|
|
class PowerPluginTestBattery(PowerPluginBase):
|
|
def test_sleep_inactive_battery(self):
|
|
'''sleep-inactive-battery-timeout'''
|
|
|
|
self.settings_session['idle-delay'] = 2
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend'
|
|
Gio.Settings.sync()
|
|
|
|
# wait for idle delay; should not yet suspend
|
|
self.check_no_suspend(2)
|
|
|
|
# suspend should happen after inactive sleep timeout + 1 s notification
|
|
# delay + 1 s error margin
|
|
self.check_for_suspend(7)
|
|
|
|
def _test_suspend_no_hibernate(self):
|
|
'''suspend-no-hibernate'''
|
|
|
|
self.settings_session['idle-delay'] = 2
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5
|
|
# Hibernate isn't possible, so it should end up suspending
|
|
# FIXME
|
|
self.settings_gsd_power['critical-battery-action'] = 'hibernate'
|
|
Gio.Settings.sync()
|
|
|
|
# wait for idle delay; should not yet hibernate
|
|
self.check_no_suspend(2)
|
|
|
|
# suspend should happen after inactive sleep timeout + 1 s notification
|
|
# delay + 1 s error margin
|
|
self.check_suspend_no_hibernate(7)
|
|
|
|
def test_sleep_inhibition(self):
|
|
'''Does not sleep under idle inhibition'''
|
|
|
|
idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend'
|
|
Gio.Settings.sync()
|
|
|
|
# create inhibitor
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE | gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
self.check_no_suspend(idle_delay + 2)
|
|
self.check_no_dim(0)
|
|
|
|
# Check that we didn't go to idle either
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
class PowerPluginTestLid(PowerPluginBase):
|
|
def test_lock_on_lid_close(self):
|
|
'''Check that we do lock on lid closing, if the machine will not suspend'''
|
|
|
|
self.settings_screensaver['lock-enabled'] = True
|
|
Gio.Settings.sync()
|
|
|
|
# create inhibitor
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
# Wait for startup inhibition to be gone
|
|
self.check_for_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 2)
|
|
|
|
# Close the lid
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check that we've blanked
|
|
time.sleep(2)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
self.check_blank(2)
|
|
|
|
# Drop the inhibit and see whether we suspend
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
# At this point logind should suspend for us
|
|
self.settings_screensaver['lock-enabled'] = False
|
|
Gio.Settings.sync()
|
|
|
|
def test_blank_on_lid_close(self):
|
|
'''Check that we do blank on lid closing, if the machine will not suspend'''
|
|
|
|
# create inhibitor
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
# Wait for startup inhibition to be gone
|
|
self.check_for_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 2)
|
|
|
|
# Close the lid
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check that we've blanked
|
|
self.check_blank(4)
|
|
|
|
# Drop the inhibit and see whether we suspend
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
# At this point logind should suspend for us
|
|
|
|
@unittest.skipIf(not mutter_at_least('42.0'), reason="mutter is too old and may be buggy")
|
|
def test_unblank_on_lid_open(self):
|
|
'''Check that we do unblank on lid opening, if the machine will not suspend'''
|
|
|
|
# create inhibitor
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
# Wait for startup inhibition to be gone
|
|
self.check_for_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 2)
|
|
|
|
# Close the lid
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check that we've blanked
|
|
self.check_blank(2)
|
|
|
|
# Reopen the lid
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', False)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check for unblanking
|
|
self.check_unblank(2)
|
|
|
|
# Drop the inhibit
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
class PowerPluginTestDim(PowerPluginBase):
|
|
def test_dim(self):
|
|
'''Check that we do go to dim'''
|
|
|
|
# Wait for startup inhibition to be gone
|
|
self.check_for_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 2)
|
|
|
|
idle_delay = math.ceil(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
self.reset_idle_timer()
|
|
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend'
|
|
Gio.Settings.sync()
|
|
# This is an absolute percentage, and our brightness is 0..100
|
|
dim_level = self.settings_gsd_power['idle-brightness'];
|
|
|
|
# Check that we're not idle
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
|
|
# Wait and check we're not idle, but dimmed
|
|
self.check_dim(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY + 1)
|
|
# Give time for the brightness to change
|
|
time.sleep(2)
|
|
if not self.skip_sysfs_backlight:
|
|
level = self.get_brightness();
|
|
self.assertTrue(level == dim_level, 'incorrect dim brightness (%d != %d)' % (level, dim_level))
|
|
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
|
|
# Bring down the screensaver
|
|
self.obj_screensaver.SetActive(True)
|
|
self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on')
|
|
|
|
# Check that we blank
|
|
self.check_blank(2)
|
|
|
|
# Go to sleep
|
|
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True], dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# Wake up
|
|
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False], dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# And check that we have the pre-dim brightness
|
|
if not self.skip_sysfs_backlight:
|
|
self.assertTrue(self.get_brightness() == gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS , 'incorrect unblanked brightness (%d != %d)' % (self.get_brightness(), gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS))
|
|
|
|
def test_lid_close_inhibition(self):
|
|
'''Check that we correctly inhibit suspend with an external monitor'''
|
|
|
|
# Wait for startup inhibition to be gone
|
|
self.check_for_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 2)
|
|
|
|
# Add an external monitor
|
|
self.set_has_external_monitor(True)
|
|
self.check_for_lid_inhibited(1)
|
|
|
|
# Check that we do not uninhibit with the external monitor attached
|
|
self.check_no_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 1)
|
|
|
|
# Close the lid
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(0.5)
|
|
|
|
# Unplug the external monitor
|
|
self.set_has_external_monitor(False)
|
|
|
|
# Check that no action happens during the safety time minus 1 second
|
|
self.check_no_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT - 1)
|
|
# Check that we're uninhibited after the safety time
|
|
self.check_for_lid_uninhibited(4)
|
|
|
|
class PowerPluginTestBatteryLevels(PowerPluginBase):
|
|
def test_notify_critical_battery(self):
|
|
'''action on critical battery'''
|
|
|
|
self.set_composite_battery_discharging()
|
|
|
|
time.sleep(2)
|
|
|
|
self.set_composite_battery_critical()
|
|
|
|
# Check that it was picked up
|
|
self.check_plugin_log('EMIT: charge-critical', 2)
|
|
|
|
self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* "" ".*[Bb]attery [Aa]lmost [Ee]mpty.*"', timeout=0.5)
|
|
|
|
def test_notify_critical_battery_on_start(self):
|
|
'''action on critical battery on startup'''
|
|
|
|
self.set_composite_battery_critical()
|
|
|
|
# Check that it was picked up
|
|
self.check_plugin_log('EMIT: charge-critical', 2)
|
|
|
|
self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* "" ".*[Bb]attery [Aa]lmost [Ee]mpty.*"', timeout=0.5)
|
|
|
|
def test_notify_device_battery(self):
|
|
'''critical power level notification for device batteries'''
|
|
|
|
# Set internal battery to discharging
|
|
self.set_composite_battery_discharging()
|
|
|
|
# Add a device battery
|
|
bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1'
|
|
self.obj_upower.AddObject(bat2_path,
|
|
'org.freedesktop.UPower.Device',
|
|
{
|
|
'PowerSupply': dbus.Boolean(False, variant_level=1),
|
|
'IsPresent': dbus.Boolean(True, variant_level=1),
|
|
'Model': dbus.String('Bat1', variant_level=1),
|
|
'Percentage': dbus.Double(40.0, variant_level=1),
|
|
'TimeToEmpty': dbus.Int64(1600, variant_level=1),
|
|
'EnergyFull': dbus.Double(100.0, variant_level=1),
|
|
'Energy': dbus.Double(40.0, variant_level=1),
|
|
'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1),
|
|
'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1),
|
|
'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.NONE, variant_level=1),
|
|
}, dbus.Array([], signature='(ssss)'))
|
|
|
|
obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path)
|
|
self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# now change the mouse battery to critical charge
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'TimeToEmpty',
|
|
dbus.Int64(30, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'Energy',
|
|
dbus.Double(0.5, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'WarningLevel',
|
|
dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
self.obj_upower.EmitSignal('', 'DeviceChanged', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
self.check_plugin_log('EMIT: charge-critical', 2)
|
|
|
|
self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*\([0-9.]+%\).*"', timeout=0.5)
|
|
|
|
def test_notify_device_spam(self):
|
|
'''no repeat notifications for device batteries'''
|
|
|
|
# Set internal battery to discharging
|
|
self.set_composite_battery_discharging()
|
|
|
|
# Add a device battery
|
|
bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1'
|
|
self.obj_upower.AddObject(bat2_path,
|
|
'org.freedesktop.UPower.Device',
|
|
{
|
|
'PowerSupply': dbus.Boolean(False, variant_level=1),
|
|
'IsPresent': dbus.Boolean(True, variant_level=1),
|
|
'Model': dbus.String('Bat1', variant_level=1),
|
|
'Serial': dbus.String('12345678', variant_level=1),
|
|
'Percentage': dbus.Double(10.0, variant_level=1),
|
|
'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1),
|
|
'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1),
|
|
'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1),
|
|
}, dbus.Array([], signature='(ssss)'))
|
|
|
|
obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path)
|
|
self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
self.check_plugin_log('EMIT: charge-low', 2)
|
|
|
|
self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*\([0-9.]+%\).*"', timeout=0.5)
|
|
|
|
# Disconnect mouse
|
|
self.obj_upower.RemoveObject(bat2_path)
|
|
time.sleep(0.5)
|
|
|
|
# Reconnect mouse
|
|
self.obj_upower.AddObject(bat2_path,
|
|
'org.freedesktop.UPower.Device',
|
|
{
|
|
'PowerSupply': dbus.Boolean(False, variant_level=1),
|
|
'IsPresent': dbus.Boolean(True, variant_level=1),
|
|
'Model': dbus.String('Bat1', variant_level=1),
|
|
'Serial': dbus.String('12345678', variant_level=1),
|
|
'Percentage': dbus.Double(10.0, variant_level=1),
|
|
'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1),
|
|
'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1),
|
|
'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1),
|
|
}, dbus.Array([], signature='(ssss)'))
|
|
|
|
obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path)
|
|
self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
self.p_notify_log.check_no_line(b'', wait=1)
|
|
|
|
# Disconnect mouse
|
|
self.obj_upower.RemoveObject(bat2_path)
|
|
time.sleep(0.5)
|
|
|
|
# Reconnect mouse with critical battery level
|
|
self.obj_upower.AddObject(bat2_path,
|
|
'org.freedesktop.UPower.Device',
|
|
{
|
|
'PowerSupply': dbus.Boolean(False, variant_level=1),
|
|
'IsPresent': dbus.Boolean(True, variant_level=1),
|
|
'Model': dbus.String('Bat1', variant_level=1),
|
|
'Serial': dbus.String('12345678', variant_level=1),
|
|
'Percentage': dbus.Double(5.0, variant_level=1),
|
|
'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1),
|
|
'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1),
|
|
'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1),
|
|
}, dbus.Array([], signature='(ssss)'))
|
|
|
|
obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path)
|
|
self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# Verify new warning
|
|
self.check_plugin_log('EMIT: charge-critical', 2)
|
|
|
|
self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*very low.* power.*\([0-9.]+%\).*"', timeout=0.5)
|
|
|
|
def test_notify_device_battery_coarse_level(self):
|
|
'''critical power level notification for device batteries with coarse level'''
|
|
|
|
# Set internal battery to discharging
|
|
self.set_composite_battery_discharging()
|
|
|
|
# Add a device battery
|
|
bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1'
|
|
self.obj_upower.AddObject(bat2_path,
|
|
'org.freedesktop.UPower.Device',
|
|
{
|
|
'PowerSupply': dbus.Boolean(False, variant_level=1),
|
|
'IsPresent': dbus.Boolean(True, variant_level=1),
|
|
'Model': dbus.String('Bat1', variant_level=1),
|
|
'Percentage': dbus.Double(40.0, variant_level=1),
|
|
'BatteryLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1),
|
|
'TimeToEmpty': dbus.Int64(1600, variant_level=1),
|
|
'EnergyFull': dbus.Double(100.0, variant_level=1),
|
|
'Energy': dbus.Double(40.0, variant_level=1),
|
|
'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1),
|
|
'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1),
|
|
'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.NONE, variant_level=1),
|
|
}, dbus.Array([], signature='(ssss)'))
|
|
|
|
obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path)
|
|
self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
time.sleep(1)
|
|
|
|
# now change the mouse battery to critical charge
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'TimeToEmpty',
|
|
dbus.Int64(30, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'Energy',
|
|
dbus.Double(0.5, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.Set('org.freedesktop.UPower.Device', 'WarningLevel',
|
|
dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1),
|
|
dbus_interface=dbus.PROPERTIES_IFACE)
|
|
obj_bat2.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
self.obj_upower.EmitSignal('', 'DeviceChanged', 'o', [bat2_path],
|
|
dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
self.check_plugin_log('EMIT: charge-critical', 2)
|
|
|
|
time.sleep(0.5)
|
|
lines = self.p_notify_log.check_line_re(rb'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*"')
|
|
lines += self.p_notify_log.clear()
|
|
for l in lines:
|
|
self.assertNotRegex(l, rb'[0-9.]+ Notify "Power" .* ".*" ".*\([0-9.]+%\).*"')
|
|
|
|
def test_forced_logout(self):
|
|
'''Test forced logout'''
|
|
|
|
self.plugin_death_expected = True
|
|
idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'logout'
|
|
Gio.Settings.sync()
|
|
|
|
self.check_for_logout(idle_delay + 2)
|
|
|
|
self.p_notify_log.check_line(b'You will soon log out because of inactivity')
|
|
|
|
def test_forced_logout_inhibition(self):
|
|
'''Test we don't force logout when inhibited'''
|
|
|
|
idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'logout'
|
|
Gio.Settings.sync()
|
|
|
|
# create suspend inhibitor which should stop us logging out
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_LOGOUT),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
self.check_no_logout(idle_delay + 3)
|
|
|
|
# Drop inhibitor
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
class PowerPluginTestBrightness(PowerPluginBase):
|
|
def test_check_missing_kbd_brightness(self):
|
|
''' https://bugzilla.gnome.org/show_bug.cgi?id=793512 '''
|
|
|
|
obj_gsd_power_kbd = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_kbd_props = dbus.Interface(obj_gsd_power_kbd, dbus.PROPERTIES_IFACE)
|
|
|
|
# Will return -1 if gsd-power crashed, and an exception if the code caught the problem
|
|
with self.assertRaises(dbus.DBusException) as exc:
|
|
kbd_brightness = obj_gsd_power_kbd_props.Get('org.gnome.SettingsDaemon.Power.Keyboard', 'Brightness')
|
|
|
|
# We should not have arrived here, if we did then the test failed, let's print this to help debugging
|
|
print('Got keyboard brightness: {}'.format(kbd_brightness))
|
|
|
|
self.assertEqual(exc.exception.get_dbus_message(), 'Failed to get property Brightness on interface org.gnome.SettingsDaemon.Power.Keyboard')
|
|
|
|
def test_inhibitor_idletime(self):
|
|
''' https://bugzilla.gnome.org/show_bug.cgi?id=705942 '''
|
|
|
|
idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5
|
|
self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend'
|
|
Gio.Settings.sync()
|
|
|
|
# create inhibitor
|
|
inhibit_id = self.obj_session_mgr.Inhibit(
|
|
'testsuite', dbus.UInt32(0), 'for testing',
|
|
dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
self.check_no_suspend(idle_delay + 2)
|
|
self.check_no_dim(0)
|
|
|
|
# Check that we didn't go to idle either
|
|
self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE)
|
|
|
|
self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id),
|
|
dbus_interface='org.gnome.SessionManager')
|
|
|
|
self.check_no_suspend(2)
|
|
self.check_no_dim(0)
|
|
|
|
time.sleep(5)
|
|
|
|
self.check_suspend_no_hibernate(7)
|
|
|
|
def disabled_test_unindle_on_ac_plug(self):
|
|
idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER)
|
|
self.settings_session['idle-delay'] = idle_delay
|
|
Gio.Settings.sync()
|
|
|
|
# Wait for idle
|
|
self.check_dim(idle_delay + 2)
|
|
|
|
# Plug in the AC
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'OnBattery', False)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check that we undim
|
|
self.check_undim(gsdpowerconstants.POWER_UP_TIME_ON_AC / 2)
|
|
|
|
# And wait a little more to see us dim again
|
|
self.check_dim(idle_delay + 2)
|
|
|
|
# Unplug the AC
|
|
self.obj_upower.Set('org.freedesktop.UPower', 'OnBattery', True)
|
|
self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
|
|
|
|
# Check that we undim
|
|
self.check_undim(gsdpowerconstants.POWER_UP_TIME_ON_AC / 2)
|
|
|
|
# And wait a little more to see us dim again
|
|
self.check_dim(idle_delay + 2)
|
|
|
|
class PowerPluginTestBrightnessStep(PowerPluginBase):
|
|
def test_brightness_stepping(self):
|
|
'''Check that stepping the backlight works as expected'''
|
|
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
obj_gsd_power = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_screen_iface = dbus.Interface(obj_gsd_power, 'org.gnome.SettingsDaemon.Power.Screen')
|
|
|
|
# Each of the step calls will only return when the value was written
|
|
start = time.time()
|
|
# We start at 50% and step by 5% each time
|
|
obj_gsd_power_screen_iface.StepUp()
|
|
self.assertEqual(self.get_brightness(), 55)
|
|
obj_gsd_power_screen_iface.StepUp()
|
|
self.assertEqual(self.get_brightness(), 60)
|
|
obj_gsd_power_screen_iface.StepUp()
|
|
self.assertEqual(self.get_brightness(), 65)
|
|
obj_gsd_power_screen_iface.StepUp()
|
|
self.assertEqual(self.get_brightness(), 70)
|
|
stop = time.time()
|
|
# This needs to take more than 0.8 seconds as each write is delayed by
|
|
# 0.2 seconds by the test backlight helper
|
|
self.assertGreater(stop - start, 0.8)
|
|
|
|
# Now, the same thing should work fine if we step multiple times,
|
|
# even if we are so quick that compression will happen.
|
|
# Use a list to keep rack of replies (as integer is immutable and would
|
|
# not be modified in the outer scope)
|
|
replies = [0]
|
|
|
|
def handle_reply(*args):
|
|
replies[0] += 1
|
|
|
|
def last_reply(*args):
|
|
replies[0] += 1
|
|
loop.quit()
|
|
|
|
def error_handler(*args):
|
|
loop.quit()
|
|
|
|
start = time.time()
|
|
obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler)
|
|
obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler)
|
|
obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler)
|
|
obj_gsd_power_screen_iface.StepDown(reply_handler=last_reply, error_handler=error_handler)
|
|
loop = GLib.MainLoop()
|
|
loop.run()
|
|
stop = time.time()
|
|
|
|
# The calls need to be returned in order. As we got the last reply, all
|
|
# others must have been received too.
|
|
self.assertEqual(replies[0], 4)
|
|
# Four steps down, so back at 50%
|
|
self.assertEqual(self.get_brightness(), 50)
|
|
# And compression must have happened, so it should take less than 0.8s
|
|
self.assertLess(stop - start, 0.8)
|
|
|
|
def test_brightness_compression(self):
|
|
'''Check that compression also happens when setting the property'''
|
|
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
# Now test that the compression works correctly.
|
|
# NOTE: Relies on the implementation detail, that the property setter
|
|
# returns immediately rather than waiting for the brightness to
|
|
# be updated.
|
|
# Should this ever be fixed, then this will need to be changed to use
|
|
# async dbus calls similar to the stepping code
|
|
|
|
obj_gsd_power = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE)
|
|
|
|
# Quickly ramp the brightness up
|
|
for brightness in range(70, 91):
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', brightness)
|
|
|
|
# The brightness of 80 should be in effect after slightly more than
|
|
# 0.4 seconds. If compression does not work as expected, this would take
|
|
# more than 5 seconds for the 20 steps.
|
|
time.sleep(2.0)
|
|
self.assertEqual(self.get_brightness(), 90)
|
|
|
|
def test_brightness_uevent(self):
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
obj_gsd_power = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE)
|
|
|
|
brightness = obj_gsd_power_prop_iface.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness')
|
|
self.assertEqual(50, brightness)
|
|
|
|
# Check that the brightness is updated if it was changed through some
|
|
# other mechanism (e.g. firmware).
|
|
# Set to 80+1 because of the GSD offset (see add_backlight).
|
|
self.testbed.set_attribute(self.backlight, 'brightness', '81')
|
|
self.testbed.uevent(self.backlight, 'change')
|
|
|
|
self.check_plugin_log('GsdBacklight: Got uevent', 1, 'gsd-power did not process uevent')
|
|
time.sleep(0.2)
|
|
|
|
brightness = obj_gsd_power_prop_iface.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness')
|
|
self.assertEqual(80, brightness)
|
|
|
|
def test_brightness_step(self):
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
for l in self.plugin_startup_msgs:
|
|
if b'Step size for backlight is 5.' in l:
|
|
break
|
|
else:
|
|
self.fail('Step size is not 5')
|
|
|
|
def test_legacy_brightness_step(self):
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
for l in self.plugin_startup_msgs:
|
|
if b'Step size for backlight is 1.' in l:
|
|
break
|
|
else:
|
|
self.fail('Step size is not 1')
|
|
|
|
def test_legacy_brightness_rounding(self):
|
|
if self.skip_sysfs_backlight:
|
|
self.skipTest("sysfs backlight support required for test")
|
|
|
|
obj_gsd_power = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE)
|
|
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 0)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 0)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 10)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 2)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 20)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 3)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 25)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 4)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 49)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 7)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 50)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 8)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 56)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 8)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 57)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 9)
|
|
obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 98)
|
|
time.sleep(0.6)
|
|
self.assertEqual(self.get_brightness(), 15)
|
|
|
|
def test_no_backlight(self):
|
|
'''Check that backlight brightness DBus api without a backlight'''
|
|
|
|
obj_gsd_power = self.session_bus_con.get_object(
|
|
'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power')
|
|
obj_gsd_power_props = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE)
|
|
obj_gsd_power_screen = dbus.Interface(obj_gsd_power, 'org.gnome.SettingsDaemon.Power.Screen')
|
|
|
|
# We expect -1 to be returned
|
|
brightness = obj_gsd_power_props.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness')
|
|
self.assertEqual(brightness, -1)
|
|
|
|
# Trying to set the brightness
|
|
with self.assertRaises(dbus.DBusException) as exc:
|
|
obj_gsd_power_props.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 1)
|
|
|
|
self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!')
|
|
|
|
with self.assertRaises(dbus.DBusException) as exc:
|
|
obj_gsd_power_screen.StepUp()
|
|
|
|
self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!')
|
|
|
|
with self.assertRaises(dbus.DBusException) as exc:
|
|
obj_gsd_power_screen.StepDown()
|
|
|
|
self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!')
|
|
|
|
def test_power_saver_on_low_battery(self):
|
|
'''Check that the power-saver profile gets held when low on battery'''
|
|
|
|
if not self.ppd:
|
|
self.skipTest("power-profiles-daemon dbusmock support is not available")
|
|
|
|
obj_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE)
|
|
|
|
self.set_composite_battery_discharging()
|
|
time.sleep(0.5)
|
|
holds = obj_props.Get('org.freedesktop.UPower.PowerProfiles', 'ActiveProfileHolds')
|
|
self.assertEqual(len(holds), 0)
|
|
|
|
self.set_composite_battery_critical()
|
|
time.sleep(0.5)
|
|
holds = obj_props.Get('org.freedesktop.UPower.PowerProfiles', 'ActiveProfileHolds')
|
|
self.assertEqual(len(holds), 1)
|
|
self.assertEqual(holds[0]['Profile'], 'power-saver')
|
|
self.assertEqual(holds[0]['ApplicationId'], 'org.gnome.SettingsDaemon.Power')
|
|
|
|
self.set_composite_battery_discharging()
|
|
time.sleep(0.5)
|
|
holds = obj_props.Get('org.freedesktop.UPower.PowerProfiles', 'ActiveProfileHolds')
|
|
self.assertEqual(len(holds), 0)
|
|
|
|
# avoid writing to stderr
|
|
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
|