提交 59a2289f 编写于 作者: A Amador Pahim

Make exit codes a combination of meanings (aka ORable)

Currently, exit codes cover all situations with one single value.

This patch makes exit codes to be ORable, so we can better represent
the variety of things that happens during an Avocado execution.

Reference: https://trello.com/c/SU5fixgHSigned-off-by: NAmador Pahim <apahim@redhat.com>
上级 9caedc1b
...@@ -21,21 +21,22 @@ statuses. ...@@ -21,21 +21,22 @@ statuses.
""" """
#: Both job and tests PASSed #: Both job and tests PASSed
AVOCADO_ALL_OK = 0 AVOCADO_ALL_OK = 0x0000
#: Job went fine, but some tests FAILed or ERRORed #: Job went fine, but some tests FAILed or ERRORed
AVOCADO_TESTS_FAIL = 1 AVOCADO_TESTS_FAIL = 0x0001
#: Something went wrong with the Job itself, by explicit #: Something went wrong with the Job itself, by explicit
#: :class:`avocado.core.exceptions.JobError` exception. #: :class:`avocado.core.exceptions.JobError` exception.
AVOCADO_JOB_FAIL = 2 AVOCADO_JOB_FAIL = 0x0002
#: Something else went wrong and avocado failed (or crashed). Commonly #: Something else went wrong and avocado failed (or crashed). Commonly
#: used on command line validation errors. #: used on command line validation errors.
AVOCADO_FAIL = 3 AVOCADO_FAIL = 0x0004
#: The job was explicitly interrupted. Usually this means that a user #: The job was explicitly interrupted. Usually this means that a user
#: hit CTRL+C while the job was still running. #: hit CTRL+C while the job was still running.
AVOCADO_JOB_INTERRUPTED = 4 AVOCADO_JOB_INTERRUPTED = 0x0008
#: Avocado generic crash #: Avocado generic crash
AVOCADO_GENERIC_CRASH = -1 AVOCADO_GENERIC_CRASH = -1
...@@ -123,6 +123,7 @@ class Job(object): ...@@ -123,6 +123,7 @@ class Job(object):
_TEST_LOGGER) _TEST_LOGGER)
self.stdout_stderr = None self.stdout_stderr = None
self.replay_sourcejob = getattr(self.args, 'replay_sourcejob', None) self.replay_sourcejob = getattr(self.args, 'replay_sourcejob', None)
self.exitcode = exit_codes.AVOCADO_ALL_OK
def _setup_job_results(self): def _setup_job_results(self):
logdir = getattr(self.args, 'logdir', None) logdir = getattr(self.args, 'logdir', None)
...@@ -296,7 +297,8 @@ class Job(object): ...@@ -296,7 +297,8 @@ class Job(object):
'simultaneously', " ".join(op_set_stdout)) 'simultaneously', " ".join(op_set_stdout))
self.log.error('Please set at least one of them to a file to ' self.log.error('Please set at least one of them to a file to '
'avoid conflicts') 'avoid conflicts')
sys.exit(exit_codes.AVOCADO_JOB_FAIL) self.exitcode |= exit_codes.AVOCADO_JOB_FAIL
sys.exit(self.exitcode)
if not op_set_stdout and not self.standalone: if not op_set_stdout and not self.standalone:
human_plugin = result.HumanTestResult(self) human_plugin = result.HumanTestResult(self)
...@@ -511,13 +513,15 @@ class Job(object): ...@@ -511,13 +513,15 @@ class Job(object):
_TEST_LOGGER.info('Test results available in %s', self.logdir) _TEST_LOGGER.info('Test results available in %s', self.logdir)
if summary is None: if summary is None:
return exit_codes.AVOCADO_JOB_FAIL self.exitcode |= exit_codes.AVOCADO_JOB_FAIL
elif 'INTERRUPTED' in summary: return self.exitcode
return exit_codes.AVOCADO_JOB_INTERRUPTED
elif summary: if 'INTERRUPTED' in summary:
return exit_codes.AVOCADO_TESTS_FAIL self.exitcode |= exit_codes.AVOCADO_JOB_INTERRUPTED
else: if 'FAIL' in summary:
return exit_codes.AVOCADO_ALL_OK self.exitcode |= exit_codes.AVOCADO_TESTS_FAIL
return self.exitcode
def run(self): def run(self):
""" """
...@@ -545,10 +549,12 @@ class Job(object): ...@@ -545,10 +549,12 @@ class Job(object):
self.status = details.status self.status = details.status
fail_class = details.__class__.__name__ fail_class = details.__class__.__name__
self.log.error('\nAvocado job failed: %s: %s', fail_class, details) self.log.error('\nAvocado job failed: %s: %s', fail_class, details)
return exit_codes.AVOCADO_JOB_FAIL self.exitcode |= exit_codes.AVOCADO_JOB_FAIL
return self.exitcode
except exceptions.OptionValidationError as details: except exceptions.OptionValidationError as details:
self.log.error('\n' + str(details)) self.log.error('\n' + str(details))
return exit_codes.AVOCADO_JOB_FAIL self.exitcode |= exit_codes.AVOCADO_JOB_FAIL
return self.exitcode
except Exception as details: except Exception as details:
self.status = "ERROR" self.status = "ERROR"
...@@ -562,7 +568,8 @@ class Job(object): ...@@ -562,7 +568,8 @@ class Job(object):
self.log.error("Please include the traceback info and command line" self.log.error("Please include the traceback info and command line"
" used on your bug report") " used on your bug report")
self.log.error('Report bugs visiting %s', _NEW_ISSUE_LINK) self.log.error('Report bugs visiting %s', _NEW_ISSUE_LINK)
return exit_codes.AVOCADO_FAIL self.exitcode |= exit_codes.AVOCADO_FAIL
return self.exitcode
finally: finally:
if not settings.get_value('runner.behavior', 'keep_tmp_files', if not settings.get_value('runner.behavior', 'keep_tmp_files',
key_type=bool, default=False): key_type=bool, default=False):
......
...@@ -152,6 +152,26 @@ the program:: ...@@ -152,6 +152,26 @@ the program::
That's basically the only rule, and a sane one, that you need to follow. That's basically the only rule, and a sane one, that you need to follow.
Exit Codes
----------
Avocado exit code tries to represent different things that can happen during
an execution. That means exit codes can be a combination of codes that were
ORed toghether as a simgle exit code. The final exit code can be debundled so
users can have a good idea on what happened to the job.
The single individual exit codes are:
* AVOCADO_ALL_OK (0)
* AVOCADO_TESTS_FAIL (1)
* AVOCADO_JOB_FAIL (2)
* AVOCADO_FAIL (4)
* AVOCADO_JOB_INTERRUPTED (8)
If a job finishes with exit code `9`, for example, it means we had at least
one test that failed and also we had at some point a job interruption, probably
due to the job timeout or a `CTRL+C`.
Implementing other result formats Implementing other result formats
--------------------------------- ---------------------------------
......
...@@ -108,13 +108,15 @@ class JobTimeOutTest(unittest.TestCase): ...@@ -108,13 +108,15 @@ class JobTimeOutTest(unittest.TestCase):
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off ' cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off '
'--xunit - --job-timeout=1 %s examples/tests/passtest.py' % '--xunit - --job-timeout=1 %s examples/tests/passtest.py' %
(self.tmpdir, self.script.path)) (self.tmpdir, self.script.path))
self.run_and_check(cmd_line, exit_codes.AVOCADO_JOB_INTERRUPTED, 2, 1, 0, 1) self.run_and_check(cmd_line, exit_codes.AVOCADO_JOB_INTERRUPTED,
2, 1, 0, 1)
def test_sleep_short_timeout_with_test_methods(self): def test_sleep_short_timeout_with_test_methods(self):
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off ' cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off '
'--xunit - --job-timeout=1 %s' % '--xunit - --job-timeout=1 %s' %
(self.tmpdir, self.py.path)) (self.tmpdir, self.py.path))
self.run_and_check(cmd_line, exit_codes.AVOCADO_JOB_INTERRUPTED, 3, 1, 0, 2) self.run_and_check(cmd_line, exit_codes.AVOCADO_JOB_INTERRUPTED,
3, 1, 0, 2)
def test_invalid_values(self): def test_invalid_values(self):
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off ' cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off '
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册