Extend power_Resume test with iterations.

Added option to provide number of iterations and delay between
iteration for power_Resume Tauto test.

BUG=b:175533027
TEST=Ran on local machine.

Change-Id: I8de18b26b065e7d8fb15762a0709d034040b69ba
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2589434
Reviewed-by: Victor Ding <victording@chromium.org>
Tested-by: Alex Bergman <abergman@google.com>
Commit-Queue: Alex Bergman <abergman@google.com>
diff --git a/client/site_tests/power_Resume/control.iterations b/client/site_tests/power_Resume/control.iterations
new file mode 100644
index 0000000..23be866
--- /dev/null
+++ b/client/site_tests/power_Resume/control.iterations
@@ -0,0 +1,25 @@
+# Copyright 2020 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_Resume.iterations"
+PURPOSE = "Measure the amount of time it takes to resume from suspend."
+CRITERIA = "This test is a benchmark."
+ATTRIBUTES = "suite:crosbolt_perf_perbuild"
+TIME = "SHORT"
+TEST_CATEGORY = "Logging"
+TEST_CLASS = "power"
+TEST_TYPE = "client"
+
+DOC = """
+This test will search /var/log/messages for pertinent strings to determine if
+the cpu is sleeping. It will wait for a number of seconds before suspending to
+ram. It will then calculate how many seconds the system was suspended, and
+how many seconds it took to resume. As a precaution it will ensure your
+network interface is UP after it has resumed.
+"""
+
+job.add_sysinfo_command('cbmem -c', logfile='bios_log', on_every_test=True)
+job.add_sysinfo_command('cbmem -t', logfile='bios_times', on_every_test=True)
+job.run_test('power_Resume', ignore_kernel_warns=True, suspend_iterations=50, iteration_delay=10)
diff --git a/client/site_tests/power_Resume/power_Resume.py b/client/site_tests/power_Resume/power_Resume.py
index 6d71d4f..bbf1312 100644
--- a/client/site_tests/power_Resume/power_Resume.py
+++ b/client/site_tests/power_Resume/power_Resume.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import time
+
 from autotest_lib.client.bin import test
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.cros.power import power_suspend
@@ -19,14 +21,21 @@
     version = 1
     preserve_srcdir = True
 
-    def initialize(self, suspend_state=''):
+    def initialize(self,
+                   suspend_state='',
+                   suspend_iterations=None,
+                   iteration_delay=0):
         """
         Entry point.
 
         @param suspend_state: Force to suspend to a specific
                 state ("mem" or "freeze"). If the string is empty, suspend
                 state is left to the default pref on the system.
+        @param suspend_iterations: number of times to attempt suspend.
+        @param iteration_delay: number of seconds to wait between suspend iterations (default: 0).
         """
+        self._suspend_iterations = suspend_iterations
+        self._iteration_delay = iteration_delay
         self._suspender = power_suspend.Suspender(
                 self.resultsdir,
                 throw=True,
@@ -36,13 +45,42 @@
 
     def run_once(self, max_devs_returned=10, seconds=0,
                  ignore_kernel_warns=False, measure_arc=False):
-        try:
-            self._suspend_once(max_devs_returned, seconds, ignore_kernel_warns,
-                               measure_arc)
-        except error.TestWarn:
-            self._suspend_once(max_devs_returned, seconds + EXTRA_TIME,
-                               ignore_kernel_warns, measure_arc)
-            raise
+        system_suspends = []
+        system_resumes = []
+        while not self._done():
+            time.sleep(self._iteration_delay)
+
+            suspend_time = 0.0
+            resume_time = 0.0
+            try:
+                (suspend_time,
+                 resume_time) = self._suspend_once(max_devs_returned, seconds,
+                                                   ignore_kernel_warns,
+                                                   measure_arc)
+            except error.TestWarn:
+                (suspend_time, resume_time) = self._suspend_once(
+                        max_devs_returned, seconds + EXTRA_TIME,
+                        ignore_kernel_warns, measure_arc)
+                raise
+            system_suspends.append(suspend_time)
+            system_resumes.append(resume_time)
+
+        self.output_perf_value(description='system_suspend',
+                               value=system_suspends,
+                               units='sec',
+                               higher_is_better=False)
+        self.output_perf_value(description='system_resume',
+                               value=system_resumes,
+                               units='sec',
+                               higher_is_better=False)
+
+    def _done(self):
+        if self._suspend_iterations == None:
+            # At least one iteration.
+            self._suspend_iterations = 1
+
+        self._suspend_iterations -= 1
+        return self._suspend_iterations < 0
 
 
     def _suspend_once(self, max_devs_returned, seconds, ignore_kernel_warns,
@@ -60,10 +98,12 @@
         for dev in slowest_devs:
             results[dev] = device_times[dev]
 
-        self.output_perf_value(description='system_suspend',
-                               value=results['seconds_system_suspend'],
-                               units='sec', higher_is_better=False)
-        self.output_perf_value(description='system_resume',
-                               value=results['seconds_system_resume'],
-                               units='sec', higher_is_better=False)
         self.write_perf_keyval(results)
+        return (results['seconds_system_suspend'],
+                results['seconds_system_resume'])
+
+    def cleanup(self):
+        """
+        Clean the suspender.
+        """
+        self._suspender.finalize()