blob: 4a16128e5cf275ff66daef1cf2c8b45fcf7f378f [file] [log] [blame]
# Copyright 2019 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.
"""Server side bluetooth adapter stress tests involving power consumption."""
import logging
import multiprocessing
import time
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
from autotest_lib.server.cros.multimedia import remote_facade_factory
test_case_log = bluetooth_adapter_tests.test_case_log
class bluetooth_AdapterPowerMeasure(
bluetooth_adapter_tests.BluetoothAdapterTests):
"""Server side bluetooth adapter power consumption test."""
# ---------------------------------------------------------------
# Definitions of all test cases
# ---------------------------------------------------------------
@test_case_log
def test_case_suspend_power_measurement(self, host, max_power_mw,
suspend_time_secs,
resume_network_timeout_secs=60):
"""Test Case: measure the Bluetooth chip power consumption on suspend"""
def print_debug_count():
"""Print the debug message about count values."""
logging.debug('count_fail_to_sleep: %d', self.count_fail_to_sleep)
logging.debug('count_fail_to_resume: %d', self.count_fail_to_resume)
logging.debug('count_system_resume_prematurely: %d',
self.count_system_resume_prematurely)
logging.debug('count_success: %d', self.count_success)
def action_suspend():
"""Calls the host method suspend."""
host.suspend(suspend_time=suspend_time_secs,
allow_early_resume=True)
boot_id = host.get_boot_id()
proc = multiprocessing.Process(target=action_suspend)
proc.daemon = True
start_time = time.time()
proc.start()
# Block waiting until the system has suspended.
try:
host.test_wait_for_sleep(suspend_time_secs)
except Exception as e:
logging.error('host.test_wait_for_sleep failed: %s', e)
self.count_fail_to_sleep += 1
print_debug_count()
# Skip this time since the system failed to suspend.
proc.join()
return
# Test the Bluetooth chip power consumption.
if self.test_power_consumption(max_power_mw):
self.count_success += 1
# Block waiting until the system has resumed.
try:
host.test_wait_for_resume(
boot_id, suspend_time_secs + resume_network_timeout_secs)
except Exception as e:
logging.error('host.test_wait_for_resume failed: %s', e)
self.count_fail_to_resume += 1
# If the system resumes prematurely, do not conduct the test in
# this iteration.
actual_suspend_time_secs = time.time() - start_time
if actual_suspend_time_secs < suspend_time_secs:
logging.error('actual suspension time %f is less than expected %f',
actual_suspend_time_secs, suspend_time_secs)
self.count_system_resume_prematurely += 1
print_debug_count()
proc.join()
def initialize_servod(self):
"""Peform initialize for servod task."""
self.count_fail_to_sleep = 0
self.count_fail_to_resume = 0
self.count_system_resume_prematurely = 0
self.count_success = 0
# When the autotest restarts ui, chrome would issue some Bluetooth
# commands which may prevent the system from suspending properly.
# Hence, let's stop ui for now.
self.host.run_short('stop ui')
board = self.host.get_board().split(':')[1]
logging.info('board: %s', board)
# TODO: figure out a way to support other boards.
if board != 'kukui':
raise error.TestError('Only kukui is supported for now.')
# self.device is a pure XMLRPC server running as chameleond
# on the chameleon host. We need to enable Servod.
if not self.device.EnableServod(board):
raise error.TestError('Failed to enable Servod.')
# Start the Servod process on the chameleon host.
if not self.device.servod.Start():
raise error.TestError('Failed to start Servod on chameleon host.')
def cleanup_servod(self):
"""Peform cleanup for servod."""
if not self.device.servod.Stop():
logging.error('Failed to stop Servod on chameleon host.')
self.host.run_short('start ui')
logging.info('count_fail_to_sleep: %d', self.count_fail_to_sleep)
logging.info('count_fail_to_resume: %d', self.count_fail_to_resume)
logging.info('count_system_resume_prematurely: %d',
self.count_system_resume_prematurely)
logging.info('count_success: %d', self.count_success)
def check_legitimate_board(self):
"""Check if this is a legitimate board to run the test.
Only a limited set of boards are supported for now, primarliy
the kukui family of barods.
@raises: TestNAError if the board is not legitimate.
"""
board = self.host.get_board().split(':')[1]
if board not in ('kukui'):
raise error.TestNAError('%s not legitimate to run the test.' %
board)
def run_once(self, host, max_power_mw=3, device_type='BLUETOOTH_BASE',
num_iterations=1, suspend_time_secs=30,
test_category='suspension'):
"""Running Bluetooth adapter power consumption autotest during system
suspension.
@param host: the DUT host.
@param max_power_mw: max power allowed in milli-watt
@param device_type: the device type emulated by the chameleon host
@param num_iterations: number of times to perform the tests.
@param suspend_time_secs: the system suspension duration in seconds
@param test_category: the test category
"""
self.host = host
self.check_legitimate_board()
factory = remote_facade_factory.RemoteFacadeFactory(host,
disable_arc=True)
self.bluetooth_facade = factory.create_bluetooth_hid_facade()
self.check_chameleon()
self.device = self.get_device(device_type)
self.initialize_servod()
self.test_power_on_adapter()
self.test_bluetoothd_running()
for i in xrange(1, num_iterations + 1):
logging.info('Starting iteration: %d / %d', i, num_iterations)
if test_category == 'suspension':
self.test_case_suspend_power_measurement(host, max_power_mw,
suspend_time_secs)
else:
logging.error('Do not support the test category: %s',
test_category)
if device_type == 'BLUETOOTH_BASE':
self.cleanup_servod()
if self.count_success == 0:
raise error.TestError('System failed to suspend/resume.')
if self.fails:
raise error.TestFail(self.fails)