1#!/usr/bin/python3 2'''GNOME settings daemon tests for power plugin.''' 3 4__author__ = 'Martin Pitt <martin.pitt@ubuntu.com>' 5__copyright__ = '(C) 2013 Canonical Ltd.' 6__license__ = 'GPL v2 or later' 7 8import unittest 9import subprocess 10import sys 11import time 12import math 13import os 14import os.path 15import signal 16 17project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 18builddir = os.environ.get('BUILDDIR', os.path.dirname(__file__)) 19 20sys.path.insert(0, os.path.join(project_root, 'tests')) 21sys.path.insert(0, builddir) 22import gsdtestcase 23import gsdpowerconstants 24import gsdpowerenums 25 26import dbus 27from dbus.mainloop.glib import DBusGMainLoop 28 29DBusGMainLoop(set_as_default=True) 30 31import gi 32gi.require_version('UPowerGlib', '1.0') 33gi.require_version('UMockdev', '1.0') 34 35from gi.repository import Gio 36from gi.repository import GLib 37from gi.repository import UPowerGlib 38from gi.repository import UMockdev 39 40class PowerPluginBase(gsdtestcase.GSDTestCase): 41 '''Test the power plugin''' 42 43 COMMON_SUSPEND_METHODS=['Suspend', 'Hibernate', 'SuspendThenHibernate'] 44 45 def setUp(self): 46 self.mock_external_monitor_file = os.path.join(self.workdir, 'GSD_MOCK_EXTERNAL_MONITOR') 47 os.environ['GSD_MOCK_EXTERNAL_MONITOR_FILE'] = self.mock_external_monitor_file 48 49 self.check_logind_gnome_session() 50 self.start_logind() 51 self.daemon_death_expected = False 52 53 54 # Setup umockdev testbed 55 self.testbed = UMockdev.Testbed.new() 56 os.environ['UMOCKDEV_DIR'] = self.testbed.get_root_dir() 57 58 # Create a mock backlight device 59 # Note that this function creates a different or even no backlight 60 # device based on the name of the test. 61 self.add_backlight() 62 63 if 'HAVE_SYSFS_BACKLIGHT' in os.environ and os.environ['HAVE_SYSFS_BACKLIGHT'] == '1': 64 self.skip_sysfs_backlight = False 65 else: 66 self.skip_sysfs_backlight = True 67 68 # start mock upowerd 69 (self.upowerd, self.obj_upower) = self.spawn_server_template( 70 'upower', {'DaemonVersion': '0.99', 'OnBattery': True, 'LidIsClosed': False}, stdout=subprocess.PIPE) 71 gsdtestcase.set_nonblock(self.upowerd.stdout) 72 73 # start mock gnome-shell screensaver 74 (self.screensaver, self.obj_screensaver) = self.spawn_server_template( 75 'gnome_screensaver', stdout=subprocess.PIPE) 76 gsdtestcase.set_nonblock(self.screensaver.stdout) 77 78 self.session_log_write = open(os.path.join(self.workdir, 'gnome-session.log'), 'wb', buffering=0) 79 self.session = subprocess.Popen(['gnome-session', '-f', 80 '-a', os.path.join(self.workdir, 'autostart'), 81 '--session=dummy', '--debug'], 82 stdout=self.session_log_write, 83 stderr=subprocess.STDOUT) 84 85 # wait until the daemon is on the bus 86 try: 87 self.wait_for_bus_object('org.gnome.SessionManager', 88 '/org/gnome/SessionManager') 89 except: 90 # on failure, print log 91 with open(self.session_log_write.name) as f: 92 print('----- session log -----\n%s\n------' % f.read()) 93 raise 94 95 self.session_log = open(self.session_log_write.name, 'rb', buffering=0) 96 97 self.obj_session_mgr = self.session_bus_con.get_object( 98 'org.gnome.SessionManager', '/org/gnome/SessionManager') 99 100 self.start_mutter() 101 102 # Set up the gnome-session presence 103 obj_session_presence = self.session_bus_con.get_object( 104 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence') 105 self.obj_session_presence_props = dbus.Interface(obj_session_presence, dbus.PROPERTIES_IFACE) 106 107 # ensure that our tests don't lock the screen when the screensaver 108 # gets active 109 self.settings_screensaver = Gio.Settings(schema_id='org.gnome.desktop.screensaver') 110 self.settings_screensaver['lock-enabled'] = False 111 112 # Ensure we set up the external monitor state 113 self.set_has_external_monitor(False) 114 115 self.settings_gsd_power = Gio.Settings(schema_id='org.gnome.settings-daemon.plugins.power') 116 117 Gio.Settings.sync() 118 self.plugin_log_write = open(os.path.join(self.workdir, 'plugin_power.log'), 'wb', buffering=0) 119 # avoid painfully long delays of actions for tests 120 env = os.environ.copy() 121 # Disable PulseAudio output from libcanberra 122 env['CANBERRA_DRIVER'] = 'null' 123 124 # Use dummy script as testing backlight helper 125 env['GSD_BACKLIGHT_HELPER'] = os.path.join (project_root, 'plugins', 'power', 'test-backlight-helper') 126 if 'POWER_LD_PRELOAD' in env: 127 if 'LD_PRELOAD' in env and env['LD_PRELOAD']: 128 env['LD_PRELOAD'] = ':'.join((env['POWER_LD_PRELOAD'], env['LD_PRELOAD'])) 129 else: 130 env['LD_PRELOAD'] = env['POWER_LD_PRELOAD'] 131 132 # We need to redirect stdout to grab the debug messages. 133 # stderr is not needed by the testing infrastructure but is useful to 134 # see warnings and errors. 135 self.daemon = subprocess.Popen( 136 [os.path.join(builddir, 'gsd-power'), '--verbose'], 137 stdout=self.plugin_log_write, 138 env=env) 139 140 # you can use this for reading the current daemon log in tests 141 self.plugin_log = open(self.plugin_log_write.name, 'rb', buffering=0) 142 143 # wait until plugin is ready 144 timeout = 100 145 while timeout > 0: 146 time.sleep(0.1) 147 timeout -= 1 148 log = self.plugin_log.read() 149 if b'System inhibitor fd is' in log: 150 break 151 152 # always start with zero idle time 153 self.reset_idle_timer() 154 155 # flush notification log 156 self.p_notify.stdout.read() 157 158 def tearDown(self): 159 160 daemon_running = self.daemon.poll() == None 161 if daemon_running: 162 self.daemon.terminate() 163 self.daemon.wait() 164 self.plugin_log.close() 165 self.plugin_log_write.flush() 166 self.plugin_log_write.close() 167 168 self.upowerd.terminate() 169 self.upowerd.wait() 170 self.screensaver.terminate() 171 self.screensaver.wait() 172 self.stop_session() 173 self.stop_mutter() 174 self.stop_logind() 175 176 # reset all changed gsettings, so that tests are independent from each 177 # other 178 for schema in [self.settings_gsd_power, self.settings_session, self.settings_screensaver]: 179 for k in schema.list_keys(): 180 schema.reset(k) 181 Gio.Settings.sync() 182 183 try: 184 os.unlink(self.mock_external_monitor_file) 185 except OSError: 186 pass 187 188 del self.testbed 189 190 # we check this at the end so that the other cleanup always happens 191 self.assertTrue(daemon_running or self.daemon_death_expected, 'daemon died during the test') 192 193 def stop_session(self): 194 '''Stop GNOME session''' 195 196 assert self.session 197 self.session.terminate() 198 self.session.wait() 199 200 self.session_log_write.flush() 201 self.session_log_write.close() 202 self.session_log.close() 203 204 def check_logind_gnome_session(self): 205 '''Check that gnome-session is built with logind support''' 206 207 path = GLib.find_program_in_path ('gnome-session') 208 assert(path) 209 (success, data) = GLib.file_get_contents (path) 210 lines = data.split(b'\n') 211 new_path = None 212 for line in lines: 213 items = line.split() 214 if items and items[0] == b'exec': 215 new_path = items[1] 216 if not new_path: 217 self.fail("could not get gnome-session's real path from %s" % path) 218 path = new_path 219 ldd = subprocess.Popen(['ldd', path], stdout=subprocess.PIPE) 220 out = ldd.communicate()[0] 221 if not b'libsystemd.so.0' in out: 222 self.fail('gnome-session is not built with logind support') 223 224 def get_status(self): 225 return self.obj_session_presence_props.Get('org.gnome.SessionManager.Presence', 'status') 226 227 def backlight_defaults(self): 228 # Hack to modify the brightness defaults before starting gsd-power. 229 # The alternative would be to create two separate test files. 230 if 'no_backlight' in self.id(): 231 return None, None 232 elif 'legacy_brightness' in self.id(): 233 return 15, 15 234 else: 235 return 100, 50 236 237 def add_backlight(self, _type="raw"): 238 max_brightness, brightness = self.backlight_defaults() 239 240 if max_brightness is None: 241 self.backlight = None 242 return 243 244 # Undo mangling done in GSD 245 if max_brightness >= 99: 246 max_brightness += 1 247 brightness += 1 248 249 # This needs to be done before starting gsd-power! 250 self.backlight = self.testbed.add_device('backlight', 'mock_backlight', None, 251 ['type', _type, 252 'max_brightness', str(max_brightness), 253 'brightness', str(brightness)], 254 []) 255 256 def get_brightness(self): 257 max_brightness = int(open(os.path.join(self.testbed.get_root_dir() + self.backlight, 'max_brightness')).read()) 258 259 # self.backlight contains the leading slash, so os.path.join doesn't quite work 260 res = int(open(os.path.join(self.testbed.get_root_dir() + self.backlight, 'brightness')).read()) 261 # Undo mangling done in GSD 262 if max_brightness >= 99: 263 res -= 1 264 return res 265 266 def set_has_external_monitor(self, external): 267 if external: 268 val = b'1' 269 else: 270 val = b'0' 271 GLib.file_set_contents (self.mock_external_monitor_file, val) 272 273 def set_composite_battery_discharging(self, icon='battery-good-symbolic'): 274 self.obj_upower.SetupDisplayDevice( 275 UPowerGlib.DeviceKind.BATTERY, 276 UPowerGlib.DeviceState.DISCHARGING, 277 50., 50., 100., # 50%, charge 50 of 100 278 0.01, 600, 0, # Discharge rate 0.01 with 600 seconds remaining, 0 time to full 279 True, # present 280 icon, UPowerGlib.DeviceLevel.NONE 281 ) 282 283 def set_composite_battery_critical(self, icon='battery-caution-symbolic'): 284 self.obj_upower.SetupDisplayDevice( 285 UPowerGlib.DeviceKind.BATTERY, 286 UPowerGlib.DeviceState.DISCHARGING, 287 2., 2., 100., # 2%, charge 2 of 100 288 0.01, 60, 0, # Discharge rate 0.01 with 60 seconds remaining, 0 time to full 289 True, # present 290 icon, UPowerGlib.DeviceLevel.CRITICAL 291 ) 292 293 def check_for_logout(self, timeout): 294 '''Check that logout is requested. 295 296 Fail after the given timeout. 297 ''' 298 # check that it request logout 299 while timeout > 0: 300 time.sleep(1) 301 timeout -= 1 302 # check that it requested logout 303 log = self.session_log.read() 304 if log is None: 305 continue 306 307 if log and (b'GsmManager: requesting logout' in log): 308 break 309 else: 310 self.fail('timed out waiting for gnome-session logout call') 311 312 def check_no_logout(self, seconds): 313 '''Check that no logout is requested in the given time''' 314 315 # wait for specified time to ensure it didn't do anything 316 time.sleep(seconds) 317 # check that it did not logout 318 log = self.session_log.read() 319 if log: 320 self.assertFalse(b'GsmManager: requesting logout' in log, 'unexpected logout request') 321 322 def check_for_suspend(self, timeout, methods=COMMON_SUSPEND_METHODS): 323 '''Check that one of the given suspend methods are requested. Default 324 methods are Suspend() or Hibernate() but also HibernateThenSuspend() 325 is valid. 326 327 Fail after the given timeout. 328 ''' 329 330 # Create a list of byte string needles to search for 331 needles = [' {} '.format(m).encode('ascii') for m in methods] 332 333 suspended = False 334 335 # check that it request suspend 336 while timeout > 0: 337 time.sleep(1) 338 timeout -= 1 339 # check that it requested suspend 340 log = self.logind.stdout.read() 341 if log is None: 342 continue 343 344 for n in needles: 345 if n in log: 346 suspended = True 347 break 348 349 if suspended: 350 break 351 352 if not suspended: 353 self.fail('timed out waiting for logind suspend call, methods: %s' % ', '.join(methods)) 354 355 def check_for_lid_inhibited(self, timeout=0): 356 '''Check that the lid inhibitor has been added. 357 358 Fail after the given timeout. 359 ''' 360 self.check_plugin_log('Adding lid switch system inhibitor', timeout, 361 'Timed out waiting for lid inhibitor') 362 363 def check_for_lid_uninhibited(self, timeout=0): 364 '''Check that the lid inhibitor has been dropped. 365 366 Fail after the given timeout. 367 ''' 368 self.check_plugin_log('uninhibiting lid close', timeout, 369 'Timed out waiting for lid uninhibition') 370 371 def check_no_lid_uninhibited(self, timeout=0): 372 '''Check that the lid inhibitor has been dropped. 373 374 Fail after the given timeout. 375 ''' 376 time.sleep(timeout) 377 # check that it requested uninhibition 378 log = self.plugin_log.read() 379 380 if b'uninhibiting lid close' in log: 381 self.fail('lid uninhibit should not have happened') 382 383 def check_no_suspend(self, seconds, methods=COMMON_SUSPEND_METHODS): 384 '''Check that no Suspend or Hibernate is requested in the given time''' 385 386 # wait for specified time to ensure it didn't do anything 387 time.sleep(seconds) 388 # check that it did not suspend or hibernate 389 log = self.logind.stdout.read() 390 if log is None: 391 return 392 393 for m in methods: 394 needle = ' {} '.format(m).encode('ascii') 395 396 self.assertFalse(needle in log, 'unexpected %s request' % m) 397 398 def check_suspend_no_hibernate(self, seconds): 399 '''Check that Suspend was requested and not Hibernate, in the given time''' 400 401 # wait for specified time to ensure it didn't do anything 402 time.sleep(seconds) 403 # check that it did suspend and didn't hibernate 404 log = self.logind.stdout.read() 405 if log: 406 self.assertTrue(b' Suspend' in log, 'missing Suspend request') 407 self.assertFalse(b' Hibernate' in log, 'unexpected Hibernate request') 408 409 def check_plugin_log(self, needle, timeout=0, failmsg=None): 410 '''Check that needle is found in the log within the given timeout. 411 Returns immediately when found. 412 413 Fail after the given timeout. 414 ''' 415 if type(needle) == str: 416 needle = needle.encode('ascii') 417 # Fast path if the message was already logged 418 log = self.plugin_log.read() 419 if needle in log: 420 return 421 422 while timeout > 0: 423 time.sleep(0.5) 424 timeout -= 0.5 425 426 # read new data (lines) from the log 427 log = self.plugin_log.read() 428 if needle in log: 429 break 430 else: 431 if failmsg is not None: 432 self.fail(failmsg) 433 else: 434 self.fail('timed out waiting for needle "%s"' % needle) 435 436 def check_no_dim(self, seconds): 437 '''Check that mode is not set to dim in the given time''' 438 439 # wait for specified time to ensure it didn't do anything 440 time.sleep(seconds) 441 # check that we don't dim 442 log = self.plugin_log.read() 443 if log: 444 self.assertFalse(b'Doing a state transition: dim' in log, 'unexpected dim request') 445 446 def check_dim(self, timeout): 447 '''Check that mode is set to dim in the given time''' 448 449 self.check_plugin_log('Doing a state transition: dim', timeout, 450 'timed out waiting for dim') 451 452 def check_undim(self, timeout): 453 '''Check that mode is set to normal in the given time''' 454 455 self.check_plugin_log('Doing a state transition: normal', timeout, 456 'timed out waiting for normal mode') 457 458 def check_blank(self, timeout): 459 '''Check that blank is requested. 460 461 Fail after the given timeout. 462 ''' 463 464 self.check_plugin_log('TESTSUITE: Blanked screen', timeout, 465 'timed out waiting for blank') 466 467 def check_unblank(self, timeout): 468 '''Check that unblank is requested. 469 470 Fail after the given timeout. 471 ''' 472 473 self.check_plugin_log('TESTSUITE: Unblanked screen', timeout, 474 'timed out waiting for unblank') 475 476 def check_no_blank(self, seconds): 477 '''Check that no blank is requested in the given time''' 478 479 # wait for specified time to ensure it didn't blank 480 time.sleep(seconds) 481 # check that it did not blank 482 log = self.plugin_log.read() 483 self.assertFalse(b'TESTSUITE: Blanked screen' in log, 'unexpected blank request') 484 485 def check_no_unblank(self, seconds): 486 '''Check that no unblank is requested in the given time''' 487 488 # wait for specified time to ensure it didn't unblank 489 time.sleep(seconds) 490 # check that it did not unblank 491 log = self.plugin_log.read() 492 self.assertFalse(b'TESTSUITE: Unblanked screen' in log, 'unexpected unblank request') 493 494class PowerPluginTest1(PowerPluginBase): 495 def test_screensaver(self): 496 # Note that the screensaver mock object 497 # doesn't know how to get out of being active, 498 # be it if the lock is disabled, or not. 499 500 self.obj_screensaver.Lock() 501 # 0.3 second animation 502 time.sleep(1) 503 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 504 505 # blank is supposed to happen straight away 506 self.check_blank(2) 507 508 # Wait a bit for the active watch to be registered through dbus, then 509 # fake user activity and check that the screen is unblanked. 510 time.sleep(0.5) 511 self.reset_idle_timer() 512 self.check_unblank(2) 513 514 # Check for no blank before the normal blank timeout 515 self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4) 516 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 517 518 # and check for blank after the blank timeout 519 self.check_blank(10) 520 521 # Wait a bit for the active watch to be registered through dbus, then 522 # fake user activity and check that the screen is unblanked. 523 time.sleep(0.5) 524 self.reset_idle_timer() 525 self.check_unblank(2) 526 527 # check no blank and then blank 528 self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4) 529 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 530 self.check_blank(10) 531 532 def test_sleep_inactive_blank(self): 533 '''screensaver/blank interaction''' 534 535 # create suspend inhibitor which should have no effect on the idle 536 inhibit_id = self.obj_session_mgr.Inhibit( 537 'testsuite', dbus.UInt32(0), 'for testing', 538 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND), 539 dbus_interface='org.gnome.SessionManager') 540 541 self.obj_screensaver.SetActive(True) 542 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 543 544 # blank is supposed to happen straight away 545 self.check_blank(2) 546 547 # Wait a bit for the active watch to be registered through dbus, then 548 # fake user activity and check that the screen is unblanked. 549 time.sleep(0.5) 550 self.reset_idle_timer() 551 self.check_unblank(2) 552 if not self.skip_sysfs_backlight: 553 self.assertTrue(self.get_brightness() == gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS , 'incorrect unblanked brightness (%d != %d)' % (self.get_brightness(), gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS)) 554 555 # Check for no blank before the normal blank timeout 556 self.check_no_blank(gsdpowerconstants.SCREENSAVER_TIMEOUT_BLANK - 4) 557 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 558 559 # and check for blank after the blank timeout 560 self.check_blank(10) 561 562 # Drop inhibitor 563 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 564 dbus_interface='org.gnome.SessionManager') 565 566class PowerPluginTest2(PowerPluginBase): 567 def test_screensaver_no_unblank(self): 568 '''Ensure the screensaver is not unblanked for new inhibitors.''' 569 570 # Lower idle delay a lot 571 self.settings_session['idle-delay'] = 1 572 573 # Bring down the screensaver 574 self.obj_screensaver.SetActive(True) 575 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 576 577 # Check that we blank 578 self.check_blank(2) 579 580 # Create the different possible inhibitors 581 inhibit_id = self.obj_session_mgr.Inhibit( 582 'testsuite', dbus.UInt32(0), 'for testing', 583 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE | gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND | gsdpowerenums.GSM_INHIBITOR_FLAG_LOGOUT), 584 dbus_interface='org.gnome.SessionManager') 585 586 self.check_no_unblank(2) 587 588 # Drop inhibitor 589 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 590 dbus_interface='org.gnome.SessionManager') 591 592 self.check_no_unblank(2) 593 594 def test_session_idle_delay(self): 595 '''verify that session idle delay works as expected when changed''' 596 597 # Verify that idle is set after 5 seconds 598 self.settings_session['idle-delay'] = 5 599 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 600 time.sleep(7) 601 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE) 602 603 # Raise the idle delay, and see that we stop being idle 604 # and get idle again after the timeout 605 self.settings_session['idle-delay'] = 10 606 # Resolve possible race condition, see also https://gitlab.gnome.org/GNOME/mutter/issues/113 607 time.sleep(0.2) 608 self.reset_idle_timer() 609 time.sleep(5) 610 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 611 time.sleep(10) 612 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE) 613 614 # Lower the delay again, and see that we get idle as we should 615 self.settings_session['idle-delay'] = 5 616 # Resolve possible race condition, see also https://gitlab.gnome.org/GNOME/mutter/issues/113 617 time.sleep(0.2) 618 self.reset_idle_timer() 619 time.sleep(2) 620 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 621 time.sleep(5) 622 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE) 623 624 def test_idle_time_reset_on_resume(self): 625 '''Check that the IDLETIME is reset when resuming''' 626 627 self.settings_screensaver['lock-enabled'] = False 628 629 # Go idle 630 self.settings_session['idle-delay'] = 5 631 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 632 time.sleep(7) 633 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_IDLE) 634 635 # Go to sleep 636 self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True], dbus_interface='org.freedesktop.DBus.Mock') 637 time.sleep(1) 638 639 # Wake up 640 self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False], dbus_interface='org.freedesktop.DBus.Mock') 641 time.sleep(1) 642 643 # And check we're not idle 644 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 645 646class PowerPluginTest3(PowerPluginBase): 647 def test_sleep_inactive_battery(self): 648 '''sleep-inactive-battery-timeout''' 649 650 self.settings_session['idle-delay'] = 2 651 self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5 652 self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend' 653 654 # wait for idle delay; should not yet suspend 655 self.check_no_suspend(2) 656 657 # suspend should happen after inactive sleep timeout + 1 s notification 658 # delay + 1 s error margin 659 self.check_for_suspend(7) 660 661 def _test_suspend_no_hibernate(self): 662 '''suspend-no-hibernate''' 663 664 self.settings_session['idle-delay'] = 2 665 self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5 666 # Hibernate isn't possible, so it should end up suspending 667 # FIXME 668 self.settings_gsd_power['critical-battery-action'] = 'hibernate' 669 670 # wait for idle delay; should not yet hibernate 671 self.check_no_suspend(2) 672 673 # suspend should happen after inactive sleep timeout + 1 s notification 674 # delay + 1 s error margin 675 self.check_suspend_no_hibernate(7) 676 677 def test_sleep_inhibition(self): 678 '''Does not sleep under idle inhibition''' 679 680 idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 681 682 self.settings_session['idle-delay'] = idle_delay 683 self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5 684 self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend' 685 686 # create inhibitor 687 inhibit_id = self.obj_session_mgr.Inhibit( 688 'testsuite', dbus.UInt32(0), 'for testing', 689 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE | gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND), 690 dbus_interface='org.gnome.SessionManager') 691 self.check_no_suspend(idle_delay + 2) 692 self.check_no_dim(0) 693 694 # Check that we didn't go to idle either 695 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 696 697 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 698 dbus_interface='org.gnome.SessionManager') 699 700class PowerPluginTest4(PowerPluginBase): 701 def test_lock_on_lid_close(self): 702 '''Check that we do lock on lid closing, if the machine will not suspend''' 703 704 self.settings_screensaver['lock-enabled'] = True 705 706 # create inhibitor 707 inhibit_id = self.obj_session_mgr.Inhibit( 708 'testsuite', dbus.UInt32(0), 'for testing', 709 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND), 710 dbus_interface='org.gnome.SessionManager') 711 712 time.sleep (gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT) 713 714 # Close the lid 715 self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True) 716 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 717 718 # Check that we've blanked 719 time.sleep(2) 720 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 721 self.check_blank(2) 722 723 # Drop the inhibit and see whether we suspend 724 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 725 dbus_interface='org.gnome.SessionManager') 726 # At this point logind should suspend for us 727 self.settings_screensaver['lock-enabled'] = False 728 729 def test_blank_on_lid_close(self): 730 '''Check that we do blank on lid closing, if the machine will not suspend''' 731 732 # create inhibitor 733 inhibit_id = self.obj_session_mgr.Inhibit( 734 'testsuite', dbus.UInt32(0), 'for testing', 735 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND), 736 dbus_interface='org.gnome.SessionManager') 737 738 time.sleep (gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT) 739 740 # Close the lid 741 self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True) 742 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 743 744 # Check that we've blanked 745 self.check_blank(4) 746 747 # Drop the inhibit and see whether we suspend 748 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 749 dbus_interface='org.gnome.SessionManager') 750 # At this point logind should suspend for us 751 752 def test_unblank_on_lid_open(self): 753 '''Check that we do unblank on lid opening, if the machine will not suspend''' 754 755 # create inhibitor 756 inhibit_id = self.obj_session_mgr.Inhibit( 757 'testsuite', dbus.UInt32(0), 'for testing', 758 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_SUSPEND), 759 dbus_interface='org.gnome.SessionManager') 760 761 time.sleep (gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT) 762 763 # Close the lid 764 self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True) 765 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 766 767 # Check that we've blanked 768 self.check_blank(2) 769 770 # Reopen the lid 771 self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', False) 772 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 773 774 # Check for unblanking 775 self.check_unblank(2) 776 777 # Drop the inhibit 778 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 779 dbus_interface='org.gnome.SessionManager') 780 781class PowerPluginTest5(PowerPluginBase): 782 def test_dim(self): 783 '''Check that we do go to dim''' 784 785 # Wait and flush log 786 time.sleep (gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 1) 787 self.plugin_log.read() 788 789 idle_delay = math.ceil(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 790 self.reset_idle_timer() 791 792 self.settings_session['idle-delay'] = idle_delay 793 self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1 794 self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend' 795 # This is an absolute percentage, and our brightness is 0..100 796 dim_level = self.settings_gsd_power['idle-brightness']; 797 798 # Check that we're not idle 799 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 800 801 # Wait and check we're not idle, but dimmed 802 self.check_dim(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY + 1) 803 # Give time for the brightness to change 804 time.sleep(2) 805 if not self.skip_sysfs_backlight: 806 level = self.get_brightness(); 807 self.assertTrue(level == dim_level, 'incorrect dim brightness (%d != %d)' % (level, dim_level)) 808 809 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 810 811 # Bring down the screensaver 812 self.obj_screensaver.SetActive(True) 813 self.assertTrue(self.obj_screensaver.GetActive(), 'screensaver not turned on') 814 815 # Check that we blank 816 self.check_blank(2) 817 818 # Go to sleep 819 self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True], dbus_interface='org.freedesktop.DBus.Mock') 820 time.sleep(1) 821 822 # Wake up 823 self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False], dbus_interface='org.freedesktop.DBus.Mock') 824 time.sleep(1) 825 826 # And check that we have the pre-dim brightness 827 if not self.skip_sysfs_backlight: 828 self.assertTrue(self.get_brightness() == gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS , 'incorrect unblanked brightness (%d != %d)' % (self.get_brightness(), gsdpowerconstants.GSD_MOCK_DEFAULT_BRIGHTNESS)) 829 830 def test_lid_close_inhibition(self): 831 '''Check that we correctly inhibit suspend with an external monitor''' 832 833 # Wait and flush log 834 time.sleep (gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 1) 835 self.plugin_log.read() 836 837 # Add an external monitor 838 self.set_has_external_monitor(True) 839 self.check_for_lid_inhibited(1) 840 841 # Check that we do not uninhibit with the external monitor attached 842 self.check_no_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT + 1) 843 844 # Close the lid 845 self.obj_upower.Set('org.freedesktop.UPower', 'LidIsClosed', True) 846 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 847 time.sleep(0.5) 848 849 # Unplug the external monitor 850 self.set_has_external_monitor(False) 851 852 # Check that no action happens during the safety time minus 1 second 853 self.check_no_lid_uninhibited(gsdpowerconstants.LID_CLOSE_SAFETY_TIMEOUT - 1) 854 # Check that we're uninhibited after the safety time 855 self.check_for_lid_uninhibited(4) 856 857class PowerPluginTest6(PowerPluginBase): 858 def test_notify_critical_battery(self): 859 '''action on critical battery''' 860 861 self.set_composite_battery_discharging() 862 863 time.sleep(2) 864 865 self.set_composite_battery_critical() 866 867 # Check that it was picked up 868 self.check_plugin_log('EMIT: charge-critical', 2) 869 870 # Wait a bit longer to ensure event has been fired 871 time.sleep(0.5) 872 # we should have gotten a notification now 873 notify_log = self.p_notify.stdout.read() 874 875 # verify notification 876 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* "battery-caution-symbolic" ".*battery critical.*"') 877 878 def test_notify_critical_battery_on_start(self): 879 '''action on critical battery on startup''' 880 881 self.set_composite_battery_critical() 882 883 # Check that it was picked up 884 self.check_plugin_log('EMIT: charge-critical', 2) 885 886 time.sleep(0.5) 887 888 # we should have gotten a notification by now 889 notify_log = self.p_notify.stdout.read() 890 891 # verify notification 892 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* "battery-caution-symbolic" ".*battery critical.*"') 893 894 def test_notify_device_battery(self): 895 '''critical power level notification for device batteries''' 896 897 # Set internal battery to discharging 898 self.set_composite_battery_discharging() 899 900 # Add a device battery 901 bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1' 902 self.obj_upower.AddObject(bat2_path, 903 'org.freedesktop.UPower.Device', 904 { 905 'PowerSupply': dbus.Boolean(False, variant_level=1), 906 'IsPresent': dbus.Boolean(True, variant_level=1), 907 'Model': dbus.String('Bat1', variant_level=1), 908 'Percentage': dbus.Double(40.0, variant_level=1), 909 'TimeToEmpty': dbus.Int64(1600, variant_level=1), 910 'EnergyFull': dbus.Double(100.0, variant_level=1), 911 'Energy': dbus.Double(40.0, variant_level=1), 912 'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1), 913 'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1), 914 'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.NONE, variant_level=1), 915 }, dbus.Array([], signature='(ssss)')) 916 917 obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path) 918 self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path], 919 dbus_interface='org.freedesktop.DBus.Mock') 920 time.sleep(1) 921 922 # now change the mouse battery to critical charge 923 obj_bat2.Set('org.freedesktop.UPower.Device', 'TimeToEmpty', 924 dbus.Int64(30, variant_level=1), 925 dbus_interface=dbus.PROPERTIES_IFACE) 926 obj_bat2.Set('org.freedesktop.UPower.Device', 'Energy', 927 dbus.Double(0.5, variant_level=1), 928 dbus_interface=dbus.PROPERTIES_IFACE) 929 obj_bat2.Set('org.freedesktop.UPower.Device', 'WarningLevel', 930 dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1), 931 dbus_interface=dbus.PROPERTIES_IFACE) 932 obj_bat2.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 933 self.obj_upower.EmitSignal('', 'DeviceChanged', 'o', [bat2_path], 934 dbus_interface='org.freedesktop.DBus.Mock') 935 936 self.check_plugin_log('EMIT: charge-critical', 2) 937 time.sleep(0.5) 938 939 # we should have gotten a notification by now 940 notify_log = self.p_notify.stdout.read() 941 942 # verify notification 943 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*\([0-9.]+%\).*"') 944 945 def test_notify_device_spam(self): 946 '''no repeat notifications for device batteries''' 947 948 # Set internal battery to discharging 949 self.set_composite_battery_discharging() 950 951 # Add a device battery 952 bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1' 953 self.obj_upower.AddObject(bat2_path, 954 'org.freedesktop.UPower.Device', 955 { 956 'PowerSupply': dbus.Boolean(False, variant_level=1), 957 'IsPresent': dbus.Boolean(True, variant_level=1), 958 'Model': dbus.String('Bat1', variant_level=1), 959 'Serial': dbus.String('12345678', variant_level=1), 960 'Percentage': dbus.Double(10.0, variant_level=1), 961 'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1), 962 'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1), 963 'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1), 964 }, dbus.Array([], signature='(ssss)')) 965 966 obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path) 967 self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path], 968 dbus_interface='org.freedesktop.DBus.Mock') 969 time.sleep(1) 970 971 self.check_plugin_log('EMIT: charge-low', 2) 972 time.sleep(0.5) 973 974 # we should have gotten a notification by now 975 notify_log = self.p_notify.stdout.read() 976 977 # verify notification 978 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*\([0-9.]+%\).*"') 979 980 # Disconnect mouse 981 self.obj_upower.RemoveObject(bat2_path) 982 time.sleep(0.5) 983 984 # Reconnect mouse 985 self.obj_upower.AddObject(bat2_path, 986 'org.freedesktop.UPower.Device', 987 { 988 'PowerSupply': dbus.Boolean(False, variant_level=1), 989 'IsPresent': dbus.Boolean(True, variant_level=1), 990 'Model': dbus.String('Bat1', variant_level=1), 991 'Serial': dbus.String('12345678', variant_level=1), 992 'Percentage': dbus.Double(10.0, variant_level=1), 993 'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1), 994 'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1), 995 'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1), 996 }, dbus.Array([], signature='(ssss)')) 997 998 obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path) 999 self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path], 1000 dbus_interface='org.freedesktop.DBus.Mock') 1001 time.sleep(1) 1002 1003 # we shouldn't have gotten a notification by now 1004 notify_log = self.p_notify.stdout.read() 1005 self.assertIsNone(notify_log) 1006 1007 # Disconnect mouse 1008 self.obj_upower.RemoveObject(bat2_path) 1009 time.sleep(0.5) 1010 1011 # Reconnect mouse with critical battery level 1012 self.obj_upower.AddObject(bat2_path, 1013 'org.freedesktop.UPower.Device', 1014 { 1015 'PowerSupply': dbus.Boolean(False, variant_level=1), 1016 'IsPresent': dbus.Boolean(True, variant_level=1), 1017 'Model': dbus.String('Bat1', variant_level=1), 1018 'Serial': dbus.String('12345678', variant_level=1), 1019 'Percentage': dbus.Double(5.0, variant_level=1), 1020 'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1), 1021 'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1), 1022 'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1), 1023 }, dbus.Array([], signature='(ssss)')) 1024 1025 obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path) 1026 self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path], 1027 dbus_interface='org.freedesktop.DBus.Mock') 1028 time.sleep(1) 1029 1030 # Verify new warning 1031 self.check_plugin_log('EMIT: charge-critical', 2) 1032 time.sleep(0.5) 1033 1034 # we should have gotten a notification by now 1035 notify_log = self.p_notify.stdout.read() 1036 1037 # verify notification 1038 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*very low.* power.*\([0-9.]+%\).*"') 1039 1040 def test_notify_device_battery_coarse_level(self): 1041 '''critical power level notification for device batteries with coarse level''' 1042 1043 # Set internal battery to discharging 1044 self.set_composite_battery_discharging() 1045 1046 # Add a device battery 1047 bat2_path = '/org/freedesktop/UPower/devices/' + 'mock_MOUSE_BAT1' 1048 self.obj_upower.AddObject(bat2_path, 1049 'org.freedesktop.UPower.Device', 1050 { 1051 'PowerSupply': dbus.Boolean(False, variant_level=1), 1052 'IsPresent': dbus.Boolean(True, variant_level=1), 1053 'Model': dbus.String('Bat1', variant_level=1), 1054 'Percentage': dbus.Double(40.0, variant_level=1), 1055 'BatteryLevel': dbus.UInt32(UPowerGlib.DeviceLevel.LOW, variant_level=1), 1056 'TimeToEmpty': dbus.Int64(1600, variant_level=1), 1057 'EnergyFull': dbus.Double(100.0, variant_level=1), 1058 'Energy': dbus.Double(40.0, variant_level=1), 1059 'State': dbus.UInt32(UPowerGlib.DeviceState.DISCHARGING, variant_level=1), 1060 'Type': dbus.UInt32(UPowerGlib.DeviceKind.MOUSE, variant_level=1), 1061 'WarningLevel': dbus.UInt32(UPowerGlib.DeviceLevel.NONE, variant_level=1), 1062 }, dbus.Array([], signature='(ssss)')) 1063 1064 obj_bat2 = self.system_bus_con.get_object('org.freedesktop.UPower', bat2_path) 1065 self.obj_upower.EmitSignal('', 'DeviceAdded', 'o', [bat2_path], 1066 dbus_interface='org.freedesktop.DBus.Mock') 1067 time.sleep(1) 1068 1069 # now change the mouse battery to critical charge 1070 obj_bat2.Set('org.freedesktop.UPower.Device', 'TimeToEmpty', 1071 dbus.Int64(30, variant_level=1), 1072 dbus_interface=dbus.PROPERTIES_IFACE) 1073 obj_bat2.Set('org.freedesktop.UPower.Device', 'Energy', 1074 dbus.Double(0.5, variant_level=1), 1075 dbus_interface=dbus.PROPERTIES_IFACE) 1076 obj_bat2.Set('org.freedesktop.UPower.Device', 'WarningLevel', 1077 dbus.UInt32(UPowerGlib.DeviceLevel.CRITICAL, variant_level=1), 1078 dbus_interface=dbus.PROPERTIES_IFACE) 1079 obj_bat2.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 1080 self.obj_upower.EmitSignal('', 'DeviceChanged', 'o', [bat2_path], 1081 dbus_interface='org.freedesktop.DBus.Mock') 1082 1083 self.check_plugin_log('EMIT: charge-critical', 2) 1084 time.sleep(0.5) 1085 1086 # we should have gotten a notification by now 1087 notify_log = self.p_notify.stdout.read() 1088 1089 # verify notification 1090 self.assertRegex(notify_log, b'[0-9.]+ Notify "Power" .* ".*" ".*Wireless mouse .*low.* power.*"') 1091 self.assertNotRegex(notify_log, b'[0-9.]+ Notify "Power" .* ".*" ".*\([0-9.]+%\).*"') 1092 1093 def test_forced_logout(self): 1094 '''Test forced logout''' 1095 1096 self.daemon_death_expected = True 1097 idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 1098 1099 self.settings_session['idle-delay'] = idle_delay 1100 self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1 1101 self.settings_gsd_power['sleep-inactive-battery-type'] = 'logout' 1102 1103 self.check_for_logout(idle_delay + 2) 1104 1105 # The notification should have been received before the logout, but it's saved anyway 1106 notify_log = self.p_notify.stdout.read() 1107 self.assertTrue(b'You will soon log out because of inactivity.' in notify_log) 1108 1109 def test_forced_logout_inhibition(self): 1110 '''Test we don't force logout when inhibited''' 1111 1112 idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 1113 1114 self.settings_session['idle-delay'] = idle_delay 1115 self.settings_gsd_power['sleep-inactive-battery-timeout'] = idle_delay + 1 1116 self.settings_gsd_power['sleep-inactive-battery-type'] = 'logout' 1117 1118 # create suspend inhibitor which should stop us logging out 1119 inhibit_id = self.obj_session_mgr.Inhibit( 1120 'testsuite', dbus.UInt32(0), 'for testing', 1121 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_LOGOUT), 1122 dbus_interface='org.gnome.SessionManager') 1123 1124 self.check_no_logout(idle_delay + 3) 1125 1126 # Drop inhibitor 1127 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 1128 dbus_interface='org.gnome.SessionManager') 1129 1130class PowerPluginTest7(PowerPluginBase): 1131 def test_check_missing_kbd_brightness(self): 1132 ''' https://bugzilla.gnome.org/show_bug.cgi?id=793512 ''' 1133 1134 obj_gsd_power_kbd = self.session_bus_con.get_object( 1135 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1136 obj_gsd_power_kbd_props = dbus.Interface(obj_gsd_power_kbd, dbus.PROPERTIES_IFACE) 1137 1138 # Will return -1 if gsd-power crashed, and an exception if the code caught the problem 1139 with self.assertRaises(dbus.DBusException) as exc: 1140 kbd_brightness = obj_gsd_power_kbd_props.Get('org.gnome.SettingsDaemon.Power.Keyboard', 'Brightness') 1141 1142 # We should not have arrived here, if we did then the test failed, let's print this to help debugging 1143 print('Got keyboard brightness: {}'.format(kbd_brightness)) 1144 1145 self.assertEqual(exc.exception.get_dbus_message(), 'Failed to get property Brightness on interface org.gnome.SettingsDaemon.Power.Keyboard') 1146 1147 def test_inhibitor_idletime(self): 1148 ''' https://bugzilla.gnome.org/show_bug.cgi?id=705942 ''' 1149 1150 idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 1151 1152 self.settings_session['idle-delay'] = idle_delay 1153 self.settings_gsd_power['sleep-inactive-battery-timeout'] = 5 1154 self.settings_gsd_power['sleep-inactive-battery-type'] = 'suspend' 1155 1156 # create inhibitor 1157 inhibit_id = self.obj_session_mgr.Inhibit( 1158 'testsuite', dbus.UInt32(0), 'for testing', 1159 dbus.UInt32(gsdpowerenums.GSM_INHIBITOR_FLAG_IDLE), 1160 dbus_interface='org.gnome.SessionManager') 1161 self.check_no_suspend(idle_delay + 2) 1162 self.check_no_dim(0) 1163 1164 # Check that we didn't go to idle either 1165 self.assertEqual(self.get_status(), gsdpowerenums.GSM_PRESENCE_STATUS_AVAILABLE) 1166 1167 self.obj_session_mgr.Uninhibit(dbus.UInt32(inhibit_id), 1168 dbus_interface='org.gnome.SessionManager') 1169 1170 self.check_no_suspend(2) 1171 self.check_no_dim(0) 1172 1173 time.sleep(5) 1174 1175 self.check_suspend_no_hibernate(7) 1176 1177 def disabled_test_unindle_on_ac_plug(self): 1178 idle_delay = round(gsdpowerconstants.MINIMUM_IDLE_DIM_DELAY / gsdpowerconstants.IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER) 1179 self.settings_session['idle-delay'] = idle_delay 1180 1181 # Wait for idle 1182 self.check_dim(idle_delay + 2) 1183 1184 # Plug in the AC 1185 self.obj_upower.Set('org.freedesktop.UPower', 'OnBattery', False) 1186 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 1187 1188 # Check that we undim 1189 self.check_undim(gsdpowerconstants.POWER_UP_TIME_ON_AC / 2) 1190 1191 # And wait a little more to see us dim again 1192 self.check_dim(idle_delay + 2) 1193 1194 # Unplug the AC 1195 self.obj_upower.Set('org.freedesktop.UPower', 'OnBattery', True) 1196 self.obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock') 1197 1198 # Check that we undim 1199 self.check_undim(gsdpowerconstants.POWER_UP_TIME_ON_AC / 2) 1200 1201 # And wait a little more to see us dim again 1202 self.check_dim(idle_delay + 2) 1203 1204class PowerPluginTest8(PowerPluginBase): 1205 def test_brightness_stepping(self): 1206 '''Check that stepping the backlight works as expected''' 1207 1208 if self.skip_sysfs_backlight: 1209 self.skipTest("sysfs backlight support required for test") 1210 1211 obj_gsd_power = self.session_bus_con.get_object( 1212 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1213 obj_gsd_power_screen_iface = dbus.Interface(obj_gsd_power, 'org.gnome.SettingsDaemon.Power.Screen') 1214 1215 # Each of the step calls will only return when the value was written 1216 start = time.time() 1217 # We start at 50% and step by 5% each time 1218 obj_gsd_power_screen_iface.StepUp() 1219 self.assertEqual(self.get_brightness(), 55) 1220 obj_gsd_power_screen_iface.StepUp() 1221 self.assertEqual(self.get_brightness(), 60) 1222 obj_gsd_power_screen_iface.StepUp() 1223 self.assertEqual(self.get_brightness(), 65) 1224 obj_gsd_power_screen_iface.StepUp() 1225 self.assertEqual(self.get_brightness(), 70) 1226 stop = time.time() 1227 # This needs to take more than 0.8 seconds as each write is delayed by 1228 # 0.2 seconds by the test backlight helper 1229 self.assertGreater(stop - start, 0.8) 1230 1231 # Now, the same thing should work fine if we step multiple times, 1232 # even if we are so quick that compression will happen. 1233 # Use a list to keep rack of replies (as integer is immutable and would 1234 # not be modified in the outer scope) 1235 replies = [0] 1236 1237 def handle_reply(*args): 1238 replies[0] += 1 1239 1240 def last_reply(*args): 1241 replies[0] += 1 1242 loop.quit() 1243 1244 def error_handler(*args): 1245 loop.quit() 1246 1247 start = time.time() 1248 obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler) 1249 obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler) 1250 obj_gsd_power_screen_iface.StepDown(reply_handler=handle_reply, error_handler=error_handler) 1251 obj_gsd_power_screen_iface.StepDown(reply_handler=last_reply, error_handler=error_handler) 1252 loop = GLib.MainLoop() 1253 loop.run() 1254 stop = time.time() 1255 1256 # The calls need to be returned in order. As we got the last reply, all 1257 # others must have been received too. 1258 self.assertEqual(replies[0], 4) 1259 # Four steps down, so back at 50% 1260 self.assertEqual(self.get_brightness(), 50) 1261 # And compression must have happened, so it should take less than 0.8s 1262 self.assertLess(stop - start, 0.8) 1263 1264 def test_brightness_compression(self): 1265 '''Check that compression also happens when setting the property''' 1266 1267 if self.skip_sysfs_backlight: 1268 self.skipTest("sysfs backlight support required for test") 1269 1270 # Now test that the compression works correctly. 1271 # NOTE: Relies on the implementation detail, that the property setter 1272 # returns immediately rather than waiting for the brightness to 1273 # be updated. 1274 # Should this ever be fixed, then this will need to be changed to use 1275 # async dbus calls similar to the stepping code 1276 1277 obj_gsd_power = self.session_bus_con.get_object( 1278 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1279 obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE) 1280 1281 # Quickly ramp the brightness up 1282 for brightness in range(70, 91): 1283 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', brightness) 1284 1285 # The brightness of 80 should be in effect after slightly more than 1286 # 0.4 seconds. If compression does not work as expected, this would take 1287 # more than 5 seconds for the 20 steps. 1288 time.sleep(2.0) 1289 self.assertEqual(self.get_brightness(), 90) 1290 1291 def test_brightness_uevent(self): 1292 if self.skip_sysfs_backlight: 1293 self.skipTest("sysfs backlight support required for test") 1294 1295 obj_gsd_power = self.session_bus_con.get_object( 1296 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1297 obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE) 1298 1299 brightness = obj_gsd_power_prop_iface.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness') 1300 self.assertEqual(50, brightness) 1301 1302 # Check that the brightness is updated if it was changed through some 1303 # other mechanism (e.g. firmware). 1304 # Set to 80+1 because of the GSD offset (see add_backlight). 1305 self.testbed.set_attribute(self.backlight, 'brightness', '81') 1306 self.testbed.uevent(self.backlight, 'change') 1307 1308 self.check_plugin_log('GsdBacklight: Got uevent', 1, 'gsd-power did not process uevent') 1309 time.sleep(0.2) 1310 1311 brightness = obj_gsd_power_prop_iface.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness') 1312 self.assertEqual(80, brightness) 1313 1314 def test_brightness_step(self): 1315 if self.skip_sysfs_backlight: 1316 self.skipTest("sysfs backlight support required for test") 1317 1318 # We cannot use check_plugin_log here because the startup check already 1319 # read the relevant message. 1320 log = open(self.plugin_log_write.name, 'rb').read() 1321 self.assertIn(b'Step size for backlight is 5.', log) 1322 1323 def test_legacy_brightness_step(self): 1324 if self.skip_sysfs_backlight: 1325 self.skipTest("sysfs backlight support required for test") 1326 1327 # We cannot use check_plugin_log here because the startup check already 1328 # read the relevant message. 1329 log = open(self.plugin_log_write.name, 'rb').read() 1330 self.assertIn(b'Step size for backlight is 1.', log) 1331 1332 def test_legacy_brightness_rounding(self): 1333 if self.skip_sysfs_backlight: 1334 self.skipTest("sysfs backlight support required for test") 1335 1336 obj_gsd_power = self.session_bus_con.get_object( 1337 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1338 obj_gsd_power_prop_iface = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE) 1339 1340 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 0) 1341 time.sleep(0.4) 1342 self.assertEqual(self.get_brightness(), 0) 1343 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 10) 1344 time.sleep(0.4) 1345 self.assertEqual(self.get_brightness(), 2) 1346 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 20) 1347 time.sleep(0.4) 1348 self.assertEqual(self.get_brightness(), 3) 1349 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 25) 1350 time.sleep(0.4) 1351 self.assertEqual(self.get_brightness(), 4) 1352 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 49) 1353 time.sleep(0.4) 1354 self.assertEqual(self.get_brightness(), 7) 1355 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 50) 1356 time.sleep(0.4) 1357 self.assertEqual(self.get_brightness(), 8) 1358 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 56) 1359 time.sleep(0.4) 1360 self.assertEqual(self.get_brightness(), 8) 1361 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 57) 1362 time.sleep(0.4) 1363 self.assertEqual(self.get_brightness(), 9) 1364 obj_gsd_power_prop_iface.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 98) 1365 time.sleep(0.4) 1366 self.assertEqual(self.get_brightness(), 15) 1367 1368 def test_no_backlight(self): 1369 '''Check that backlight brightness DBus api without a backlight''' 1370 1371 obj_gsd_power = self.session_bus_con.get_object( 1372 'org.gnome.SettingsDaemon.Power', '/org/gnome/SettingsDaemon/Power') 1373 obj_gsd_power_props = dbus.Interface(obj_gsd_power, dbus.PROPERTIES_IFACE) 1374 obj_gsd_power_screen = dbus.Interface(obj_gsd_power, 'org.gnome.SettingsDaemon.Power.Screen') 1375 1376 # We expect -1 to be returned 1377 brightness = obj_gsd_power_props.Get('org.gnome.SettingsDaemon.Power.Screen', 'Brightness') 1378 self.assertEqual(brightness, -1) 1379 1380 # Trying to set the brightness 1381 with self.assertRaises(dbus.DBusException) as exc: 1382 obj_gsd_power_props.Set('org.gnome.SettingsDaemon.Power.Screen', 'Brightness', 1) 1383 1384 self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!') 1385 1386 with self.assertRaises(dbus.DBusException) as exc: 1387 obj_gsd_power_screen.StepUp() 1388 1389 self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!') 1390 1391 with self.assertRaises(dbus.DBusException) as exc: 1392 obj_gsd_power_screen.StepDown() 1393 1394 self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!') 1395 1396# avoid writing to stderr 1397unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) 1398