| # Copyright 2017 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. |
| |
| """Test that waits the battery to be charged to specific level. |
| |
| Description |
| ----------- |
| The test waits until the battery is charged to the given level, and pass. |
| |
| The ``target_charge_pct`` sets the target charge level in percentage. |
| ``target_charge_pct`` can be set to some special values: |
| |
| * ``"goofy"``: Use ``min_charge_pct`` from Goofy's charge_manager plugin as |
| target charge level. |
| * ``"cutoff"``: Use ``CUTOFF_BATTERY_MIN_PERCENTAGE`` from cutoff.json as |
| target charge level. |
| |
| If ``target_charge_pct_is_delta`` is True, ``target_charge_pct`` would be |
| interpreted as difference to current charge level. |
| |
| If battery doesn't reach the target level in ``timeout_secs`` seconds, the test |
| would fail. |
| |
| Test Procedure |
| -------------- |
| This is an automated test without user interaction. |
| |
| 1. A screen would be shown with current battery level, target battery level, |
| and time remaining. |
| 2. Test would pass when battery reach target level, or fail if test run longer |
| than ``timeout_secs``. |
| |
| Dependency |
| ---------- |
| Device API `cros.factory.device.power`. |
| |
| Examples |
| -------- |
| To charge the device to ``min_charge_pct`` in Goofy charge_manager (default |
| behavior), add this in test list:: |
| |
| { |
| "pytest_name": "blocking_charge", |
| "exclusive_resources": ["POWER"] |
| } |
| |
| To charge the device to minimum battery level needed for cutoff, add this in |
| test list:: |
| |
| { |
| "pytest_name": "blocking_charge", |
| "exclusive_resources": ["POWER"], |
| "args": { |
| "target_charge_pct": "cutoff" |
| } |
| } |
| |
| To charge the device to 75 percent, add this in test list:: |
| |
| { |
| "pytest_name": "blocking_charge", |
| "exclusive_resources": ["POWER"], |
| "args": { |
| "target_charge_pct": 75 |
| } |
| } |
| |
| To charge the device 10 percent more, and only allow 5 minutes time for |
| charging, add this in test list:: |
| |
| { |
| "pytest_name": "blocking_charge", |
| "exclusive_resources": ["POWER"], |
| "args": { |
| "target_charge_pct_is_delta": true, |
| "timeout_secs": 300, |
| "target_charge_pct": 20 |
| } |
| } |
| """ |
| |
| import logging |
| import os |
| |
| import factory_common # pylint: disable=unused-import |
| from cros.factory.device import device_utils |
| from cros.factory.test.env import paths |
| from cros.factory.test import event_log # TODO(chuntsen): Deprecate event log. |
| from cros.factory.test.i18n import _ |
| from cros.factory.test import test_case |
| from cros.factory.test.utils import goofy_plugin_utils |
| from cros.factory.testlog import testlog |
| from cros.factory.utils.arg_utils import Arg |
| from cros.factory.utils import config_utils |
| from cros.factory.utils import type_utils |
| |
| _DEFAULT_TARGET_CHARGE = 78 |
| |
| |
| def FormatTime(seconds): |
| return '%d:%02d:%02d' % (seconds / 3600, (seconds / 60) % 60, seconds % 60) |
| |
| |
| def MakeChargeTextLabel(start, current, target, elapsed, remaining): |
| return _( |
| 'Charging to {target}% (Start: {start}%. Current: {current}%.)<br>' |
| 'Time elapsed: {elapsed} Time remaining: {remaining}', |
| target=target, |
| start=start, |
| current=current, |
| elapsed=FormatTime(elapsed), |
| remaining=FormatTime(remaining)) |
| |
| |
| def MakeSpriteHTMLTag(src, height, width): |
| return ('<div id="batteryIcon" style="background-image: url(%s);' |
| 'width: %dpx; height: %dpx; margin: auto;"></div>') % (src, width, |
| height) |
| |
| |
| def _GetCutoffBatteryMinPercentage(): |
| config = config_utils.LoadConfig( |
| config_name='cutoff', |
| default_config_dirs=os.path.join(paths.FACTORY_DIR, 'sh', 'cutoff')) |
| return config.get('CUTOFF_BATTERY_MIN_PERCENTAGE', _DEFAULT_TARGET_CHARGE) |
| |
| |
| def _GetGoofyBatteryMinPercentage(): |
| config = goofy_plugin_utils.GetPluginArguments('charge_manager') or {} |
| return config.get('min_charge_pct', _DEFAULT_TARGET_CHARGE) |
| |
| |
| class ChargerTest(test_case.TestCase): |
| ARGS = [ |
| Arg('target_charge_pct', (int, type_utils.Enum(['goofy', 'cutoff'])), |
| 'Target charge level.', default='goofy'), |
| Arg('target_charge_pct_is_delta', bool, |
| 'Specify target_charge_pct is a delta of current charge', |
| default=False), |
| Arg('timeout_secs', int, 'Maximum allowed time to charge battery', |
| default=3600), |
| ] |
| |
| def setUp(self): |
| self._power = device_utils.CreateDUTInterface().power |
| |
| # Group checker for Testlog. |
| self._group_checker = testlog.GroupParam('charge', ['charge', 'elapsed']) |
| |
| def runTest(self): |
| self.assertTrue(self._power.CheckBatteryPresent(), 'Cannot find battery.') |
| self.assertTrue(self._power.CheckACPresent(), 'Cannot find AC power.') |
| |
| start_charge = self._power.GetChargePct() |
| self.assertTrue(start_charge, 'Error getting battery state.') |
| |
| target_charge = self.args.target_charge_pct |
| if self.args.target_charge_pct_is_delta: |
| self.assertIsInstance(target_charge, int, |
| 'target_charge must be int when ' |
| 'target_charge_pct_is_delta is True.') |
| target_charge = min(target_charge + start_charge, 100) |
| elif target_charge == 'cutoff': |
| target_charge = _GetCutoffBatteryMinPercentage() |
| elif target_charge == 'goofy': |
| target_charge = _GetGoofyBatteryMinPercentage() |
| |
| logging.info('Target charge is %d%%', target_charge) |
| testlog.LogParam('start_charge', start_charge) |
| testlog.LogParam('target_charge', target_charge) |
| if start_charge >= target_charge: |
| return |
| |
| self._power.SetChargeState(self._power.ChargeState.CHARGE) |
| self.ui.SetState(MakeSpriteHTMLTag('charging_sprite.png', 256, 256)) |
| logging.info('Charging starting at %d%%', start_charge) |
| |
| for elapsed in xrange(self.args.timeout_secs): |
| charge = self._power.GetChargePct() |
| |
| if charge >= target_charge: |
| event_log.Log('charged', charge=charge, target=target_charge, |
| elapsed=elapsed) |
| with self._group_checker: |
| testlog.CheckNumericParam('charge', charge, min=target_charge) |
| testlog.LogParam('elapsed', elapsed) |
| return |
| self.ui.RunJS( |
| 'document.getElementById("batteryIcon").style.backgroundPosition' |
| ' = "-%dpx 0px"' % ((elapsed % 4) * 256)) |
| self.ui.SetInstruction(MakeChargeTextLabel( |
| start_charge, |
| charge, |
| target_charge, |
| elapsed, |
| self.args.timeout_secs - elapsed)) |
| |
| if elapsed % 300 == 0: |
| logging.info('Battery level is %d%% after %d minutes', |
| charge, |
| elapsed / 60) |
| self.Sleep(1) |
| |
| event_log.Log('failed_to_charge', charge=charge, target=target_charge, |
| timeout_sec=self.args.timeout_secs) |
| self.FailTask('Cannot charge battery to %d%% in %d seconds.' % |
| (target_charge, self.args.timeout_secs)) |