blob: 3f8f27bd1726030c9294f997cd212efb699b483d [file] [log] [blame]
# Copyright (c) 2012 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 json, logging, threading, time, traceback
from autotest_lib.client.common_lib import error
from autotest_lib.server import autotest, test
from autotest_lib.server.cros.faft.config.config import Config as FAFTConfig
_RETRY_SUSPEND_ATTEMPTS = 1
_RETRY_SUSPEND_MS = 10000
_SUSPEND_WAIT_SECONDS = 30
_BOOT_WAIT_SECONDS = 100
class power_SuspendShutdown(test.test):
"""Test power manager fallback to power-off if suspend fails."""
version = 1
def initialize(self, host):
"""
Initial settings before running test.
@param host: Host/DUT object to run test on.
"""
# save original boot id
self.orig_boot_id = host.get_boot_id()
self.host = host
# override /sys/power/state via bind mount
logging.info('binding /dev/full to /sys/power/state')
host.run('mount --bind /dev/full /sys/power/state')
# override suspend retry attempts via bind mount
logging.info('settings retry_suspend_attempts to %s',
_RETRY_SUSPEND_ATTEMPTS)
host.run('echo %s > /tmp/retry_suspend_attempts;'
' mount --bind /tmp/retry_suspend_attempts'
' /usr/share/power_manager/retry_suspend_attempts'
% _RETRY_SUSPEND_ATTEMPTS)
# override suspend retry interval via bind mount
logging.info('settings retry_suspend_ms to %s',
_RETRY_SUSPEND_MS)
host.run('echo %s > /tmp/retry_suspend_ms;'
' mount --bind /tmp/retry_suspend_ms'
' /usr/share/power_manager/retry_suspend_ms'
% _RETRY_SUSPEND_MS)
# restart powerd to pick up new retry settings
logging.info('restarting powerd')
host.run('restart powerd')
time.sleep(2)
def platform_check(self, platform_name):
"""
Raises error if device does not have a lid.
@param platform_name: Name of the platform
"""
client_attr = FAFTConfig(platform_name)
if not client_attr.has_lid:
raise error.TestError(
'This test does nothing on devices without a lid.')
if client_attr.chrome_ec and not 'lid' in client_attr.ec_capability:
raise error.TestNAError("TEST IT MANUALLY! Chrome EC can't control "
"lid on the device %s" % client_attr.platform)
def login_into_dut(self, client_autotest, thread_started_evt,
exit_without_logout=True):
"""
Runs the Desktopui_Simple login client test in a seperate thread. The
Desktopui_Simple client test will exit without logout.
@param client_autotest: Client autotest name to login into DUT
@param thread_started_evt: Thread attribute to start the thread
@param exit_without_logout: if flag is set thread exists without logout.
if not set, thread will wait fot logout
event.
"""
logging.info('Login into client started')
thread_started_evt.set()
try:
self.autotest_client.run_test(client_autotest,
exit_without_logout=
exit_without_logout)
except:
logging.info('DUT login process failed')
def create_thread(self, client_autotest, exit_without_logout):
"""
Created seperate thread for client test
@param client_autotest: Client autotest name to login into DUT
@param exit_without_logout: if flag is set thread exists without logout.
if not set, thread will wait fot logout
event.
@return t: thread object
"""
thread_started_evt = threading.Event()
logging.info('Launching Desktopui_simplelogin thread')
try:
t = threading.Thread(target=self.login_into_dut,
args=(client_autotest,
thread_started_evt, exit_without_logout))
except:
raise error.TestError('Thread creation failed')
t.start()
thread_started_evt.wait()
logging.info('Login thread started')
return t
def logged_in(self):
"""
Checks if the host has a logged in user.
@param host: Host/DUT object
@return True if a user is logged in on the device.
"""
host = self.host
try:
out = host.run('cryptohome --action=status').stdout.strip()
except:
return False
try:
status = json.loads(out)
except ValueError:
logging.info('Cryptohome did not return a value, retrying.')
return False
return any((mount['mounted'] for mount in status['mounts']))
def run_once(self, client_autotest):
"""
Run the acutal test on device.
@param client_autotest: Client autotest name to login into DUT
@param host: Host/DUT object
"""
# check platform is capable of running the test
host = self.host
platform = host.run_output('mosys platform name')
self.platform_check(platform)
self.autotest_client = autotest.Autotest(host)
logging.info('platform is %s', platform)
exit_without_logout = True
t = self.create_thread(client_autotest, exit_without_logout)
t.join()
# Waiting for the login thread to finish
max_wait_time = 15
for check_count in range(int(max_wait_time)):
if check_count == max_wait_time:
raise error.TestError('Login thread is still'
'alive after %s seconds' % max_wait_time)
if t.is_alive():
time.sleep(1)
else:
logging.info('Login thread successfully finished')
break
# close the lid while logged_in to initiate suspend
logging.info('closing lid')
host.servo.lid_close()
# wait for power manager to give up and shut down
logging.info('waiting for power off')
host.wait_down(timeout=_SUSPEND_WAIT_SECONDS,
old_boot_id=self.orig_boot_id)
# ensure host is now off
if host.is_up():
raise error.TestFail('DUT still up with lid closed')
else:
logging.info('good, host is now off')
# restart host
host.servo.lid_open()
host.wait_up(timeout=_BOOT_WAIT_SECONDS)
def cleanup(self):
"""Clean up the mounts and restore the settings."""
# reopen lid - might still be closed due to failure
host = self.host
logging.info('reopening lid')
host.servo.lid_open()
# try to clean up the mess we've made if shutdown failed
if host.get_boot_id() == self.orig_boot_id:
# clean up mounts
logging.info('cleaning up bind mounts')
host.run('umount /sys/power/state'
' /usr/share/power_manager/retry_suspend_attempts'
' /usr/share/power_manager/retry_suspend_ms',
ignore_status=True)
# restart powerd to pick up old retry settings
host.run('restart powerd')
# Reboot Device to logout and cleanup
logging.info('Server: reboot client')
try:
self.host.reboot()
except error.AutoservRebootError as e:
raise error.TestFail('%s.\nTest failed with error %s' % (
traceback.format_exc(), str(e)))