A FAFT test case for forcing normal boot on dev firmware.

This test is only meaningful on Alex/ZGB, which contains two different types of
RW firmware: normal and developer firmware. It requires a USB disk plugged-in,
which contains a Chrome OS test image (built by "build_image --test").
On runtime, this test sets developer firmware in A and then corrupts the
firmware in B. It forces to do a normal boot. Going to recovery is expected.

BUG=chromium-os:19710
TEST=run_remote_tests.sh --remote=$REMOTE_IP -a "xml_config=$OVERLAY_XML \
        servo_vid=0x18d1 servo_pid=0x5001" DevFwNormalBoot

Change-Id: I5be0643c9445aa8e9c5989a99eac21f9dcc11d3f
Reviewed-on: https://gerrit.chromium.org/gerrit/12534
Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org>
Tested-by: Tom Wai-Hong Tam <waihong@chromium.org>
Commit-Ready: Tom Wai-Hong Tam <waihong@chromium.org>
diff --git a/server/site_tests/firmware_DevFwNormalBoot/control b/server/site_tests/firmware_DevFwNormalBoot/control
new file mode 100644
index 0000000..50b0f3b
--- /dev/null
+++ b/server/site_tests/firmware_DevFwNormalBoot/control
@@ -0,0 +1,27 @@
+# Copyright (c) 2011 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 = "firmware_DevFwNormalBoot"
+PURPOSE = "Servo based test forcing normal boot on dev firmware"
+CRITERIA = "This test will fail if firmware does not enter recovery mode"
+TIME = "LONG"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "firmware"
+TEST_TYPE = "server"
+
+DOC = """
+This test is only meaningful on Alex/ZGB, which contains two different types of
+RW firmware: normal and developer firmware. It requires a USB disk plugged-in,
+which contains a Chrome OS test image (built by "build_image --test").
+On runtime, this test sets developer firmware in A and then corrupts the
+firmware in B. It forces to do a normal boot. Going to recovery is expected.
+"""
+
+def run_devfwnormalboot(machine):
+    host = hosts.create_host(machine)
+    job.run_test("firmware_DevFwNormalBoot", host=host, cmdline_args=args,
+                 use_faft=True, disable_sysinfo=True)
+
+parallel_simple(run_devfwnormalboot, machines)
diff --git a/server/site_tests/firmware_DevFwNormalBoot/firmware_DevFwNormalBoot.py b/server/site_tests/firmware_DevFwNormalBoot/firmware_DevFwNormalBoot.py
new file mode 100644
index 0000000..0a37e44
--- /dev/null
+++ b/server/site_tests/firmware_DevFwNormalBoot/firmware_DevFwNormalBoot.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2011 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
+
+from autotest_lib.server.cros.faftsequence import FAFTSequence
+
+
+class firmware_DevFwNormalBoot(FAFTSequence):
+    """
+    Servo based test forcing normal boot on dev firmware.
+
+    This test is only meaningful on Alex/ZGB, which contains two different
+    types of RW firmware: normal and developer firmware. It requires a USB
+    disk plugged-in, which contains a Chrome OS test image (built by
+    "build_image --test"). On runtime, this test sets developer firmware in
+    A and then corrupts the firmware in B. It forces to do a normal boot.
+    Going to recovery is expected.
+    """
+    version = 1
+
+    # Codes dedicated for failed to load RW firmware.
+    INVALID_RW_FW_CODE = '3'
+
+    # True if Alex/ZBG which contains two different types of firmware.
+    has_different_dev_fw = False
+
+
+    def corrupt_fw_b_and_disable_devsw(self):
+        self.faft_client.corrupt_firmware('b')
+        self.servo.disable_development_mode()
+
+
+    def restore_fw_b_and_enable_devsw(self):
+        self.faft_client.restore_firmware('b')
+        self.servo.enable_development_mode()
+
+
+    def setup(self):
+        super(firmware_DevFwNormalBoot, self).setup()
+        # This test is only meaningful on Alex/ZGB.
+        fwid = self.faft_client.get_crossystem_value('fwid').lower()
+        if fwid.startswith('alex') or fwid.startswith('zgb'):
+            self.has_different_dev_fw = True
+            self.assert_test_image_in_usb_disk()
+            self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
+            # This test is run on developer mode only.
+            self.setup_dev_mode(dev_mode=True)
+
+
+    def run_once(self, host=None):
+        if self.has_different_dev_fw:
+            self.register_faft_sequence((
+                {   # Step 1, expected dev fw on A, corrupt fw B and force
+                    # normal boot.
+                    'state_checker': (self.crossystem_checker, {
+                        'devsw_boot': '1',
+                        'mainfw_act': 'A',
+                        'mainfw_type': 'developer',
+                    }),
+                    'userspace_action': self.corrupt_fw_b_and_disable_devsw,
+                    'firmware_action': self.wait_fw_screen_and_plug_usb,
+                    'install_deps_after_boot': True,
+                },
+                {   # Step 2, expected recovery boot, resume developer boot.
+                    'state_checker': (self.crossystem_checker, {
+                        'devsw_boot': '0',
+                        'mainfw_type': 'recovery',
+                        'recovery_reason' : self.INVALID_RW_FW_CODE,
+                        'recoverysw_boot': '0',
+                    }),
+                    'userspace_action': self.restore_fw_b_and_enable_devsw,
+                },
+                {   # Step 3, expected developer mode as before, done.
+                    'state_checker': (self.crossystem_checker, {
+                        'devsw_boot': '1',
+                        'mainfw_act': 'A',
+                        'mainfw_type': 'developer',
+                    }),
+                }
+            ))
+            self.run_faft_sequence()
+        else:
+            logging.info('This test does nothing on non-Alex/ZGB devices.')
diff --git a/server/site_tests/suites/control.faft b/server/site_tests/suites/control.faft
index bf698c5..0abe6fd 100644
--- a/server/site_tests/suites/control.faft
+++ b/server/site_tests/suites/control.faft
@@ -20,7 +20,9 @@
     ('firmware_DevTriggerRecovery', {}),
 ]
 
-TESTS_ON_DEV_MODE = []
+TESTS_ON_DEV_MODE = [
+    ('firmware_DevFwNormalBoot', {}),
+]
 
 TESTS_ON_BOTH_MODES = [
     ('firmware_TryFwB', {}),