• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Server side bluetooth adapter stress tests involving power consumption."""
6
7import logging
8import multiprocessing
9import time
10
11from autotest_lib.client.common_lib import error
12from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
13from autotest_lib.server.cros.multimedia import remote_facade_factory
14
15
16test_case_log = bluetooth_adapter_tests.test_case_log
17
18
19class bluetooth_AdapterPowerMeasure(
20        bluetooth_adapter_tests.BluetoothAdapterTests):
21    """Server side bluetooth adapter power consumption test."""
22
23    # ---------------------------------------------------------------
24    # Definitions of all test cases
25    # ---------------------------------------------------------------
26
27    @test_case_log
28    def test_case_suspend_power_measurement(self, host, max_power_mw,
29                                            suspend_time_secs,
30                                            resume_network_timeout_secs=60):
31        """Test Case: measure the Bluetooth chip power consumption on suspend"""
32
33        def print_debug_count():
34            """Print the debug message about count values."""
35            logging.debug('count_fail_to_sleep: %d', self.count_fail_to_sleep)
36            logging.debug('count_fail_to_resume: %d', self.count_fail_to_resume)
37            logging.debug('count_system_resume_prematurely: %d',
38                          self.count_system_resume_prematurely)
39            logging.debug('count_success: %d', self.count_success)
40
41        def action_suspend():
42            """Calls the host method suspend."""
43            host.suspend(suspend_time=suspend_time_secs,
44                         allow_early_resume=True)
45
46        boot_id = host.get_boot_id()
47        proc = multiprocessing.Process(target=action_suspend)
48        proc.daemon = True
49        start_time = time.time()
50        proc.start()
51
52        # Block waiting until the system has suspended.
53        try:
54            host.test_wait_for_sleep(suspend_time_secs)
55        except Exception as e:
56            logging.error('host.test_wait_for_sleep failed: %s', e)
57            self.count_fail_to_sleep += 1
58            print_debug_count()
59            # Skip this time since the system failed to suspend.
60            proc.join()
61            return
62
63        # Test the Bluetooth chip power consumption.
64        if self.test_power_consumption(max_power_mw):
65            self.count_success += 1
66
67        # Block waiting until the system has resumed.
68        try:
69            host.test_wait_for_resume(
70                    boot_id, suspend_time_secs + resume_network_timeout_secs)
71        except Exception as e:
72            logging.error('host.test_wait_for_resume failed: %s', e)
73            self.count_fail_to_resume += 1
74
75        # If the system resumes prematurely, do not conduct the test in
76        # this iteration.
77        actual_suspend_time_secs = time.time() - start_time
78        if actual_suspend_time_secs < suspend_time_secs:
79            logging.error('actual suspension time %f is less than expected %f',
80                          actual_suspend_time_secs, suspend_time_secs)
81            self.count_system_resume_prematurely += 1
82
83        print_debug_count()
84        proc.join()
85
86
87    def initialize_servod(self):
88        """Peform initialize for servod task."""
89        self.count_fail_to_sleep = 0
90        self.count_fail_to_resume = 0
91        self.count_system_resume_prematurely = 0
92        self.count_success = 0
93
94        # When the autotest restarts ui, chrome would issue some Bluetooth
95        # commands which may prevent the system from suspending properly.
96        # Hence, let's stop ui for now.
97        self.host.run_short('stop ui')
98
99        board = self.host.get_board().split(':')[1]
100        logging.info('board: %s', board)
101
102        # TODO: figure out a way to support other boards.
103        if board != 'kukui':
104            raise error.TestError('Only kukui is supported for now.')
105
106        # self.device is a pure XMLRPC server running as chameleond
107        # on the chameleon host. We need to enable Servod.
108        if not self.device.EnableServod(board):
109            raise error.TestError('Failed to enable Servod.')
110
111        # Start the Servod process on the chameleon host.
112        if not self.device.servod.Start():
113            raise error.TestError('Failed to start Servod on chameleon host.')
114
115
116    def cleanup_servod(self):
117        """Peform cleanup for servod."""
118        if not self.device.servod.Stop():
119            logging.error('Failed to stop Servod on chameleon host.')
120
121        self.host.run_short('start ui')
122
123        logging.info('count_fail_to_sleep: %d', self.count_fail_to_sleep)
124        logging.info('count_fail_to_resume: %d', self.count_fail_to_resume)
125        logging.info('count_system_resume_prematurely: %d',
126                     self.count_system_resume_prematurely)
127        logging.info('count_success: %d', self.count_success)
128
129
130    def run_once(self, host, max_power_mw=3, device_type='BLUETOOTH_BASE',
131                 num_iterations=1, suspend_time_secs=30,
132                 test_category='suspension'):
133        """Running Bluetooth adapter power consumption autotest during system
134        suspension.
135
136        @param host: the DUT host.
137        @param max_power_mw: max power allowed in milli-watt
138        @param device_type: the device type emulated by the chameleon host
139        @param num_iterations: number of times to perform the tests.
140        @param suspend_time_secs: the system suspension duration in seconds
141        @param test_category: the test category
142
143        """
144
145        self.host = host
146        factory = remote_facade_factory.RemoteFacadeFactory(host,
147                                                            disable_arc=True)
148        self.bluetooth_facade = factory.create_bluetooth_hid_facade()
149
150        self.check_chameleon()
151        self.device = self.get_device(device_type)
152        self.initialize_servod()
153        self.test_power_on_adapter()
154        self.test_bluetoothd_running()
155
156        for i in xrange(1, num_iterations + 1):
157            logging.info('Starting iteration: %d / %d', i, num_iterations)
158
159            if test_category == 'suspension':
160                self.test_case_suspend_power_measurement(host, max_power_mw,
161                                                         suspend_time_secs)
162            else:
163                logging.error('Do not support the test category: %s',
164                              test_category)
165
166        if device_type == 'BLUETOOTH_BASE':
167            self.cleanup_servod()
168
169        if self.count_success == 0:
170            raise error.TestError('System failed to suspend/resume.')
171
172        if self.fails:
173            raise error.TestFail(self.fails)
174