Base_test's _call_run_once() does not execute the after_iteration hooks
if the test fails.  It is important to execute the after_iteration hooks
in the event of a test failure since these hooks may be used to gather
important test logs to help diagnose the failure.  This patch
modifies _call_run_once() to execute after_iteration hooks regardless of
the outcome of the test.

A new unit test was added to verify the behavior of _call_run_once().  The
patch was tested using unittest_suite.py to ensure that it did not break
other functionalities.  It was also tested with an actual after_iteration
hook that collected test logs and the test was forced to fail.

Risk: High
Visibility: The order of when the after_iteration hooks has been changed
and may affect existing tests.
Bugs: None

Signed-off-by: Thieu Le <thie...@chromium.org>
---
 client/common_lib/test.py          |   35 +++++++++++++++++++----------------
 client/common_lib/test_unittest.py |   24 +++++++++++++++++++++++-
 2 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/client/common_lib/test.py b/client/common_lib/test.py
index 63c1d31..c55d23b 100644
--- a/client/common_lib/test.py
+++ b/client/common_lib/test.py
@@ -198,22 +198,25 @@ class base_test(object):
         for hook in self.before_iteration_hooks:
             hook(self)
 
-        if profile_only:
-            if not self.job.profilers.present():
-                self.job.record('WARN', None, None, 'No profilers have been '
-                                'added but profile_only is set - nothing '
-                                'will be run')
-            self.run_once_profiling(postprocess_profiled_run, *args, **dargs)
-        else:
-            self.before_run_once()
-            self.run_once(*args, **dargs)
-            self.after_run_once()
-
-        for hook in self.after_iteration_hooks:
-            hook(self)
+        try:
+            if profile_only:
+                if not self.job.profilers.present():
+                    self.job.record('WARN', None, None,
+                                    'No profilers have been added but '
+                                    'profile_only is set - nothing '
+                                    'will be run')
+                self.run_once_profiling(postprocess_profiled_run,
+                                        *args, **dargs)
+            else:
+                self.before_run_once()
+                self.run_once(*args, **dargs)
+                self.after_run_once()
 
-        self.postprocess_iteration()
-        self.analyze_perf_constraints(constraints)
+            self.postprocess_iteration()
+            self.analyze_perf_constraints(constraints)
+        finally:
+            for hook in self.after_iteration_hooks:
+                hook(self)
 
 
     def execute(self, iterations=None, test_length=None, profile_only=None,
diff --git a/client/common_lib/test_unittest.py 
b/client/common_lib/test_unittest.py
index 9710fd0..d2218ba 100755
--- a/client/common_lib/test_unittest.py
+++ b/client/common_lib/test_unittest.py
@@ -64,13 +64,35 @@ class Test_base_test_execute(TestTestCase):
         self.test.drop_caches_between_iterations.expect_call()
         before_hook.expect_call(self.test)
         self.test.run_once.expect_call(1, 2, arg='val')
-        after_hook.expect_call(self.test)
         self.test.postprocess_iteration.expect_call()
         self.test.analyze_perf_constraints.expect_call([])
+        after_hook.expect_call(self.test)
         self.test._call_run_once([], False, None, (1, 2), {'arg': 'val'})
         self.god.check_playback()
 
 
+    def test_call_run_once_with_exception(self):
+        # setup
+        self.god.stub_function(self.test, 'drop_caches_between_iterations')
+        self.god.stub_function(self.test, 'run_once')
+        before_hook = self.god.create_mock_function('before_hook')
+        after_hook = self.god.create_mock_function('after_hook')
+        self.test.register_before_iteration_hook(before_hook)
+        self.test.register_after_iteration_hook(after_hook)
+        error = Exception('fail')
+
+        # tests the test._call_run_once implementation
+        self.test.drop_caches_between_iterations.expect_call()
+        before_hook.expect_call(self.test)
+        self.test.run_once.expect_call(1, 2, arg='val').and_raises(error)
+        after_hook.expect_call(self.test)
+        try:
+            self.test._call_run_once([], False, None, (1, 2), {'arg': 'val'})
+        except:
+            pass
+        self.god.check_playback()
+
+
     def _expect_call_run_once(self):
         self.test._call_run_once.expect_call((), False, None, (), {})
 
-- 
1.7.3.1

_______________________________________________
Autotest mailing list
Autotest@test.kernel.org
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

Reply via email to