Document job exception handling machinations in comments and remove an
except Exception: case in job.run_test() that was impossible to reach.
Allow error.JobError raised from a test (run via run_test or run_group)
to be recorded as an ABORT and passed on up to actually ABORT things.
Signed-off-by: Gregory Smith <gps@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@2522 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/bin/job.py b/client/bin/job.py
index c104485..6cf19dc 100755
--- a/client/bin/job.py
+++ b/client/bin/job.py
@@ -384,8 +384,14 @@
pid = parallel.fork_start(self.resultdir, l)
parallel.fork_waitfor(self.resultdir, pid)
except error.TestBaseException:
+ # These are already classified with an error type (exit_status)
raise
+ except error.JobError:
+ raise # Caught further up and turned into an ABORT.
except Exception, e:
+ # Converts all other exceptions thrown by the test regardless
+ # of phase into a TestError(TestBaseException) subclass that
+ # reports them with their full stack trace.
raise error.UnhandledTestError(e)
finally:
# Reset the logging level to client level
@@ -470,11 +476,9 @@
try:
self._runtest(url, tag, args, dargs)
except error.TestBaseException, detail:
+ # The error is already classified, record it properly.
self.record(detail.exit_status, subdir, testname, str(detail))
raise
- except Exception, detail:
- self.record('FAIL', subdir, testname, str(detail))
- raise
else:
self.record('GOOD', subdir, testname, 'completed successfully')
@@ -483,9 +487,13 @@
if container:
self.release_container()
return True
- except error.TestBaseException, e:
+ except error.TestBaseException:
return False
# Any other exception here will be given to the caller
+ #
+ # NOTE: The only exception possible from the control file here
+ # is error.JobError as _runtest() turns all others into an
+ # UnhandledTestError that is caught above.
def _rungroup(self, subdir, testname, function, *args, **dargs):
@@ -513,10 +521,19 @@
self._decrement_group_level()
self.record('END %s' % e.exit_status, subdir, testname, str(e))
raise
+ except error.JobError, e:
+ self._decrement_group_level()
+ self.record('END ABORT', subdir, testname, str(e))
+ raise
except Exception, e:
+ # This should only ever happen due to a bug in the given
+ # function's code. The common case of being called by
+ # run_test() will never reach this. If a control file called
+ # run_group() itself, bugs in its function will be caught
+ # here.
self._decrement_group_level()
err_msg = str(e) + '\n' + traceback.format_exc()
- self.record('END FAIL', subdir, testname, err_msg)
+ self.record('END ERROR', subdir, testname, err_msg)
raise
@@ -540,11 +557,12 @@
function=function, **dargs)
except error.TestError:
pass
- # if there was a non-TestError exception, raise it
+ # if there was a non-TestError exception, re-raise it as a TestError
except Exception, e:
exc_info = sys.exc_info()
err = ''.join(traceback.format_exception(*exc_info))
- raise error.TestError(name + ' failed\n' + err)
+ del exc_info
+ raise error.TestError('%s failed:\n%s' % (name, err))
_RUN_NUMBER_STATE = '__run_number'
@@ -1221,7 +1239,8 @@
myjob.record('ABORT', None, command, instance.args[0])
myjob._decrement_group_level()
myjob.record('END ABORT', None, None, instance.args[0])
- assert(myjob.group_level == 0)
+ assert (myjob.group_level == 0), ('myjob.group_level must be 0,'
+ ' not %d' % myjob.group_level)
myjob.complete(1)
else:
sys.exit(1)
diff --git a/client/common_lib/error.py b/client/common_lib/error.py
index 16b742d..8c002aa 100644
--- a/client/common_lib/error.py
+++ b/client/common_lib/error.py
@@ -42,33 +42,30 @@
class TestBaseException(AutotestError):
"""The parent of all test exceptions."""
- pass
+ # Children are required to override this. Never instantiate directly.
+ exit_status="NEVER_RAISE_THIS"
class TestError(TestBaseException):
"""Indicates that something went wrong with the test harness itself."""
exit_status="ERROR"
- pass
class TestNAError(TestBaseException):
"""Indictates that the test is Not Applicable. Should be thrown
when various conditions are such that the test is inappropriate."""
exit_status="TEST_NA"
- pass
class TestFail(TestBaseException):
"""Indicates that the test failed, but the job will not continue."""
exit_status="FAIL"
- pass
class TestWarn(TestBaseException):
"""Indicates that bad things (may) have happened, but not an explicit
failure."""
exit_status="WARN"
- pass
class UnhandledTestError(TestError):
@@ -138,6 +135,7 @@
class AutotestRunError(AutotestError):
+ """Indicates a problem running server side control files."""
pass