FAFT: Adding new test firmware_ECLidShutdown

This tests the functionality of the
GBB_FLAG_DISABLE_LID_SHUTDOWN flag.

BUG=chromium:446525
BRANCH=none
TEST=tested on veyron_jerry and samus

Change-Id: I06f8f654513212bdf129c981f9dab9f12c9c54d1
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/304190
Reviewed-by: Wai-Hong Tam <waihong@chromium.org>
diff --git a/server/cros/faft/firmware_test.py b/server/cros/faft/firmware_test.py
index 6cc7f04..6b0d322 100644
--- a/server/cros/faft/firmware_test.py
+++ b/server/cros/faft/firmware_test.py
@@ -689,6 +689,32 @@
             self.check_ec_capability(['usbpd_uart'], suppress_warning=True)):
             self.servo.set('usbpd_uart_capture', 'off')
 
+    def _get_power_state(self, power_state):
+        """
+        Return the current power state of the AP
+        """
+        return self.ec.send_command_get_output("powerinfo", [power_state])
+
+    def wait_power_state(self, power_state, retries):
+        """
+        Wait for certain power state.
+
+        @param power_state: power state you are expecting
+        @param retries: retries.  This is necessary if AP is powering down
+        and transitioning through different states.
+        """
+        logging.info('Checking power state "%s" maximum %d times.',
+                     power_state, retries)
+        while retries > 0:
+            logging.info("try count: %d" % retries)
+            try:
+                retries = retries - 1
+                ret = self._get_power_state(power_state)
+                return True
+            except error.TestFail:
+                pass
+        return False
+
     def _fetch_servo_log(self):
         """Fetch the servo log."""
         cmd = '[ -e %s ] && cat %s || echo NOTFOUND' % ((self._SERVOD_LOG,) * 2)
diff --git a/server/site_tests/firmware_ECLidShutdown/control b/server/site_tests/firmware_ECLidShutdown/control
new file mode 100644
index 0000000..810dd78
--- /dev/null
+++ b/server/site_tests/firmware_ECLidShutdown/control
@@ -0,0 +1,35 @@
+# Copyright (c) 2015 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 = "firmware_ECLidShutdown"
+PURPOSE = "Verify functionality of DUT with GBB_FLAG_DISABLE_LID_SHUTDOWN"
+CRITERIA = "This test will ensure disable lid shutdown GBB flag working"
+ATTRIBUTES = "suite:faft, suite:faft_ec"
+SUITE = "faft,faft_ec"
+TIME = "SHORT"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "firmware"
+TEST_TYPE = "server"
+JOB_RETRIES = 2
+
+DOC = """
+This test check the functionality of disable lid shutdown GBB flag.
+    - Verifies that closing lid in recovery will shutdown DUT
+      when GBB_FLAG_DISABLE_LID_SHUTDOWN flag disabled.
+    - Verifies that closing lid in recovery will not shutdown DUT
+      when GBB_FLAG_DISABLE_LID_SHUTDOWN flag enabled.
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run_eclidshutdown(machine):
+    host = hosts.create_host(machine, servo_args=servo_args)
+    job.run_test("firmware_ECLidShutdown", host=host, cmdline_args=args,
+                 disable_sysinfo=True)
+
+parallel_simple(run_eclidshutdown, machines)
diff --git a/server/site_tests/firmware_ECLidShutdown/firmware_ECLidShutdown.py b/server/site_tests/firmware_ECLidShutdown/firmware_ECLidShutdown.py
new file mode 100644
index 0000000..9da2ff8
--- /dev/null
+++ b/server/site_tests/firmware_ECLidShutdown/firmware_ECLidShutdown.py
@@ -0,0 +1,126 @@
+# Copyright (c) 2015 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.
+
+import logging
+import time
+
+from autotest_lib.client.common_lib import error
+from autotest_lib.server.cros import vboot_constants as vboot
+from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
+from autotest_lib.server.cros.faft.utils import mode_switcher
+
+class firmware_ECLidShutdown(FirmwareTest):
+    """
+    Testing GBB_FLAG_DISABLE_LID_SHUTDOWN flag
+    """
+    version = 1
+
+    # Delay between closing and opening the lid
+    LID_DELAY = 2
+    # time to wait before checking if DUT booted into OS mode
+    BOOTUP_TIME = 30
+    # time to wait to let DUT transition into recovery mode
+    RECOVERY_DELAY = 1
+    # # times to check if DUT in expected power state
+    # This accomodates if DUT needs to transition into certain states.
+    PWR_RETRIES = 13
+
+    def cleanup(self):
+        """If DUT not pingable, may be still stuck in recovery mode.
+        Reboot it.  Also, reset GBB_FLAGS and make sure that lid set
+        to open (in case of error).
+        """
+        if self.servo.get('lid_open') == 'no':
+            self.servo.set('lid_open', 'yes')
+        self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN,
+                                 0)
+        try:
+            self.switcher.wait_for_client()
+        except ConnectionError:
+            logging.error("ERROR: client not in OS mode.  Rebooting ...")
+            # reboot back to OS mode
+            self.switcher.mode_aware_reboot(reboot_type='cold',
+                                            sync_before_boot=False)
+        super(firmware_ECLidShutdown, self).cleanup()
+
+    def _reset_ec_regexp(self):
+        """Reset ec_uart_regexp field
+
+        Needs to be done for the ec_uart_regexp otherwise
+        dut-control command will time out due to no match.
+        """
+        self.servo.set('ec_uart_regexp', 'None')
+
+    def verify_lid_shutdown(self):
+        """
+        Make sure that firmware boots into OS with lid closed
+        """
+        self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN,
+                                 0)
+        # reboot into recovery mode and wait a bit for it to actually get there
+        self.switcher.reboot_to_mode(to_mode='rec',
+                                     wait_for_dut_up=False)
+        time.sleep(self.RECOVERY_DELAY)
+
+        # close/open lid
+        self.servo.set('lid_open', 'no')
+        time.sleep(self.LID_DELAY)
+        if not self.wait_power_state("G3", self.PWR_RETRIES):
+            logging.error("ERROR: EC does not shut down")
+            return False
+        self.servo.set('lid_open', 'yes')
+
+        # ping DUT - should boot into OS now
+        self._reset_ec_regexp()
+        self.switcher.wait_for_client()
+
+        return True
+
+    def check_disable_lid_shutdown(self):
+        """
+        Set flag to disable shutdown of DUT when lid closed.  Then check
+        if DUT shuts down during recovery mode screen.
+        """
+        # enable shutdown flag
+        self.clear_set_gbb_flags(0,
+                                 vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN)
+        # reboot into recovery mode and wait a bit for it to get there
+        self.switcher.reboot_to_mode(to_mode='rec',
+                                      wait_for_dut_up=False)
+        time.sleep(self.RECOVERY_DELAY)
+
+        # close/open the lid
+        self.servo.set('lid_open', 'no')
+        time.sleep(self.LID_DELAY)
+        if not self.wait_power_state("S0", self.PWR_RETRIES):
+            logging.error("ERROR: EC shuts down")
+            return False
+        self.servo.set('lid_open', 'yes')
+
+        # this should be more than enough time for system to boot up
+        # if it was going to.
+        time.sleep(self.BOOTUP_TIME)
+
+        # should still be offline
+        self.switcher.wait_for_client_offline()
+
+        # reboot back to OS mode
+        self.switcher.mode_aware_reboot(reboot_type='cold',
+                                        sync_before_boot=False)
+
+        # disable flag
+        self._reset_ec_regexp()
+        return True
+
+
+    def run_once(self):
+        if not self.check_ec_capability(['lid']):
+            raise error.TestNAError("This device needs a lid to run this test")
+
+        logging.info("Verify DUT with DISABLE_LID_SHUTDOWN disabled")
+        self.check_state(self.verify_lid_shutdown)
+
+        logging.info("Verify DUT with DISABLE_LID_SHUTDOWN enabled")
+        self.check_state(self.check_disable_lid_shutdown)
+
diff --git a/server/site_tests/firmware_ECPowerG3/firmware_ECPowerG3.py b/server/site_tests/firmware_ECPowerG3/firmware_ECPowerG3.py
index 12edcfe..4167ed5 100644
--- a/server/site_tests/firmware_ECPowerG3/firmware_ECPowerG3.py
+++ b/server/site_tests/firmware_ECPowerG3/firmware_ECPowerG3.py
@@ -30,27 +30,10 @@
         self.ec.send_command("chan 0xffffffff")
         super(firmware_ECPowerG3, self).cleanup()
 
-    def wait_power(self, reg_ex, retries):
-        """
-        Wait for certain power state.
-
-        @param reg_ex: Acceptable "powerinfo" response. Can be a regex.
-        @param retries: retries.
-        """
-        logging.info('Checking for "%s" maximum %d times.', reg_ex, retries)
-        while retries > 0:
-            try:
-                retries = retries - 1
-                self.ec.send_command_get_output("powerinfo", [reg_ex])
-                return True
-            except error.TestFail:
-                pass
-        return False
-
     def check_G3(self):
         """Shutdown the system and check if X86 drop into G3 correctly."""
         self.faft_client.system.run_shell_command("shutdown -P now")
-        if not self.wait_power("power state 0 = G3", self.G3_RETRIES):
+        if not self.wait_power_state("G3", self.G3_RETRIES):
             logging.error("EC fails to drop into G3")
             self._failed = True
         self.servo.power_short_press()