289 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
| # Copyright 2016 The Chromium OS Authors. All rights reserved.
 | |
| # Use of this source code is governed by a BSD-style license that can be
 | |
| # found in the LICENSE file.
 | |
| 
 | |
| import logging
 | |
| import time
 | |
| 
 | |
| from autotest_lib.client.bin import utils
 | |
| from autotest_lib.client.common_lib import error
 | |
| from autotest_lib.client.cros import cryptohome
 | |
| from autotest_lib.client.cros.enterprise import enterprise_policy_base
 | |
| from autotest_lib.client.cros.graphics import graphics_utils
 | |
| from autotest_lib.client.cros.power import power_status, power_utils
 | |
| 
 | |
| 
 | |
| class policy_PowerManagementIdleSettings(
 | |
|           enterprise_policy_base.EnterprisePolicyTest):
 | |
|     """
 | |
|     Test effect of PowerManagementIdleSettings policy on Chrome OS behavior.
 | |
| 
 | |
|     This test verifies the effect of the PowerManagementIdleSettings user
 | |
|     policy on specific Chrome OS client behaviors. It tests two valid values
 | |
|     for the IdleAction property: 'DoNothing' and Not set, with three test
 | |
|     cases: DoNothing_Continue, NotSet_Sleep, and Logout_EndSession. It also
 | |
|     verifies that the screen dims after ScreenDim delay, and then turns off
 | |
|     after ScreenOff delay (both delays in milliseconds).
 | |
| 
 | |
|     Note: Valid IdleAction values are 'DoNothing', 'Suspend', 'Logout', and
 | |
|     'Shutdown'. This test exercises only the DoNothing and Logout actions.
 | |
|     Suspend is tested by enterprise_PowerManager.py. Shutdown can be tested
 | |
|     only using a Server-side AutoTest.
 | |
| 
 | |
|     Chrome reports user activity to the power manager at most every 5 seconds.
 | |
|     To accomodate potential delays, the test pads the idle-action delay with
 | |
|     a 5 second activity report interval.
 | |
| 
 | |
|     Several supporting policies are necessary to facillitate testing, or to
 | |
|     make testing more reliable. These policies are listed below with a brief
 | |
|     description of the set value.
 | |
|     - WaitForInitialUserActivity=False so idle timer starts immediately after
 | |
|       session starts.
 | |
|     - UserActivityScreenDimDelayScale=100 to prevent increase delays when
 | |
|       user activity occurs after screen dim.
 | |
|     - ChromeOsLockOnIdleSuspend=False to prevent screen lock upon suspend.
 | |
|     - AllowScreenLock=False to prevent manual screen lock. Will not affect
 | |
|       this test, but is the safest setting.
 | |
|     - AllowScreenWakeLocks=False to ignore 'keep awake' requests. Since wake
 | |
|       locks are not requested during this test, ignoring them is unnecessary.
 | |
|       But for safety we ignore them when testing suspend.
 | |
|     - LidCloseAction=3 to invoke no action upon (accidental) lid closure.
 | |
|     - ResoreOnStartup* polices are set to display the settings and policy
 | |
|       pages. This is useful when debugging failures.
 | |
| 
 | |
|     """
 | |
|     version = 1
 | |
| 
 | |
|     def initialize(self, **kwargs):
 | |
|         """Set up local variables and ensure device is on AC power."""
 | |
|         self._initialize_test_constants()
 | |
|         self._power_status = power_status.get_status()
 | |
|         if not self._power_status.on_ac():
 | |
|             raise error.TestNAError('Test must be run with DUT on AC power.')
 | |
|         self._backlight = power_utils.Backlight()
 | |
|         super(policy_PowerManagementIdleSettings, self).initialize(**kwargs)
 | |
| 
 | |
|     def _initialize_test_constants(self):
 | |
|         self.POLICY_NAME = 'PowerManagementIdleSettings'
 | |
|         self.SCREEN_SETTLE_TIME = 0.3
 | |
|         self.SCREEN_DIM_DELAY = 4
 | |
|         self.IDLE_WARNING_DELAY = 6
 | |
|         self.SCREEN_OFF_DELAY = 8
 | |
|         self.IDLE_ACTION_DELAY = 10
 | |
|         self.ACTIVITY_REPORT_INTERVAL = 5
 | |
|         self.IDLE_ACTION_NOTSET = {
 | |
|             'AC': {
 | |
|                 'Delays': {
 | |
|                     'ScreenDim': (self.SCREEN_DIM_DELAY * 1000),
 | |
|                     'IdleWarning': (self.IDLE_WARNING_DELAY * 1000),
 | |
|                     'ScreenOff': (self.SCREEN_OFF_DELAY * 1000),
 | |
|                     'Idle': (self.IDLE_ACTION_DELAY * 1000)
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         self.IDLE_ACTION_DONOTHING = {
 | |
|             'AC': {
 | |
|                 'Delays': {
 | |
|                     'ScreenDim': (self.SCREEN_DIM_DELAY * 1000),
 | |
|                     'IdleWarning': (self.IDLE_WARNING_DELAY * 1000),
 | |
|                     'ScreenOff': (self.SCREEN_OFF_DELAY * 1000),
 | |
|                     'Idle': (self.IDLE_ACTION_DELAY * 1000)
 | |
|                 },
 | |
|                 'IdleAction': 'DoNothing'
 | |
|             }
 | |
|         }
 | |
|         self.IDLE_ACTION_LOGOUT = {
 | |
|             'AC': {
 | |
|                 'Delays': {
 | |
|                     'ScreenDim': (self.SCREEN_DIM_DELAY * 1000),
 | |
|                     'IdleWarning': (self.IDLE_WARNING_DELAY * 1000),
 | |
|                     'ScreenOff': (self.SCREEN_OFF_DELAY * 1000),
 | |
|                     'Idle': (self.IDLE_ACTION_DELAY * 1000)
 | |
|                 },
 | |
|                 'IdleAction': 'Logout'
 | |
|             }
 | |
|         }
 | |
|         self.TEST_CASES = {
 | |
|             'NotSet_Sleep': self.IDLE_ACTION_NOTSET,
 | |
|             'DoNothing_Continue': self.IDLE_ACTION_DONOTHING,
 | |
|             'Logout_EndSession': self.IDLE_ACTION_LOGOUT
 | |
|         }
 | |
|         self.STARTUP_URLS = ['chrome://settings', 'chrome://policy']
 | |
|         self.SUPPORTING_POLICIES = {
 | |
|             'WaitForInitialUserActivity': True,
 | |
|             'UserActivityScreenDimDelayScale': 100,
 | |
|             'ChromeOsLockOnIdleSuspend': False,
 | |
|             'AllowScreenLock': False,
 | |
|             'AllowScreenWakeLocks': False,
 | |
|             'LidCloseAction': 3,
 | |
|             'RestoreOnStartup': 4,
 | |
|             'RestoreOnStartupURLs': self.STARTUP_URLS
 | |
|         }
 | |
| 
 | |
| 
 | |
|     def elapsed_time(self, start_time):
 | |
|         """Get time elapsed since |start_time|.
 | |
| 
 | |
|         @param start_time: clock time from which elapsed time is measured.
 | |
|         @returns time elapsed since the start time.
 | |
|         """
 | |
|         return time.time() - start_time
 | |
| 
 | |
| 
 | |
|     def _simulate_user_activity(self):
 | |
|         """Inject user activity via D-bus to restart idle timer.
 | |
| 
 | |
|         Note that if the screen has gone black, these use activities will
 | |
|         wake up the display again. However, they will not wake up a screen
 | |
|         that has merely been dimmed.
 | |
| 
 | |
|         """
 | |
|         graphics_utils.click_mouse()  # Note: Duration is 0.4 seconds.
 | |
|         graphics_utils.press_keys(['KEY_LEFTCTRL'])
 | |
| 
 | |
| 
 | |
|     def _wait_for_login_status(self, attribute, value, timeout):
 | |
|         """Return when attribute has value, or its current value on timeout.
 | |
| 
 | |
|         Login_status is a dictionary of attributes that describe the login
 | |
|         status of the current session. It contains values for the following
 | |
|         attributes: isLoggedIn, isRegularUser, isOwner, isKiosk, isGuest,
 | |
|         isScreenLocked, userImage, email, and displayEmail.
 | |
| 
 | |
|         @param attribute: String attribute key to be measured.
 | |
|         @param value: Boolean attribute value expected.
 | |
|         @param timeout: integer seconds till timeout.
 | |
|         @returns dict of login status.
 | |
| 
 | |
|         """
 | |
|         attribute_value = utils.wait_for_value(
 | |
|             lambda: self.cr.login_status[attribute],
 | |
|             expected_value=value,
 | |
|             timeout_sec=timeout)
 | |
|         return attribute_value
 | |
| 
 | |
| 
 | |
|     def _poll_until_user_is_logged_out(self, timeout):
 | |
|         """Return True when user logs out, False when user remains logged in.
 | |
| 
 | |
|         @returns boolean of user logged out status.
 | |
| 
 | |
|         """
 | |
|         my_result = utils.poll_for_condition(
 | |
|             lambda: not cryptohome.is_vault_mounted(user=self.username,
 | |
|                                                     allow_fail=True),
 | |
|             exception=None,
 | |
|             timeout=timeout,
 | |
|             sleep_interval=2,
 | |
|             desc='Polling for user to be logged out.')
 | |
|         return my_result
 | |
| 
 | |
| 
 | |
|     def _set_brightness_to_maximum(self):
 | |
|         """Set screen to maximum brightness."""
 | |
|         max_level = self._backlight.get_max_level()
 | |
|         self._backlight.set_level(max_level)
 | |
| 
 | |
| 
 | |
|     def _wait_for_brightness_change(self, timeout):
 | |
|         """Return screen brightness on update, or current value on timeout.
 | |
| 
 | |
|         @returns float of screen brightness percentage.
 | |
| 
 | |
|         """
 | |
|         initial_brightness = self._backlight.get_percent()
 | |
|         current_brightness = utils.wait_for_value_changed(
 | |
|             lambda: self._backlight.get_percent(),
 | |
|             old_value=initial_brightness,
 | |
|             timeout_sec=timeout)
 | |
|         if current_brightness != initial_brightness:
 | |
|             time.sleep(self.SCREEN_SETTLE_TIME)
 | |
|             current_brightness = self._backlight.get_percent()
 | |
|         return current_brightness
 | |
| 
 | |
| 
 | |
|     def _test_idle_action(self, policy_value):
 | |
|         """
 | |
|         Verify CrOS enforces PowerManagementIdleSettings policy value.
 | |
| 
 | |
|         @param policy_value: policy value for this case.
 | |
|         @raises: TestFail if idle actions are not performed after their
 | |
|                  specified delays.
 | |
| 
 | |
|         """
 | |
|         logging.info('Running _test_idle_action(%s)', policy_value)
 | |
| 
 | |
|         # Wait until UI settles down with user logged in.
 | |
|         user_is_logged_in = self._wait_for_login_status(
 | |
|             'isLoggedIn', True, self.IDLE_ACTION_DELAY)
 | |
|         if not user_is_logged_in:
 | |
|             raise error.TestFail('User must be logged in at start.')
 | |
| 
 | |
|         # Set screen to maxiumum brightness.
 | |
|         self._set_brightness_to_maximum()
 | |
|         max_brightness = self._backlight.get_percent()
 | |
|         logging.info('Brightness maximized to: %.2f', max_brightness)
 | |
| 
 | |
|         # Induce user activity to start idle timer.
 | |
|         self._simulate_user_activity()
 | |
|         start_time = time.time()
 | |
| 
 | |
|         # Verify screen is dimmed after expected delay.
 | |
|         seconds_to_dim = (
 | |
|             self.SCREEN_DIM_DELAY - self.elapsed_time(start_time))
 | |
|         dim_brightness = self._wait_for_brightness_change(seconds_to_dim)
 | |
|         dim_elapsed_time = self.elapsed_time(start_time)
 | |
|         logging.info('  Brightness dimmed to: %.2f, ', dim_brightness)
 | |
|         logging.info('  after %s seconds.', dim_elapsed_time)
 | |
|         if not (dim_brightness < max_brightness and dim_brightness > 0.0):
 | |
|             raise error.TestFail('Screen did not dim on delay.')
 | |
| 
 | |
|         # Verify screen is turned off after expected delay.
 | |
|         seconds_to_off = (
 | |
|             self.SCREEN_OFF_DELAY - self.elapsed_time(start_time))
 | |
|         off_brightness = self._wait_for_brightness_change(seconds_to_off)
 | |
|         off_elapsed_time = self.elapsed_time(start_time)
 | |
|         logging.info('  Brightness off to: %.2f, ', off_brightness)
 | |
|         logging.info('  after %s seconds.', off_elapsed_time)
 | |
|         if not off_brightness < dim_brightness:
 | |
|             raise error.TestFail('Screen did not turn off on delay.')
 | |
| 
 | |
|         # Verify user is still logged in before IdleAction.
 | |
|         user_is_logged_in = self.cr.login_status['isLoggedIn']
 | |
|         if not user_is_logged_in:
 | |
|             raise error.TestFail('User must be logged in before idle action.')
 | |
| 
 | |
|         # Get user logged in state after IdleAction.
 | |
|         seconds_to_action = (
 | |
|             self.IDLE_ACTION_DELAY + self.ACTIVITY_REPORT_INTERVAL
 | |
|             - self.elapsed_time(start_time))
 | |
|         try:
 | |
|             user_is_logged_in = not self._poll_until_user_is_logged_out(
 | |
|                 seconds_to_action)
 | |
|         except utils.TimeoutError:
 | |
|             pass
 | |
|         action_elapsed_time = self.elapsed_time(start_time)
 | |
|         logging.info('  User logged out: %r, ', not user_is_logged_in)
 | |
|         logging.info('  after %s seconds.', action_elapsed_time)
 | |
| 
 | |
|         # Verify user status against expected result, based on case.
 | |
|         if self.case == 'NotSet_Sleep' or self.case == 'DoNothing_Continue':
 | |
|             if not user_is_logged_in:
 | |
|                 raise error.TestFail('User should be logged in.')
 | |
|         elif self.case == 'Logout_EndSession':
 | |
|             if user_is_logged_in:
 | |
|                 raise error.TestFail('User should be logged out.')
 | |
| 
 | |
| 
 | |
|     def run_once(self, case):
 | |
|         """
 | |
|         Setup and run the test configured for the specified test case.
 | |
| 
 | |
|         @param case: Name of the test case to run.
 | |
| 
 | |
|         """
 | |
|         case_value = self.TEST_CASES[case]
 | |
|         self.SUPPORTING_POLICIES[self.POLICY_NAME] = case_value
 | |
|         self.setup_case(user_policies=self.SUPPORTING_POLICIES)
 | |
|         self._test_idle_action(case_value)
 |