Add full reboot option

The current reboot test uses 'reboot' command. However, this doesn't
necessarily exercise the full power sequence. This change provides a new
reboot option 'full_reboot' which performs the following:
  - AP shutdown
  - EC reboot
  - AP power-up
The new full reboot option should provide us a slightly different test
coverage.

BUG=chrome-os-partner:16645
TEST=Run full reboot step

Change-Id: I14ab15c4100ecf269478a7faa99a089f13ed6a45
Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/197241
diff --git a/py/goofy/goofy.py b/py/goofy/goofy.py
index 046d3e9..d095c1e 100755
--- a/py/goofy/goofy.py
+++ b/py/goofy/goofy.py
@@ -416,7 +416,7 @@
     """Starts shutdown procedure.
 
     Args:
-      operation: The shutdown operation (reboot or halt).
+      operation: The shutdown operation (reboot, full_reboot, or halt).
     """
     active_tests = []
     for test in self.test_list.walk():
diff --git a/py/goofy/goofy_rpc.py b/py/goofy/goofy_rpc.py
index a0a4c23..12c4f97 100755
--- a/py/goofy/goofy_rpc.py
+++ b/py/goofy/goofy_rpc.py
@@ -337,9 +337,10 @@
     """Starts a shutdown operation through Goofy.
 
     Args:
-      operation: The shutdown operation to run ('halt' or 'reboot').
+      operation: The shutdown operation to run ('halt', 'reboot',
+        or 'full_reboot').
     """
-    if operation not in ['halt', 'reboot']:
+    if operation not in ['halt', 'reboot', 'full_reboot']:
       raise GoofyRPCException('Invalid shutdown operation %r' % operation)
     self._InRunQueue(lambda: self.goofy.shutdown(operation))
 
diff --git a/py/goofy/test_environment.py b/py/goofy/test_environment.py
index 996785a..49e14a8 100644
--- a/py/goofy/test_environment.py
+++ b/py/goofy/test_environment.py
@@ -35,7 +35,7 @@
     """Shuts the machine down (from a ShutdownStep).
 
     Args:
-      operation: 'reboot' or 'halt'.
+      operation: 'reboot', 'full_reboot', or 'halt'.
 
     Returns:
       True if Goofy should gracefully exit, or False if Goofy
@@ -90,10 +90,14 @@
       self.browser_type = self.BROWSER_TYPE_LOGIN
 
   def shutdown(self, operation):
-    assert operation in ['reboot', 'halt']
+    assert operation in ['reboot', 'full_reboot', 'halt']
     logging.info('Shutting down: %s', operation)
     subprocess.check_call('sync')
-    subprocess.check_call(operation)
+    if operation == 'full_reboot':
+      subprocess.check_call(['ectool', 'reboot_ec', 'cold', 'at-shutdown'])
+      subprocess.check_call('halt')
+    else:
+      subprocess.check_call(operation)
     time.sleep(30)
     assert False, 'Never reached (should %s)' % operation
 
@@ -207,7 +211,7 @@
 class FakeChrootEnvironment(Environment):
   """A chroot environment that doesn't actually shutdown or run autotests."""
   def shutdown(self, operation):
-    assert operation in ['reboot', 'halt']
+    assert operation in ['reboot', 'full_reboot', 'halt']
     logging.warn('In chroot: skipping %s', operation)
     return False
 
diff --git a/py/test/factory.py b/py/test/factory.py
index 1641eb9..2e54ab1 100644
--- a/py/test/factory.py
+++ b/py/test/factory.py
@@ -1304,13 +1304,15 @@
 
 
 class ShutdownStep(OperatorTest):
-  """A shutdown (halt or reboot) step.
+  """A shutdown (halt, reboot, or full_reboot) step.
 
   Properties:
     iterations: The number of times to reboot.
-    operation: The command to run to perform the shutdown (REBOOT or HALT).
+    operation: The command to run to perform the shutdown (FULL_REBOOT,
+      REBOOT, or HALT).
     delay_secs: Number of seconds the operator has to abort the shutdown.
   """
+  FULL_REBOOT = 'full_reboot'
   REBOOT = 'reboot'
   HALT = 'halt'
 
@@ -1322,7 +1324,7 @@
     assert not self.subtests, 'Reboot/halt steps may not have subtests'
     assert not self.backgroundable, (
         'Reboot/halt steps may not be backgroundable')
-    assert operation in [self.REBOOT, self.HALT]
+    assert operation in [self.REBOOT, self.HALT, self.FULL_REBOOT]
     assert delay_secs >= 0
     self.pytest_name = 'shutdown'
     self.dargs = kwargs.get('dargs', {})
@@ -1346,4 +1348,12 @@
     super(RebootStep, self).__init__(operation=ShutdownStep.REBOOT, **kw)
 
 
+class FullRebootStep(ShutdownStep):
+  """Fully reboots the machine."""
+  def __init__(self, **kw):
+    kw.setdefault('id', 'FullReboot')
+    super(FullRebootStep, self).__init__(
+        operation=ShutdownStep.FULL_REBOOT, **kw)
+
+
 AutomatedRebootSubTest = RebootStep
diff --git a/py/test/pytests/shutdown/shutdown.py b/py/test/pytests/shutdown/shutdown.py
index 5dae068..db3d60b 100644
--- a/py/test/pytests/shutdown/shutdown.py
+++ b/py/test/pytests/shutdown/shutdown.py
@@ -39,7 +39,7 @@
 
 
 class ShutdownTest(unittest.TestCase):
-  """Factory test for shutdown operations (reboot or halt).
+  """Factory test for shutdown operations (reboot, full_reboot, or halt).
 
   This test has two stages.  The Shutdown() method is the first stage which
   happens before the system actually shuts down; the PostShutdown() method
@@ -53,7 +53,8 @@
   """
   ARGS = [
       Arg('operation', str,
-          "The command to run to perform the shutdown ('reboot' or 'halt')."),
+          ("The command to run to perform the shutdown ('reboot', "
+           "'full_reboot', or 'halt').")),
       Arg('delay_secs', int,
           'Number of seconds the operator has to abort the shutdown.',
           default=5),
@@ -69,6 +70,7 @@
 
   def setUp(self):
     assert self.args.operation in (factory.ShutdownStep.REBOOT,
+                                   factory.ShutdownStep.FULL_REBOOT,
                                    factory.ShutdownStep.HALT)
     self.ui = test_ui.UI()
     self.template = ui_templates.OneSection(self.ui)
diff --git a/py/test/test_lists/test_lists.py b/py/test/test_lists/test_lists.py
index 76444bf..f2db4cc 100644
--- a/py/test/test_lists/test_lists.py
+++ b/py/test/test_lists/test_lists.py
@@ -231,6 +231,10 @@
   return Add(factory.RebootStep(*args, **kwargs))
 
 
+def FullRebootStep(*args, **kwargs):
+  return Add(factory.FullRebootStep(*args, **kwargs))
+
+
 def Passed(name):
   return RequireRun(name, passed=True)