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.
4import logging
5
6from autotest_lib.client.bin import test
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib.cros import chrome
9from autotest_lib.client.common_lib import utils
10from autotest_lib.client.cros.power import power_status
11from autotest_lib.client.cros.power import power_utils
12
13class power_BatteryDrain(test.test):
14    """Not a test, but a utility for server tests to drain the battery below
15    a certain threshold within a certain timeframe."""
16    version = 1
17
18    backlight = None
19    keyboard_backlight = None
20
21    url = 'https://crospower.page.link/power_BatteryDrain'
22
23    def cleanup(self):
24        '''Cleanup for a test run'''
25        if self._force_discharge:
26            if not power_utils.charge_control_by_ectool(True):
27                logging.warn('Can not restore from force discharge.')
28        if self.backlight:
29            self.backlight.restore()
30        if self.keyboard_backlight:
31            default_level = self.keyboard_backlight.get_default_level()
32            self.keyboard_backlight.set_level(default_level)
33
34    def run_once(self, drain_to_percent, drain_timeout, force_discharge=False):
35        '''
36        Entry point of this test. The DUT must not be connected to AC.
37
38        It turns the screen and keyboard backlight up as high as possible, and
39        then opens Chrome to a WebGL heavy webpage. I also tried using a
40        dedicated tool for stress-testing the CPU
41        (https://github.com/intel/psst), but that only drew 27 watts on my DUT,
42        compared with 35 watts using the WebGL website. If you find a better
43        way to use a lot of power, please modify this test!
44
45        @param drain_to_percent: Battery percentage to drain to.
46        @param drain_timeout: In seconds.
47        @param force_discharge: Force discharge even with AC plugged in.
48        '''
49        status = power_status.get_status()
50        if not status.battery:
51            raise error.TestNAError('DUT has no battery. Test Skipped')
52
53        self._force_discharge = force_discharge
54        if force_discharge:
55            if not power_utils.charge_control_by_ectool(False):
56                raise error.TestError('Could not run battery force discharge.')
57
58        ac_error = error.TestFail('DUT is on AC power, but should not be')
59        if not force_discharge and status.on_ac():
60            raise ac_error
61
62        self.backlight = power_utils.Backlight()
63        self.backlight.set_percent(100)
64        try:
65            self.keyboard_backlight = power_utils.KbdBacklight()
66            self.keyboard_backlight.set_percent(100)
67        except power_utils.KbdBacklightException as e:
68            logging.info("Assuming no keyboard backlight due to %s", str(e))
69            self.keyboard_backlight = None
70
71        with chrome.Chrome(init_network_controller=True) as cr:
72            tab = cr.browser.tabs.New()
73            tab.Navigate(self.url)
74
75            logging.info(
76                'Waiting {} seconds for battery to drain to {} percent'.format(
77                    drain_timeout, drain_to_percent))
78
79            def is_battery_low_enough():
80                """Check if battery level reach target."""
81                status.refresh()
82                if not force_discharge and status.on_ac():
83                    raise ac_error
84                return status.percent_display_charge() <= drain_to_percent
85
86            err = error.TestFail(
87                "Battery did not drain to {} percent in {} seconds".format(
88                    drain_to_percent, drain_timeout))
89            utils.poll_for_condition(is_battery_low_enough,
90                                            exception=err,
91                                            timeout=drain_timeout,
92                                            sleep_interval=1)
93