blob: d6bfa16c0d42cda379eba2cb6d4747c5635be887 [file] [log] [blame]
# Copyright 2014 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.
"""A basic battery test.
Description
-----------
This is a basic battery test that charges and discharges the battery on DUT.
The goal of this factory test is to perform a quick basic verification of
battery functions (typically less than 30 seconds).
Test Procedure
--------------
1. Prompt the operator to plug in the AC power source.
2. The battery current is sampled periodically, and its value is checked.
3. Prompt the operator to unplug the AC power source.
4. The battery current is sampled periodically, and its value is checked.
5. Prompt the operator to plug in the AC power source, again.
6. The battery current is sampled periodically, and its value is checked.
Dependency
----------
Depend on the sysfs driver to control and read information from the battery.
Examples
--------
To perform a basic battery test, add this in test list::
{
"pytest_name": "battery_basic"
}
To relax the limitation of battery cycle count to 5::
{
"pytest_name": "battery_basic",
"args": {
"max_cycle_count": 5
}
}
"""
from __future__ import print_function
import logging
import factory_common # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.test.i18n import _
from cros.factory.test import test_case
from cros.factory.test.utils import stress_manager
from cros.factory.utils.arg_utils import Arg
from cros.factory.utils import sync_utils
from cros.factory.utils import time_utils
class SimpleBatteryTest(test_case.TestCase):
"""A simple battery test."""
ARGS = [
Arg('charge_duration_secs', type=(int, float), default=5,
help='the duration in seconds to charge the battery'),
Arg('discharge_duration_secs', type=(int, float), default=5,
help='the duration in seconds to discharge the battery'),
Arg('min_charge_current_mA', type=(int, float), default=None,
help=('the minimum charge current in mA that the battery needs to '
'reach during charge test')),
Arg('min_discharge_current_mA', type=(int, float), default=-2000,
help=('the minimum discharge current in mA that the battery needs to '
'reach during discharge test')),
Arg('current_sampling_period_secs', type=(int, float), default=0.5,
help=('the period in seconds to sample charge/discharge current '
'during test')),
Arg('max_cycle_count', type=int, default=1,
help=('the maximum cycle count beyond which the battery is considered'
'used')),
]
def setUp(self):
self._dut = device_utils.CreateDUTInterface()
if self.args.min_charge_current_mA:
self.assertGreater(self.args.min_charge_current_mA, 0,
'min_charge_current_mA must be greater than zero')
if self.args.min_discharge_current_mA:
self.assertLess(self.args.min_discharge_current_mA, 0,
'min_discharge_current_mA must be less than zero')
self.ui.ToggleTemplateClass('font-large', True)
def SampleBatteryCurrent(self, duration_secs):
"""Samples battery current for a given duration.
Args:
duration_secs: The duration in seconds to sample battery current.
Returns:
A list of sampled battery current.
"""
sampled_current = []
end_time = time_utils.MonotonicTime() + duration_secs
while time_utils.MonotonicTime() < end_time:
sampled_current.append(self._dut.power.GetBatteryCurrent())
self.Sleep(self.args.current_sampling_period_secs)
logging.info('Sampled battery current: %s', sampled_current)
return sampled_current
def TestCharge(self, duration_secs):
"""Tests battery charging for a given duration.
Args:
duration_secs: The duration in seconds to test charging the battery.
Raises:
TestFailure if the sampled battery charge current does not pass
the given threshold in dargs.
"""
self.ui.SetState(_('Plug AC to proceed'))
sync_utils.WaitFor(self._dut.power.CheckACPresent, timeout_secs=10)
self.ui.SetState(_('Testing battery charge...'))
self._dut.power.SetChargeState(self._dut.power.ChargeState.CHARGE)
sampled_current = self.SampleBatteryCurrent(duration_secs)
if self.args.min_charge_current_mA:
self.assertGreaterEqual(
max(sampled_current), self.args.min_charge_current_mA,
'Battery charge current did not reach defined threshold %f mA' %
self.args.min_charge_current_mA)
else:
self.assertGreater(
max(sampled_current), 0,
'Battery was not charging during charge test')
def TestDischarge(self, duration_secs):
"""Tests battery discharging for a given duration.
The test runs under high system load to maximize battery discharge current.
Args:
duration_secs: The duration in seconds to test discharging the battery.
Raises:
TestFailure if the sampled battery discharge current does not pass
the given threshold in dargs.
"""
self.ui.SetState(_('Unplug AC to proceed'))
sync_utils.WaitFor(lambda: not self._dut.power.CheckACPresent(),
timeout_secs=10)
self.ui.SetState(_('Testing battery discharge...'))
# Discharge under high system load.
with stress_manager.StressManager(self._dut).Run(duration_secs):
sampled_current = self.SampleBatteryCurrent(duration_secs)
if self.args.min_discharge_current_mA:
self.assertLessEqual(
min(sampled_current), self.args.min_discharge_current_mA,
'Battery discharge current did not reach defined threshold %f mA' %
self.args.min_discharge_current_mA)
else:
self.assertLess(
min(sampled_current), 0,
'Battery was not discharging during charge test')
def runTest(self):
self.assertTrue(self._dut.power.CheckBatteryPresent(),
'Cannot locate battery sysfs path. Missing battery?')
cycle_count = self._dut.power.GetBatteryCycleCount()
self.assertLessEqual(
cycle_count, self.args.max_cycle_count,
'Battery cycle count %d exceeds max %d' % (cycle_count,
self.args.max_cycle_count))
self.TestCharge(self.args.charge_duration_secs)
self.TestDischarge(self.args.discharge_duration_secs)
self.TestCharge(self.args.charge_duration_secs)