power: Add test to use Servo v4 to charge the DUT

Add a server side test that controls charging the DUT. This server
side test first makes sure that the attached Servo v4 can control
charging the DUT, then puts the DUT on AC to charge, and finally
disconnect DUT from AC.

BUG=b:117681170
TEST=see following
test_that <dut ip> power_BatteryChargeControl.args \
--autotest_dir ~/trunk/src/third_party/autotest/files/ \
--args 'servo_host=localhost servo_port=9999 percent_charge_to_add=.5'

test_that <dut ip> power_BatteryChargeControl.args \
--autotest_dir ~/trunk/src/third_party/autotest/files/ \
--args 'servo_host=localhost servo_port=9999 percent_target_charge=83'

test_that <dut ip> power_BatteryCharge.args \
--autotest_dir ~/trunk/src/third_party/autotest/files/ \
--args 'percent_target_charge=3'

test_that <dut ip> power_BatteryChargeControl.charge70 \
--autotest_dir ~/trunk/src/third_party/autotest/files/

Change-Id: I530dde75fae74661436437cc4126bff3560367ef
Signed-off-by: Mengqi Guo <mqg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1285530
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Puthikorn Voravootivat <puthik@chromium.org>
diff --git a/client/site_tests/power_BatteryCharge/control b/client/site_tests/power_BatteryCharge/control
index 0aabcd1..10e3b96 100644
--- a/client/site_tests/power_BatteryCharge/control
+++ b/client/site_tests/power_BatteryCharge/control
@@ -12,13 +12,10 @@
 TEST_TYPE = "client"
 
 DOC = """
-This test enforces the following contraints:
- - Initial battery charge < 5%
- - Device should be plugged in to an AC outlet
- - In 4 hours, the battery charge should increase by at least 94% of maximum
+Device should be plugged into an AC outlet.
 
 This test depends on power_status.py, which is included in
-client/cros/ in AutoTest. power_status.py has many status
+autotest/files/client/cros/power/. power_status.py has many status
 initialization and parsing routines for battery status.
 """
 
diff --git a/client/site_tests/power_BatteryCharge/control.args b/client/site_tests/power_BatteryCharge/control.args
new file mode 100644
index 0000000..7cd1431
--- /dev/null
+++ b/client/site_tests/power_BatteryCharge/control.args
@@ -0,0 +1,50 @@
+# Copyright 2018 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.
+
+AUTHOR = "Chrome OS Team"
+NAME = "power_BatteryCharge.args"
+PURPOSE = "Measure the time required to charge the battery."
+CRITERIA = "This test is a benchmark."
+TIME = "LONG"
+TEST_CATEGORY = "Benchmark"
+TEST_CLASS = "power"
+TEST_TYPE = "client"
+
+DOC = """
+Device should be plugged into an AC outlet.
+
+This test depends on power_status.py, which is included in
+autotest/files/client/cros/power/. power_status.py has many status
+initialization and parsing routines for battery status.
+
+Sample usage:
+test_that <ip address of DUT> power_BatteryCharge.args \
+--args 'percent_charge_to_add=100'
+
+test_that <ip address of DUT> power_BatteryCharge.args \
+--args 'percent_target_charge=95'
+
+What are the parameters:
+percent_charge_to_add: percentage of the charge capacity charge to
+                       add. The target charge will be capped at the charge
+                       capacity. Optional.
+percent_target_charge: percentage of the charge capacity target charge. The
+                       target charge will be capped at the charge capacity.
+                       Optional.
+"""
+
+args_dict = utils.args_to_dict(args)
+
+max_hours = 3
+time_limit = max_hours * 60 * 60
+# percent_target_charge is prioritized over percent_charge_to_add.
+percent_charge_to_add = args_dict.get('percent_charge_to_add', 1)
+percent_target_charge = args_dict.get('percent_target_charge', None)
+
+job.run_test('power_BatteryCharge',
+             tag=NAME.split('.')[1],
+             max_run_time=time_limit,
+             percent_charge_to_add=percent_charge_to_add,
+             percent_target_charge=percent_target_charge,
+             use_design_charge_capacity=False)
diff --git a/server/site_tests/power_BatteryChargeControl/control.args b/server/site_tests/power_BatteryChargeControl/control.args
new file mode 100644
index 0000000..cab5a21
--- /dev/null
+++ b/server/site_tests/power_BatteryChargeControl/control.args
@@ -0,0 +1,51 @@
+# Copyright 2018 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "power_BatteryChargeControl.args"
+PURPOSE = "Use Servo v4 to charge the DUT"
+CRITERIA = ""
+TIME = "LONG"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "power"
+TEST_TYPE = "server"
+DEPENDENCIES = "servo"
+
+DOC = """
+DUT is connected to Servo v4 via USB type-C, and Servo v4 is connected to AC
+power.
+
+Sample usage:
+test_that <ip address of DUT> power_BatteryChargeControl.args \
+--args 'servo_host=localhost servo_port=9999 percent_charge_to_add=100'
+
+test_that <ip address of DUT> power_BatteryChargeControl.args \
+--args 'servo_host=localhost servo_port=9999 percent_target_charge=95'
+
+What are the parameters:
+percent_charge_to_add: percentage of the charge capacity charge to
+                       add. The target charge will be capped at the charge
+                       capacity. Optional.
+percent_target_charge: percentage of the charge capacity target charge. The
+                       target charge will be capped at the charge capacity.
+                       Optional.
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+# percent_target_charge is prioritized over percent_charge_to_add.
+percent_charge_to_add = args_dict.get('percent_charge_to_add', 1)
+percent_target_charge = args_dict.get('percent_target_charge', None)
+
+def run(machine):
+    host = hosts.create_host(machine, servo_args=servo_args)
+    job.run_test("power_BatteryChargeControl",
+                 tag=NAME.split('.')[1],
+                 host=host,
+                 percent_charge_to_add=percent_charge_to_add,
+                 percent_target_charge=percent_target_charge)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/power_BatteryChargeControl/control.charge70 b/server/site_tests/power_BatteryChargeControl/control.charge70
new file mode 100644
index 0000000..c3ff1fc
--- /dev/null
+++ b/server/site_tests/power_BatteryChargeControl/control.charge70
@@ -0,0 +1,38 @@
+# Copyright 2018 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "power_BatteryChargeControl.charge70"
+PURPOSE = "Use Servo v4 to charge the DUT"
+CRITERIA = ""
+TIME = "LONG"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "power"
+TEST_TYPE = "server"
+DEPENDENCIES = "servo"
+
+DOC = """
+Use Servo v4 to charge the DUT to 70% battery capacity.
+DUT is connected to Servo v4 via USB type-C, and Servo v4 is connected to AC
+power.
+
+Sample usage:
+test_that <ip address of DUT> power_BatteryChargeControl.charge70 \
+--args 'servo_host=localhost servo_port=9999'
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run(machine):
+    host = hosts.create_host(machine, servo_args=servo_args)
+    job.run_test("power_BatteryChargeControl",
+                 tag=NAME.split('.')[1],
+                 host=host,
+                 percent_charge_to_add=None,
+                 percent_target_charge=70)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/power_BatteryChargeControl/control.charge95 b/server/site_tests/power_BatteryChargeControl/control.charge95
new file mode 100644
index 0000000..29c818b
--- /dev/null
+++ b/server/site_tests/power_BatteryChargeControl/control.charge95
@@ -0,0 +1,38 @@
+# Copyright 2018 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "power_BatteryChargeControl.charge95"
+PURPOSE = "Use Servo v4 to charge the DUT"
+CRITERIA = ""
+TIME = "LONG"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "power"
+TEST_TYPE = "server"
+DEPENDENCIES = "servo"
+
+DOC = """
+Use Servo v4 to charge the DUT to 95% battery capacity.
+DUT is connected to Servo v4 via USB type-C, and Servo v4 is connected to AC
+power.
+
+Sample usage:
+test_that <ip address of DUT> power_BatteryChargeControl.charge95 \
+--args 'servo_host=localhost servo_port=9999'
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run(machine):
+    host = hosts.create_host(machine, servo_args=servo_args)
+    job.run_test("power_BatteryChargeControl",
+                 tag=NAME.split('.')[1],
+                 host=host,
+                 percent_charge_to_add=None,
+                 percent_target_charge=95)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/power_BatteryChargeControl/power_BatteryChargeControl.py b/server/site_tests/power_BatteryChargeControl/power_BatteryChargeControl.py
new file mode 100644
index 0000000..8770841
--- /dev/null
+++ b/server/site_tests/power_BatteryChargeControl/power_BatteryChargeControl.py
@@ -0,0 +1,68 @@
+# Copyright 2018 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 test that controls charging the DUT with Servo v4."""
+
+import logging
+import time
+
+from autotest_lib.client.common_lib import error
+from autotest_lib.server import autotest
+from autotest_lib.server import test
+
+# Wait time for Servo role change and PD negotiation.
+_SLEEP = 5
+# Max number of hours the DUT can charge for.
+_MAX_HOURS = 3
+
+
+class power_BatteryChargeControl(test.test):
+    """Server side test that controls charging the DUT.
+
+    This server side test first makes sure that the attached Servo v4 can
+    control charging the DUT, then puts the DUT on AC to charge, and finally
+    disconnect DUT from AC.
+    """
+    version = 1
+
+    def run_once(self, host, percent_charge_to_add, percent_target_charge):
+        """Running the test.
+
+        @param host: CrosHost object representing the DUT.
+        @param percent_charge_to_add: percentage of the charge capacity charge
+                to add. The target charge will be capped at the charge capacity.
+        @param percent_target_charge: percentage of the charge capacity target
+                charge. The target charge will be capped at the charge capacity.
+        """
+        self.servo = host.servo
+        servo_type = self.servo.get_servo_version()
+        if 'servo_v4' in servo_type:
+            servo_v4_version = self.servo.get('servo_v4_version')
+            logging.info('Servo v4 version: %s', servo_v4_version)
+        else:
+            raise error.TestNAError('This test needs to be run with Servo v4. '
+                                    'Test skipped.')
+
+        self.servo.set('servo_v4_role', 'snk')
+        time.sleep(_SLEEP)
+        if host.is_ac_connected():
+            raise error.TestError('Test failed to set Servo v4 as power snk.')
+
+        self.servo.set('servo_v4_role', 'src')
+        time.sleep(_SLEEP)
+        if not host.is_ac_connected():
+            raise error.TestError('Test failed to set Servo v4 as power src.')
+
+        time_limit = _MAX_HOURS * 60 * 60
+        autotest_client = autotest.Autotest(host)
+        autotest_client.run_test('power_BatteryCharge',
+                                 max_run_time=time_limit,
+                                 percent_charge_to_add=percent_charge_to_add,
+                                 percent_target_charge=percent_target_charge,
+                                 use_design_charge_capacity=False)
+
+        self.servo.set('servo_v4_role', 'snk')
+        time.sleep(_SLEEP)
+        if host.is_ac_connected():
+            raise error.TestError('Test failed to set Servo v4 as power snk.')