| # 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) |