From fa0e77a73632734d49ae17b4be7d1aca634815e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Doktor?= Date: Mon, 23 Mar 2015 18:38:55 +0100 Subject: [PATCH] scripts.avocado-bash-utils: Add Avocado bash utils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is initial support for people using custom bash scripts with avocado. Tests should use: PATH=$(avocado "exec-path"):$PATH and then they can utilize the helpers. This version contain functions to write to Test.log the same way it's possible from python including failing the test with TestWarn in case avocado_warn was used. Signed-off-by: Lukáš Doktor --- avocado.spec | 5 ++ avocado/plugins/exec_path.py | 64 +++++++++++++++++++ avocado/test.py | 17 ++++- docs/source/WritingTests.rst | 14 ++++ examples/tests/simplewarning.sh | 9 +++ libexec/avocado-bash-utils | 20 ++++++ libexec/avocado_debug | 4 ++ libexec/avocado_error | 4 ++ libexec/avocado_info | 4 ++ libexec/avocado_warn | 4 ++ scripts/avocado | 1 + .../all/functional/avocado/basic_tests.py | 18 ++++++ setup.py | 10 +++ 13 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 avocado/plugins/exec_path.py create mode 100755 examples/tests/simplewarning.sh create mode 100755 libexec/avocado-bash-utils create mode 100755 libexec/avocado_debug create mode 100755 libexec/avocado_error create mode 100755 libexec/avocado_info create mode 100755 libexec/avocado_warn diff --git a/avocado.spec b/avocado.spec index 69287b99..5a8acca4 100644 --- a/avocado.spec +++ b/avocado.spec @@ -55,6 +55,11 @@ these days a framework) to perform automated testing. %{_docdir}/avocado/avocado-rest-client.rst %exclude %{python_sitelib}/avocado/plugins/htmlresult.py* %exclude %{python_sitelib}/avocado/plugins/resources/htmlresult/* +%{_libexecdir}/avocado/avocado-bash-utils +%{_libexecdir}/avocado/avocado_debug +%{_libexecdir}/avocado/avocado_error +%{_libexecdir}/avocado/avocado_info +%{_libexecdir}/avocado/avocado_warn %package plugins-output-html Summary: Avocado HTML report plugin diff --git a/avocado/plugins/exec_path.py b/avocado/plugins/exec_path.py new file mode 100644 index 00000000..2416cc5c --- /dev/null +++ b/avocado/plugins/exec_path.py @@ -0,0 +1,64 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2013-2014 +""" +Libexec PATHs modifier +""" + +import os +import sys + +from avocado.core import exit_codes, output +from avocado.plugins import plugin + + +class ExecPath(plugin.Plugin): + + """ + Implements the avocado 'exec-path' subcommand + """ + + name = 'exec_path' + enabled = True + priority = 0 + view = None + + def configure(self, parser): + """ + Add the subparser for the exec-path action. + + :param parser: Main test runner parser. + """ + self.parser = parser.subcommands.add_parser( + 'exec-path', + help='Returns path to avocado bash libraries and exits.') + + super(ExecPath, self).configure(self.parser) + + def run(self, args): + """ + Print libexec path and finish + + :param args: Command line args received from the run subparser. + """ + self.view = output.View(app_args=args, use_paginator=False) + if 'VIRTUAL_ENV' in os.environ: + self.view.notify(event='minor', msg='libexec') + elif os.path.exists('/usr/libexec/avocado'): + self.view.notify(event='minor', msg='/usr/libexec/avocado') + elif os.path.exists('/usr/lib/avocado'): + self.view.notify(event='minor', msg='/usr/lib/avocado') + else: + self.view.notify(event='error', + msg="Can't locate avocado libexec path") + sys.exit(exit_codes.AVOCADO_FAIL) + return sys.exit(exit_codes.AVOCADO_ALL_OK) diff --git a/avocado/test.py b/avocado/test.py index b96f4eda..1d3b5813 100644 --- a/avocado/test.py +++ b/avocado/test.py @@ -11,6 +11,7 @@ # This code was inspired in the autotest project, # client/shared/test.py # Authors: Martin J Bligh , Andy Whitcroft +import re """ Contains the base test implementation, used as a base for the actual @@ -524,6 +525,9 @@ class SimpleTest(Test): Run an arbitrary command that returns either 0 (PASS) or !=0 (FAIL). """ + re_avocado_log = re.compile(r'^\d\d:\d\d:\d\d DEBUG\| \[stdout\]' + r' \d\d:\d\d:\d\d WARN \|') + def __init__(self, path, params=None, base_logdir=None, tag=None, job=None): self.path = os.path.abspath(path) super(SimpleTest, self).__init__(name=path, base_logdir=base_logdir, @@ -543,9 +547,8 @@ class SimpleTest(Test): :param result: :class:`avocado.utils.process.CmdResult` instance. """ - run_info = str(result) - for line in run_info.splitlines(): - self.log.info(line) + self.log.info("Exit status: %s", result.exit_status) + self.log.info("Duration: %s", result.duration) def action(self): """ @@ -562,6 +565,14 @@ class SimpleTest(Test): self._log_detailed_cmd_info(details.result) raise exceptions.TestFail(details) + def runTest(self, result=None): + super(SimpleTest, self).runTest(result) + for line in open(self.logfile): + if self.re_avocado_log.match(line): + raise exceptions.TestWarn("Test passed but there were warnings" + " on stdout during execution. Check " + "the log for details.") + class MissingTest(Test): diff --git a/docs/source/WritingTests.rst b/docs/source/WritingTests.rst index 07fe970f..87712cf6 100644 --- a/docs/source/WritingTests.rst +++ b/docs/source/WritingTests.rst @@ -711,6 +711,20 @@ Here are the current variables that Avocado exports to the tests: | * | All variables from --multiplex-file | TIMEOUT=60; IO_WORKERS=10; VM_BYTES=512M; ... | +-------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------------+ + +Simple Tests BASH extensions +============================ + +To enhance simple tests one can use supported set of libraries we created. The +only requirement is to use:: + + PATH=$(avocado "exec-path"):$PATH + +which injects path to avocado utils into shell PATH. Take a look into +``avocado exec-path`` to see list of available functions and take a look at +``examples/tests/simplewarning.sh`` for inspiration. + + Wrap Up ======= diff --git a/examples/tests/simplewarning.sh b/examples/tests/simplewarning.sh new file mode 100755 index 00000000..4eda5fe5 --- /dev/null +++ b/examples/tests/simplewarning.sh @@ -0,0 +1,9 @@ +#!/bin/sh +PATH=$(avocado "exec-path"):$PATH + +avocado_debug "Debug message" +avocado_info "Info message" +avocado_warn "Warning message (should cause this test to finish with warning)" +avocado_error "Error message (ordinary message not changing the results)" +echo "Simple output without log-level specification" +exit 0 # no error reported diff --git a/libexec/avocado-bash-utils b/libexec/avocado-bash-utils new file mode 100755 index 00000000..ecd60519 --- /dev/null +++ b/libexec/avocado-bash-utils @@ -0,0 +1,20 @@ +#!/bin/sh +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; specifically version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2014 + +# Write to avocado_log +# First argument is the log level +avocado_log() { + LEVEL=`printf '%-5s' $1` + shift + echo "`date '+%H:%M:%S'` $LEVEL| $*" +} diff --git a/libexec/avocado_debug b/libexec/avocado_debug new file mode 100755 index 00000000..7f50f40d --- /dev/null +++ b/libexec/avocado_debug @@ -0,0 +1,4 @@ +#!/bin/sh +. avocado-bash-utils + +avocado_log DEBUG $* diff --git a/libexec/avocado_error b/libexec/avocado_error new file mode 100755 index 00000000..cdefc588 --- /dev/null +++ b/libexec/avocado_error @@ -0,0 +1,4 @@ +#!/bin/sh +. avocado-bash-utils + +avocado_log ERROR $* diff --git a/libexec/avocado_info b/libexec/avocado_info new file mode 100755 index 00000000..c6ca8907 --- /dev/null +++ b/libexec/avocado_info @@ -0,0 +1,4 @@ +#!/bin/sh +. avocado-bash-utils + +avocado_log INFO $* diff --git a/libexec/avocado_warn b/libexec/avocado_warn new file mode 100755 index 00000000..a8995de0 --- /dev/null +++ b/libexec/avocado_warn @@ -0,0 +1,4 @@ +#!/bin/sh +. avocado-bash-utils + +avocado_log WARN $* diff --git a/scripts/avocado b/scripts/avocado index 2a824293..09dae4ca 100755 --- a/scripts/avocado +++ b/scripts/avocado @@ -20,6 +20,7 @@ import sys # simple magic for using scripts within a source tree basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if os.path.isdir(os.path.join(basedir, 'avocado')): + os.environ['PATH'] += ":" + os.path.join(basedir, 'libexec') sys.path.append(basedir) from avocado.cli.app import AvocadoApp diff --git a/selftests/all/functional/avocado/basic_tests.py b/selftests/all/functional/avocado/basic_tests.py index f6caf0f1..6a36b53a 100644 --- a/selftests/all/functional/avocado/basic_tests.py +++ b/selftests/all/functional/avocado/basic_tests.py @@ -266,6 +266,24 @@ class RunnerSimpleTest(unittest.TestCase): self.assertEqual(result.exit_status, expected_rc, "Avocado did not return rc %d:\n%s" % (expected_rc, result)) + def test_simplewarning(self): + """ + simplewarning.sh uses the avocado-bash-utils + """ + os.chdir(basedir) + cmd_line = ('./scripts/avocado run --sysinfo=off ' + 'examples/tests/simplewarning.sh --show-job-log') + result = process.run(cmd_line, ignore_status=True) + self.assertEqual(result.exit_status, 0, + "Avocado did not return rc 0:\n%s" % + (result)) + self.assertIn('DEBUG| Debug message', result.stdout, result) + self.assertIn('INFO | Info message', result.stdout, result) + self.assertIn('WARN | Warning message (should cause this test to ' + 'finish with warning)', result.stdout, result) + self.assertIn('ERROR| Error message (ordinary message not changing ' + 'the results)', result.stdout, result) + def tearDown(self): self.pass_script.remove() self.fail_script.remove() diff --git a/setup.py b/setup.py index 9d7e0700..02377cae 100755 --- a/setup.py +++ b/setup.py @@ -48,6 +48,15 @@ def get_tests_dir(): return get_dir(['usr', 'share', 'avocado', 'tests'], ['tests']) +def get_avocado_libexec_dir(): + if VIRTUAL_ENV: + return get_dir(['libexec']) + elif os.path.exists('/usr/libexec'): # RHEL-like distro + return get_dir(['usr', 'libexec', 'avocado']) + else: # Debian-like distro + return get_dir(['usr', 'lib', 'avocado']) + + def get_data_files(): data_files = [(get_dir(['etc', 'avocado']), ['etc/avocado/avocado.conf'])] data_files += [(get_dir(['etc', 'avocado', 'conf.d']), @@ -65,6 +74,7 @@ def get_data_files(): glob.glob('examples/wrappers/*.sh'))] data_files += [(get_dir(['usr', 'share', 'avocado', 'api'], ['api']), glob.glob('examples/api/*/*.py'))] + data_files.append((get_avocado_libexec_dir(), glob.glob('libexec/*'))) return data_files -- GitLab