2020-07-16 16:09:56 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
|
|
|
|
# power-profiles-daemon 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 <martin.pitt@ubuntu.com>
|
|
|
|
|
# (C) 2020 Bastien Nocera <hadess@hadess.net>
|
2021-03-11 14:32:30 +01:00
|
|
|
# (C) 2021 David Redondo <kde@david-redondo.de>
|
2020-07-16 16:09:56 +02:00
|
|
|
#
|
|
|
|
|
# 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 tempfile
|
|
|
|
|
import subprocess
|
|
|
|
|
import unittest
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
import gi
|
|
|
|
|
from gi.repository import GLib
|
|
|
|
|
from gi.repository import Gio
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
sys.stderr.write('Skipping tests, PyGobject not available for Python 3, or missing GI typelibs: %s\n' % str(e))
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
gi.require_version('UMockdev', '1.0')
|
|
|
|
|
from gi.repository import UMockdev
|
|
|
|
|
except ImportError:
|
|
|
|
|
sys.stderr.write('Skipping tests, umockdev not available (https://github.com/martinpitt/umockdev)\n')
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
import dbusmock
|
|
|
|
|
except ImportError:
|
|
|
|
|
sys.stderr.write('Skipping tests, python-dbusmock not available (http://pypi.python.org/pypi/python-dbusmock).\n')
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PP = 'net.hadess.PowerProfiles'
|
|
|
|
|
PP_PATH = '/net/hadess/PowerProfiles'
|
2021-03-11 14:32:30 +01:00
|
|
|
PP_INTERFACE = 'net.hadess.PowerProfiles'
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
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', 'power-profiles-daemon'), os.X_OK):
|
|
|
|
|
cls.daemon_path = os.path.join(builddir, 'src', 'power-profiles-daemon')
|
|
|
|
|
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', 'power-profiles-daemon')
|
|
|
|
|
print('Testing binaries from JHBuild (%s)' % cls.daemon_path)
|
|
|
|
|
else:
|
|
|
|
|
cls.daemon_path = None
|
|
|
|
|
with open('/usr/lib/systemd/system/power-profiles-daemon.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'
|
|
|
|
|
print('Testing installed system binary (%s)' % cls.daemon_path)
|
|
|
|
|
|
2020-09-15 11:31:25 +02:00
|
|
|
# fail on CRITICALs on client and server side
|
2020-07-16 16:09:56 +02:00
|
|
|
GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING |
|
|
|
|
|
GLib.LogLevelFlags.LEVEL_ERROR |
|
|
|
|
|
GLib.LogLevelFlags.LEVEL_CRITICAL)
|
2020-09-15 11:31:25 +02:00
|
|
|
os.environ['G_DEBUG'] = 'fatal_warnings'
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
# 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()
|
2021-09-28 17:19:40 +02:00
|
|
|
self.polkitd, self.obj_polkit = self.spawn_server_template(
|
2021-09-28 12:57:44 +02:00
|
|
|
'polkitd', {}, stdout=subprocess.PIPE)
|
2021-09-28 17:19:40 +02:00
|
|
|
self.obj_polkit.SetAllowed(['net.hadess.PowerProfiles.switch-profile',
|
|
|
|
|
'net.hadess.PowerProfiles.hold-profile'])
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
self.proxy = None
|
|
|
|
|
self.log = None
|
|
|
|
|
self.daemon = None
|
|
|
|
|
|
2020-10-28 17:34:53 +01:00
|
|
|
# Used for dytc devices
|
|
|
|
|
self.tp_acpi = None
|
|
|
|
|
|
2020-07-16 16:09:56 +02:00
|
|
|
def tearDown(self):
|
|
|
|
|
del self.testbed
|
|
|
|
|
self.stop_daemon()
|
2021-09-28 12:57:44 +02:00
|
|
|
|
|
|
|
|
if self.polkitd:
|
|
|
|
|
try:
|
|
|
|
|
self.polkitd.kill()
|
|
|
|
|
except OSError:
|
|
|
|
|
pass
|
|
|
|
|
self.polkitd.wait()
|
|
|
|
|
self.polkitd = None
|
2021-09-28 17:19:40 +02:00
|
|
|
self.obj_polkit = None
|
2021-09-28 12:57:44 +02:00
|
|
|
|
2020-10-28 17:34:53 +01:00
|
|
|
del self.tp_acpi
|
2021-07-05 17:08:35 +02:00
|
|
|
try:
|
2021-09-07 22:58:44 +02:00
|
|
|
os.remove(self.testbed.get_root_dir() + '/' + 'ppd_test_conf.ini')
|
2021-07-05 17:08:35 +02:00
|
|
|
except Exception:
|
|
|
|
|
pass
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
# 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):
|
|
|
|
|
'''Start daemon and create DBus proxy.
|
|
|
|
|
|
|
|
|
|
When done, this sets self.proxy as the Gio.DBusProxy for power-profiles-daemon.
|
|
|
|
|
'''
|
|
|
|
|
env = os.environ.copy()
|
|
|
|
|
env['G_DEBUG'] = 'fatal-criticals'
|
|
|
|
|
env['G_MESSAGES_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()
|
|
|
|
|
if os.getenv('VALGRIND') != None:
|
2020-11-04 17:06:13 +01:00
|
|
|
daemon_path = ['valgrind', self.daemon_path, '-v']
|
2020-07-16 16:09:56 +02:00
|
|
|
else:
|
|
|
|
|
daemon_path = [self.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
|
|
|
|
|
while timeout > 0:
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
timeout -= 1
|
|
|
|
|
try:
|
|
|
|
|
self.get_dbus_property('ActiveProfile')
|
|
|
|
|
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, PP,
|
|
|
|
|
PP_PATH, PP, None)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(self.daemon.poll(), None, 'daemon crashed')
|
|
|
|
|
|
|
|
|
|
def stop_daemon(self):
|
|
|
|
|
'''Stop the daemon if it is running.'''
|
|
|
|
|
|
|
|
|
|
if self.daemon:
|
|
|
|
|
try:
|
|
|
|
|
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, PP,
|
|
|
|
|
PP_PATH, 'org.freedesktop.DBus.Properties', None)
|
|
|
|
|
return proxy.Get('(ss)', PP, name)
|
|
|
|
|
|
|
|
|
|
def set_dbus_property(self, name, value):
|
|
|
|
|
'''Set property value on daemon D-Bus interface.'''
|
|
|
|
|
|
|
|
|
|
proxy = Gio.DBusProxy.new_sync(
|
|
|
|
|
self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, PP,
|
|
|
|
|
PP_PATH, 'org.freedesktop.DBus.Properties', None)
|
|
|
|
|
return proxy.Set('(ssv)', PP, name, value)
|
|
|
|
|
|
2021-03-11 14:32:30 +01:00
|
|
|
def call_dbus_method(self, name, parameters):
|
|
|
|
|
'''Call a method of the daemon D-Bus interface.'''
|
|
|
|
|
|
|
|
|
|
proxy = Gio.DBusProxy.new_sync(
|
|
|
|
|
self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, PP,
|
|
|
|
|
PP_PATH, PP_INTERFACE, None)
|
|
|
|
|
return proxy.call_sync(name, parameters, Gio.DBusCallFlags.NO_AUTO_START, -1, None)
|
|
|
|
|
|
|
|
|
|
|
2020-07-16 16:09:56 +02:00
|
|
|
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)
|
|
|
|
|
|
2021-03-19 13:12:47 +01:00
|
|
|
def read_sysfs_file(self, path):
|
|
|
|
|
with open(self.testbed.get_root_dir() + '/' + path, 'rb') as f:
|
|
|
|
|
return f.read().rstrip()
|
2020-07-20 16:48:07 +02:00
|
|
|
return None
|
|
|
|
|
|
2021-03-19 13:12:47 +01:00
|
|
|
def read_sysfs_attr(self, device, attribute):
|
|
|
|
|
return self.read_sysfs_file(device + '/' + attribute)
|
|
|
|
|
|
2022-02-12 23:13:06 +01:00
|
|
|
def get_mtime(self, device, attribute):
|
|
|
|
|
return os.path.getmtime(self.testbed.get_root_dir() + '/' + device + '/' + attribute)
|
|
|
|
|
|
2020-09-09 11:39:45 +02:00
|
|
|
def read_file(self, path):
|
|
|
|
|
with open(path, 'rb') as f:
|
|
|
|
|
return f.read()
|
|
|
|
|
return None
|
|
|
|
|
|
2020-10-28 17:34:53 +01:00
|
|
|
def create_dytc_device(self):
|
|
|
|
|
self.tp_acpi = self.testbed.add_device('platform', 'thinkpad_acpi', None,
|
2021-03-15 21:15:43 +01:00
|
|
|
['dytc_lapmode', '0\n'],
|
2020-10-28 17:34:53 +01:00
|
|
|
[ 'DEVPATH', '/devices/platform/thinkpad_acpi' ]
|
|
|
|
|
)
|
2021-02-08 15:25:11 +01:00
|
|
|
|
2021-07-05 18:14:31 +02:00
|
|
|
def create_empty_platform_profile(self):
|
|
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
|
|
|
|
os.makedirs(acpi_dir)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-07-05 18:14:31 +02:00
|
|
|
profile.write('\n')
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-07-05 18:14:31 +02:00
|
|
|
choices.write('\n')
|
|
|
|
|
|
2021-02-08 15:25:11 +01:00
|
|
|
def create_platform_profile(self):
|
2020-11-19 16:47:43 +01:00
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
|
|
|
|
os.makedirs(acpi_dir)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-03-15 19:27:19 +01:00
|
|
|
profile.write("performance\n")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-03-15 19:27:19 +01:00
|
|
|
choices.write("low-power balanced performance\n")
|
2020-10-28 17:34:53 +01:00
|
|
|
|
2021-07-05 17:08:35 +02:00
|
|
|
def remove_platform_profile(self):
|
|
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
|
|
|
|
os.remove(os.path.join(acpi_dir, "platform_profile_choices"))
|
|
|
|
|
os.remove(os.path.join(acpi_dir, "platform_profile"))
|
|
|
|
|
os.removedirs(acpi_dir)
|
|
|
|
|
|
2020-07-16 16:09:56 +02:00
|
|
|
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
|
|
|
|
|
#
|
2021-02-08 16:51:17 +01:00
|
|
|
def test_dbus_startup_error(self):
|
|
|
|
|
'''D-Bus startup error'''
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
2021-07-07 03:45:34 +00:00
|
|
|
out = subprocess.run([self.daemon_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
2021-02-08 16:51:17 +01:00
|
|
|
self.assertEqual(out.returncode, 1, "power-profile-daemon started but should have failed")
|
|
|
|
|
self.stop_daemon()
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
def test_no_performance_driver(self):
|
|
|
|
|
'''no performance driver'''
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceDegraded'), '')
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 2)
|
2021-03-18 17:46:27 +01:00
|
|
|
self.assertEqual(profiles[1]['Driver'], 'placeholder')
|
|
|
|
|
self.assertEqual(profiles[0]['Driver'], 'placeholder')
|
2020-08-05 14:47:03 +02:00
|
|
|
self.assertEqual(profiles[1]['Profile'], 'balanced')
|
|
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
2020-07-16 16:09:56 +02:00
|
|
|
|
2020-08-12 16:55:58 +02:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
2020-07-16 16:09:56 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
|
|
|
|
|
# process = subprocess.Popen(['gdbus', 'introspect', '--system', '--dest', 'net.hadess.PowerProfiles', '--object-path', '/net/hadess/PowerProfiles'])
|
|
|
|
|
# print (self.get_dbus_property('GPUs'))
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-04-02 12:07:50 +02:00
|
|
|
def test_inhibited_property(self):
|
|
|
|
|
'''Test that the inhibited property exists'''
|
|
|
|
|
|
|
|
|
|
self.create_dytc_device()
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceInhibited'), '')
|
|
|
|
|
|
|
|
|
|
def test_degraded_transition(self):
|
|
|
|
|
'''Test that transitions work as expected when degraded'''
|
2020-08-10 15:41:11 +02:00
|
|
|
|
2020-10-28 17:34:53 +01:00
|
|
|
self.create_dytc_device()
|
2021-02-08 15:25:11 +01:00
|
|
|
self.create_platform_profile()
|
2020-08-10 15:41:11 +02:00
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2021-07-05 17:04:46 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
2020-08-10 15:41:11 +02:00
|
|
|
|
2020-08-12 16:55:58 +02:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
|
2020-08-10 15:41:11 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
|
2021-04-02 12:07:50 +02:00
|
|
|
# Degraded
|
2021-03-15 21:15:43 +01:00
|
|
|
self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '1\n')
|
2020-08-10 15:41:11 +02:00
|
|
|
self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now on'))
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceDegraded'), 'lap-detected')
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
2020-08-10 15:41:11 +02:00
|
|
|
|
|
|
|
|
# Switch to non-performance
|
2020-08-12 16:55:58 +02:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
2020-08-10 15:41:11 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
|
2020-09-01 16:25:50 +02:00
|
|
|
def test_intel_pstate(self):
|
2020-09-03 12:52:29 +02:00
|
|
|
'''Intel P-State driver (no UPower)'''
|
2020-09-01 16:25:50 +02:00
|
|
|
|
|
|
|
|
# Create 2 CPUs with preferences
|
2020-11-05 16:17:56 +01:00
|
|
|
dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
|
2020-09-01 16:25:50 +02:00
|
|
|
os.makedirs(dir1)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
|
2021-03-16 16:21:23 +01:00
|
|
|
prefs.write("performance\n")
|
2020-11-05 16:17:56 +01:00
|
|
|
dir2 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy1/")
|
2020-09-01 16:25:50 +02:00
|
|
|
os.makedirs(dir2)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(dir2, "energy_performance_preference"),'w') as prefs:
|
2021-03-16 16:21:23 +01:00
|
|
|
prefs.write("performance\n")
|
2020-09-01 16:25:50 +02:00
|
|
|
|
2020-09-08 18:09:04 +02:00
|
|
|
# Create no_turbo pref
|
2020-11-05 16:17:56 +01:00
|
|
|
pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
|
2020-09-08 18:09:04 +02:00
|
|
|
os.makedirs(pstate_dir)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
|
2021-03-16 16:17:42 +01:00
|
|
|
no_turbo.write("0\n")
|
2020-09-08 18:09:04 +02:00
|
|
|
|
2020-09-01 16:25:50 +02:00
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.assertEqual(profiles[0]['Driver'], 'intel_pstate')
|
|
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
|
|
|
|
|
|
|
|
|
contents = None
|
|
|
|
|
with open(os.path.join(dir2, "energy_performance_preference"), 'rb') as f:
|
|
|
|
|
contents = f.read()
|
2020-09-03 12:16:15 +02:00
|
|
|
self.assertEqual(contents, b'balance_performance')
|
2020-09-01 16:25:50 +02:00
|
|
|
|
|
|
|
|
# Set performance mode
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
|
|
|
|
|
contents = None
|
|
|
|
|
with open(os.path.join(dir2, "energy_performance_preference"), 'rb') as f:
|
|
|
|
|
contents = f.read()
|
|
|
|
|
self.assertEqual(contents, b'performance')
|
|
|
|
|
|
2020-09-08 18:09:04 +02:00
|
|
|
# Disable turbo
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
|
2021-03-16 16:17:42 +01:00
|
|
|
no_turbo.write("1\n")
|
2020-09-08 18:09:04 +02:00
|
|
|
|
|
|
|
|
self.assertEventually(lambda: self.have_text_in_log('File monitor change happened for '))
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceDegraded'), 'high-operating-temperature')
|
2020-09-08 18:09:04 +02:00
|
|
|
|
2020-09-01 16:25:50 +02:00
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
# Verify that the Lenovo DYTC driver still gets preferred
|
2021-02-08 15:25:11 +01:00
|
|
|
self.create_platform_profile()
|
2020-09-01 16:25:50 +02:00
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2021-02-08 16:01:18 +01:00
|
|
|
self.assertEqual(profiles[0]['Driver'], 'platform_profile')
|
2020-09-01 16:25:50 +02:00
|
|
|
|
2020-09-03 12:52:29 +02:00
|
|
|
def test_intel_pstate_balance(self):
|
|
|
|
|
'''Intel P-State driver (balance)'''
|
|
|
|
|
|
|
|
|
|
# Create CPU with preference
|
2020-11-05 16:17:56 +01:00
|
|
|
dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
|
2020-09-03 12:52:29 +02:00
|
|
|
os.makedirs(dir1)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
|
2021-03-16 16:21:23 +01:00
|
|
|
prefs.write("performance\n")
|
2020-09-03 12:52:29 +02:00
|
|
|
|
|
|
|
|
upowerd, obj_upower = self.spawn_server_template(
|
|
|
|
|
'upower', {'DaemonVersion': '0.99', 'OnBattery': False}, stdout=subprocess.PIPE)
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.assertEqual(profiles[0]['Driver'], 'intel_pstate')
|
|
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
|
|
|
|
|
|
|
|
|
contents = None
|
|
|
|
|
with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f:
|
|
|
|
|
contents = f.read()
|
2021-03-16 16:21:23 +01:00
|
|
|
# This matches what's written by ppd-driver-intel-pstate.c
|
2020-09-03 12:52:29 +02:00
|
|
|
self.assertEqual(contents, b'balance_performance')
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
upowerd.terminate()
|
|
|
|
|
upowerd.wait()
|
2021-03-17 14:08:36 +01:00
|
|
|
upowerd.stdout.close()
|
2020-09-03 12:52:29 +02:00
|
|
|
|
2020-07-16 16:09:56 +02:00
|
|
|
def test_dytc_performance_driver(self):
|
|
|
|
|
'''Lenovo DYTC performance driver'''
|
|
|
|
|
|
2020-10-28 17:34:53 +01:00
|
|
|
self.create_dytc_device()
|
2021-02-08 15:25:11 +01:00
|
|
|
self.create_platform_profile()
|
2020-07-16 16:09:56 +02:00
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2021-02-08 16:01:18 +01:00
|
|
|
self.assertEqual(profiles[0]['Driver'], 'platform_profile')
|
2020-08-06 12:36:04 +02:00
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
2021-02-08 16:01:18 +01:00
|
|
|
self.assertEqual(profiles[2]['Driver'], 'platform_profile')
|
2020-07-16 16:09:56 +02:00
|
|
|
self.assertEqual(profiles[2]['Profile'], 'performance')
|
2021-07-05 17:04:46 +02:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
|
2021-03-16 17:04:59 +01:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
2020-08-06 15:47:39 +02:00
|
|
|
|
2021-04-02 12:07:50 +02:00
|
|
|
# lapmode detected
|
2021-03-15 21:15:43 +01:00
|
|
|
self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '1\n')
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEventually(lambda: self.get_dbus_property('PerformanceDegraded') == 'lap-detected')
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
2020-07-16 16:09:56 +02:00
|
|
|
|
|
|
|
|
# Reset lapmode
|
2021-03-15 21:15:43 +01:00
|
|
|
self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '0\n')
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEventually(lambda: self.get_dbus_property('PerformanceDegraded') == '')
|
2020-07-16 16:09:56 +02:00
|
|
|
|
2021-04-02 12:07:50 +02:00
|
|
|
# Performance mode didn't change
|
2020-07-16 16:09:56 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
2020-08-06 15:47:39 +02:00
|
|
|
|
|
|
|
|
# Switch to power-saver mode
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
2021-03-19 13:16:26 +01:00
|
|
|
self.assertEventually(lambda: self.read_sysfs_file("sys/firmware/acpi/platform_profile") == b'low-power')
|
2020-09-15 11:45:06 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
2020-08-06 15:47:39 +02:00
|
|
|
|
2020-09-15 15:05:03 +02:00
|
|
|
# And mimick a user pressing a Fn+H
|
2020-11-19 16:47:43 +01:00
|
|
|
with open(os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/platform_profile"), 'w') as platform_profile:
|
2021-03-16 16:21:46 +01:00
|
|
|
platform_profile.write('performance\n')
|
2020-09-15 15:05:03 +02:00
|
|
|
self.assertEventually(lambda: self.get_dbus_property('ActiveProfile') == 'performance')
|
|
|
|
|
|
2020-08-12 14:18:33 +02:00
|
|
|
def test_fake_driver(self):
|
|
|
|
|
'''Test that the fake driver works'''
|
|
|
|
|
|
|
|
|
|
os.environ['POWER_PROFILE_DAEMON_FAKE_DRIVER'] = '1'
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
del os.environ['POWER_PROFILE_DAEMON_FAKE_DRIVER']
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 2)
|
|
|
|
|
|
2022-02-12 23:13:06 +01:00
|
|
|
def test_trickle_charge_system(self):
|
|
|
|
|
'''Trickle power_supply charge type'''
|
|
|
|
|
|
|
|
|
|
fastcharge = self.testbed.add_device('power_supply', 'bq24190-charger', None,
|
|
|
|
|
[ 'charge_type', 'Trickle', 'scope', 'System' ],
|
|
|
|
|
[]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
self.assertIn('trickle_charge', self.get_dbus_property('Actions'))
|
|
|
|
|
|
|
|
|
|
# Verify that charge-type stays untouched
|
|
|
|
|
self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Trickle')
|
|
|
|
|
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Trickle')
|
|
|
|
|
|
|
|
|
|
def test_trickle_charge_mode_no_change(self):
|
|
|
|
|
'''Trickle power_supply charge type'''
|
|
|
|
|
|
|
|
|
|
fastcharge = self.testbed.add_device('power_supply', 'MFi Fastcharge', None,
|
|
|
|
|
[ 'charge_type', 'Fast', 'scope', 'Device' ],
|
|
|
|
|
[]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
mtime = self.get_mtime(fastcharge, 'charge_type')
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
self.assertIn('trickle_charge', self.get_dbus_property('Actions'))
|
|
|
|
|
|
|
|
|
|
# Verify that charge-type didn't get touched
|
|
|
|
|
self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Fast')
|
|
|
|
|
self.assertEqual(self.get_mtime(fastcharge, 'charge_type'), mtime)
|
|
|
|
|
|
2020-07-20 16:48:07 +02:00
|
|
|
def test_trickle_charge_mode(self):
|
|
|
|
|
'''Trickle power_supply charge type'''
|
|
|
|
|
|
|
|
|
|
idevice = self.testbed.add_device('usb', 'iDevice', None,
|
|
|
|
|
[],
|
|
|
|
|
[ 'ID_MODEL', 'iDevice', 'DRIVER', 'apple-mfi-fastcharge' ]
|
|
|
|
|
)
|
|
|
|
|
fastcharge = self.testbed.add_device('power_supply', 'MFi Fastcharge', idevice,
|
|
|
|
|
[ 'charge_type', 'Trickle', 'scope', 'Device' ],
|
|
|
|
|
[]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
2020-08-12 11:27:22 +02:00
|
|
|
self.assertIn('trickle_charge', self.get_dbus_property('Actions'))
|
|
|
|
|
|
2020-07-20 16:48:07 +02:00
|
|
|
# Verify that charge-type got changed to Fast on startup
|
|
|
|
|
self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Fast')
|
|
|
|
|
|
|
|
|
|
# Verify that charge-type got changed to Trickle when power saving
|
2020-08-12 16:55:58 +02:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
2020-07-20 16:48:07 +02:00
|
|
|
self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Trickle')
|
|
|
|
|
|
|
|
|
|
# FIXME no performance mode
|
|
|
|
|
# Verify that charge-type got changed to Fast in a non-default, non-power save mode
|
2020-08-12 16:55:58 +02:00
|
|
|
# self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
|
2020-07-20 16:48:07 +02:00
|
|
|
# self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), 'Fast')
|
|
|
|
|
|
2021-02-09 10:06:43 +01:00
|
|
|
def test_platform_driver_late_load(self):
|
|
|
|
|
'''Test that we can handle the platform_profile driver getting loaded late'''
|
2021-07-05 18:14:31 +02:00
|
|
|
self.create_empty_platform_profile()
|
2021-02-09 10:06:43 +01:00
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 2)
|
|
|
|
|
|
2021-07-05 18:14:31 +02:00
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-02-09 10:06:43 +01:00
|
|
|
choices.write("low-power\nbalanced\nperformance\n")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-03-16 16:21:46 +01:00
|
|
|
profile.write("performance\n")
|
2021-02-09 10:06:43 +01:00
|
|
|
|
2021-03-15 12:38:55 +01:00
|
|
|
# Wait for profiles to get reloaded
|
|
|
|
|
self.assertEventually(lambda: len(self.get_dbus_property('Profiles')) == 3)
|
2021-02-09 10:06:43 +01:00
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2021-03-16 17:04:59 +01:00
|
|
|
# Was set in platform_profile before we loaded the drivers
|
2021-07-05 17:04:46 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
2021-04-02 12:07:50 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceDegraded'), '')
|
2021-02-09 10:06:43 +01:00
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-03-17 11:37:06 +01:00
|
|
|
def test_hp_wmi(self):
|
|
|
|
|
|
|
|
|
|
# Uses cool instead of low-power
|
|
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
|
|
|
|
os.makedirs(acpi_dir)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-03-17 11:37:06 +01:00
|
|
|
profile.write("cool\n")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-03-17 11:37:06 +01:00
|
|
|
choices.write("cool balanced performance\n")
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.assertEqual(profiles[0]['Driver'], 'platform_profile')
|
|
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
2021-07-05 17:04:46 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'balanced')
|
2021-03-17 11:37:06 +01:00
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
2021-03-19 13:16:26 +01:00
|
|
|
self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'cool')
|
2021-03-17 11:37:06 +01:00
|
|
|
|
|
|
|
|
self.stop_daemon()
|
2021-07-24 23:00:04 +02:00
|
|
|
|
|
|
|
|
def test_quiet(self):
|
|
|
|
|
# Uses cool instead of low-power
|
|
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
|
|
|
|
os.makedirs(acpi_dir)
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-07-24 23:00:04 +02:00
|
|
|
profile.write("cool\n")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-07-24 23:00:04 +02:00
|
|
|
choices.write("quiet balanced balanced-performance performance\n")
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
self.assertEqual(profiles[0]['Driver'], 'platform_profile')
|
|
|
|
|
self.assertEqual(profiles[0]['Profile'], 'power-saver')
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'balanced')
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'quiet')
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
2021-03-17 11:37:06 +01:00
|
|
|
|
2021-03-11 14:32:30 +01:00
|
|
|
def test_hold_release_profile(self):
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
|
|
|
|
|
|
|
|
|
cookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', 'testReason', 'testApplication')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
profileHolds = self.get_dbus_property('ActiveProfileHolds')
|
|
|
|
|
self.assertEqual(len(profileHolds), 1)
|
|
|
|
|
self.assertEqual(profileHolds[0]["Profile"], "performance")
|
|
|
|
|
self.assertEqual(profileHolds[0]["Reason"], "testReason")
|
|
|
|
|
self.assertEqual(profileHolds[0]["ApplicationId"], "testApplication")
|
|
|
|
|
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", cookie))
|
|
|
|
|
profileHolds = self.get_dbus_property('ActiveProfileHolds')
|
|
|
|
|
self.assertEqual(len(profileHolds), 0)
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
# When the profile is changed manually, holds should be released a
|
|
|
|
|
self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(len(self.get_dbus_property('ActiveProfileHolds')), 1)
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('balanced'))
|
|
|
|
|
self.assertEqual(len(self.get_dbus_property('ActiveProfileHolds')), 0)
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
# When all holds are released, the last manually selected profile should be activated
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
cookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", cookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-03-12 10:27:28 +01:00
|
|
|
def test_vanishing_hold(self):
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
builddir = os.getenv('top_builddir', '.')
|
|
|
|
|
tool_path = os.path.join(builddir, 'src', 'powerprofilesctl')
|
|
|
|
|
|
|
|
|
|
launch_process = subprocess.Popen([tool_path, 'launch', '-p', 'power-saver', 'sleep', '3600'],
|
|
|
|
|
stdout=sys.stdout, stderr=sys.stderr)
|
|
|
|
|
assert launch_process
|
|
|
|
|
time.sleep(1)
|
|
|
|
|
holds = self.get_dbus_property('ActiveProfileHolds')
|
|
|
|
|
self.assertEqual(len(holds), 1)
|
|
|
|
|
hold = holds[0]
|
|
|
|
|
self.assertEqual(hold['Profile'], 'power-saver')
|
|
|
|
|
|
|
|
|
|
# Make sure to handle vanishing clients
|
|
|
|
|
launch_process.terminate()
|
|
|
|
|
launch_process.wait()
|
|
|
|
|
|
|
|
|
|
holds = self.get_dbus_property('ActiveProfileHolds')
|
|
|
|
|
self.assertEqual(len(holds), 0)
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-03-11 14:32:30 +01:00
|
|
|
def test_hold_priority(self):
|
|
|
|
|
'''power-saver should take priority over performance'''
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2021-07-05 17:04:46 +02:00
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
2021-03-11 14:32:30 +01:00
|
|
|
|
|
|
|
|
# Test every order of holding and releasing power-saver and performance
|
|
|
|
|
# hold performance and then power-saver, release in the same order
|
|
|
|
|
performanceCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
powerSaverCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('power-saver', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", performanceCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", powerSaverCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
# hold performance and then power-saver, but release power-saver first
|
|
|
|
|
performanceCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
powerSaverCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('power-saver', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)",powerSaverCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", performanceCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
# hold power-saver and then performance, release in the same order
|
|
|
|
|
powerSaverCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('power-saver', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
performanceCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)",powerSaverCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", performanceCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
# hold power-saver and then performance, but release performance first
|
|
|
|
|
powerSaverCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('power-saver', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
performanceCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)",performanceCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.call_dbus_method('ReleaseProfile', GLib.Variant("(u)", powerSaverCookie))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-07-05 17:08:35 +02:00
|
|
|
def test_save_profile(self):
|
|
|
|
|
'''save profile across runs'''
|
|
|
|
|
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
# sys.stderr.write('\n-------------- config file: ----------------\n')
|
2021-09-07 22:58:44 +02:00
|
|
|
# with open(self.testbed.get_root_dir() + '/' + 'ppd_test_conf.ini') as f:
|
2021-07-05 17:08:35 +02:00
|
|
|
# sys.stderr.write(f.read())
|
|
|
|
|
# sys.stderr.write('------------------------------\n')
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
# Programmatically set profile aren't saved
|
|
|
|
|
performanceCookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
|
|
|
|
def test_save_deferred_load(self):
|
|
|
|
|
'''save profile across runs, but kernel driver loaded after start'''
|
|
|
|
|
|
|
|
|
|
self.create_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
self.remove_platform_profile()
|
|
|
|
|
|
|
|
|
|
# We could verify the contents of the configuration file here
|
|
|
|
|
|
|
|
|
|
self.create_empty_platform_profile()
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices:
|
2021-07-05 17:08:35 +02:00
|
|
|
choices.write("low-power\nbalanced\nperformance\n")
|
2021-08-23 13:18:13 +02:00
|
|
|
with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile:
|
2021-07-05 17:08:35 +02:00
|
|
|
profile.write("performance\n")
|
|
|
|
|
|
|
|
|
|
self.assertEventually(lambda: self.get_dbus_property('ActiveProfile') == 'power-saver')
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-10-28 11:04:00 +02:00
|
|
|
def test_not_allowed_profile(self):
|
|
|
|
|
'''Check that we get errors when trying to change a profile and not allowed'''
|
2021-09-28 17:19:40 +02:00
|
|
|
|
|
|
|
|
self.obj_polkit.SetAllowed(dbus.Array([], signature='s'))
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
proxy = Gio.DBusProxy.new_sync(
|
|
|
|
|
self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, PP,
|
|
|
|
|
PP_PATH, 'org.freedesktop.DBus.Properties', None)
|
|
|
|
|
with self.assertRaises(gi.repository.GLib.GError) as cm:
|
|
|
|
|
proxy.Set('(ssv)', PP, 'ActiveProfile', GLib.Variant.new_string('power-saver'))
|
|
|
|
|
self.assertIn('AccessDenied', str(cm.exception))
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-10-28 10:56:53 +02:00
|
|
|
def test_not_allowed_hold(self):
|
|
|
|
|
'''Check that we get an error when trying to hold a profile and not allowed'''
|
|
|
|
|
|
|
|
|
|
self.obj_polkit.SetAllowed(dbus.Array([], signature='s'))
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(gi.repository.GLib.GError) as cm:
|
|
|
|
|
self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', '', '')))
|
|
|
|
|
self.assertIn('AccessDenied', str(cm.exception))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
|
|
|
|
|
self.assertEqual(len(self.get_dbus_property('ActiveProfileHolds')), 0)
|
|
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2022-01-31 10:41:25 +01:00
|
|
|
def test_intel_pstate_noturbo(self):
|
|
|
|
|
'''Intel P-State driver (balance)'''
|
|
|
|
|
|
|
|
|
|
# Create CPU with preference
|
|
|
|
|
dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
|
|
|
|
|
os.makedirs(dir1)
|
|
|
|
|
with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
|
|
|
|
|
prefs.write("performance\n")
|
|
|
|
|
|
|
|
|
|
# Create no_turbo pref with turbo_pct
|
|
|
|
|
pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
|
|
|
|
|
os.makedirs(pstate_dir)
|
|
|
|
|
with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
|
|
|
|
|
no_turbo.write("1\n")
|
|
|
|
|
with open(os.path.join(pstate_dir, "turbo_pct"),'w') as no_turbo:
|
|
|
|
|
no_turbo.write("0\n")
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
|
|
|
|
|
profiles = self.get_dbus_property('Profiles')
|
|
|
|
|
self.assertEqual(len(profiles), 3)
|
2022-01-31 10:48:01 +01:00
|
|
|
self.assertEqual(self.get_dbus_property('PerformanceDegraded'), '')
|
2022-01-31 10:41:25 +01:00
|
|
|
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2021-11-08 15:54:35 +01:00
|
|
|
def test_powerprofilesctl_error(self):
|
|
|
|
|
'''Check that powerprofilesctl returns 1 rather than an exception on error'''
|
|
|
|
|
|
|
|
|
|
builddir = os.getenv('top_builddir', '.')
|
|
|
|
|
tool_path = os.path.join(builddir, 'src', 'powerprofilesctl')
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'list'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'get'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'set', 'not-a-profile'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'list-holds'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'launch', '-p', 'power-saver', 'sleep', '1'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
|
|
|
|
|
self.start_daemon()
|
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError) as cm:
|
|
|
|
|
subprocess.check_output([tool_path, 'set', 'not-a-profile'],
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
universal_newlines=True)
|
|
|
|
|
self.assertNotIn('Traceback', cm.exception.stderr)
|
|
|
|
|
self.stop_daemon()
|
|
|
|
|
|
2020-07-16 16:09:56 +02:00
|
|
|
#
|
|
|
|
|
# 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()
|