From 67079cd97eda4bac433a23c97cb8c55e42c7978d Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Sat, 5 Dec 2015 23:04:49 +0900 Subject: [PATCH 01/20] Add subunit_trace --color option's doc This commit adds a document for the subunit_trace --color option. Change-Id: I0278a20ead837d20161e4410abec0c711cc402cd --- doc/source/subunit_trace.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/subunit_trace.rst b/doc/source/subunit_trace.rst index 1338fe6..aa9388d 100644 --- a/doc/source/subunit_trace.rst +++ b/doc/source/subunit_trace.rst @@ -11,7 +11,7 @@ Summary ------- subunit-trace [--fails|-f] [--failonly] [--perc-diff|-d] [--no-summary] - [--diff-threshold|-t ] + [--diff-threshold|-t ] [--color] Options ------- @@ -31,6 +31,8 @@ Options change will always be displayed. --no-summary Don't print the summary of the test run after completes + --color + Print result with colors Usage ----- From 5ca66b4680a813839710b8838d06fce26fafeeb8 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Wed, 23 Dec 2015 01:31:14 +0000 Subject: [PATCH 02/20] remove python 2.6 trove classifier OpenStack projects are no longer being tested under Python 2.6, so remove the trove classifier implying that this project supports 2.6. Change-Id: Iac614c24ba33b169ffcb83680556adf0b550f2c3 --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index ab1151a..2ceb8b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,7 +15,6 @@ classifier = Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 - Programming Language :: Python :: 2.6 Programming Language :: Python :: 3 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 From 6f3958fb353bba450a044e028c92e7e785b45e72 Mon Sep 17 00:00:00 2001 From: janonymous Date: Sat, 26 Dec 2015 12:54:37 +0530 Subject: [PATCH 03/20] py26/py33 are no longer supported by Infra's CI Python 3.3/2.6 support would be dropped by Infra team from mitaka,CI would no longer be testing it, so projects should drop it also. Change-Id: Ib4c347038aa894ef808c0ab731d9b38982a47b40 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 931250f..44404b3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.6 -envlist = py33,py34,py26,py27,pypy,pep8 +envlist = py34,py27,pypy,pep8 skipsdist = True [testenv] From 8f71069bc85acb1703328971dd946230ebde2fd6 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Fri, 4 Dec 2015 18:34:41 +0900 Subject: [PATCH 04/20] Add unit test for colorizer This commit adds unit-test cases for colorizer module. Change-Id: I329a808bbed3240e6fa41ac21d3e5558a0704d6a --- os_testr/tests/utils/__init__.py | 0 os_testr/tests/utils/test_colorizer.py | 76 ++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 os_testr/tests/utils/__init__.py create mode 100644 os_testr/tests/utils/test_colorizer.py diff --git a/os_testr/tests/utils/__init__.py b/os_testr/tests/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/os_testr/tests/utils/test_colorizer.py b/os_testr/tests/utils/test_colorizer.py new file mode 100644 index 0000000..fdf96b2 --- /dev/null +++ b/os_testr/tests/utils/test_colorizer.py @@ -0,0 +1,76 @@ +# Copyright 2016 Hewlett Packard Enterprise Development LP +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import six +import sys + +from ddt import data +from ddt import ddt +from ddt import unpack + +from os_testr.tests import base +from os_testr.utils import colorizer + + +@ddt +class TestNullColorizer(base.TestCase): + + @data(None, "foo", sys.stdout, ) + def test_supported_always_true(self, stream): + self.assertTrue(colorizer.NullColorizer.supported(stream)) + + @data(("foo", "red"), ("foo", "bar")) + @unpack + def test_write_string_ignore_color(self, text, color): + output = six.StringIO() + c = colorizer.NullColorizer(output) + c.write(text, color) + self.assertEqual(text, output.getvalue()) + + @data((None, "red"), (None, None)) + @unpack + def test_write_none_exception(self, text, color): + c = colorizer.NullColorizer(sys.stdout) + self.assertRaises(TypeError, c.write, text, color) + + +@ddt +class TestAnsiColorizer(base.TestCase): + + def test_supported_false(self): + # NOTE(masayukig): This returns False because our unittest env isn't + # interactive + self.assertFalse(colorizer.AnsiColorizer.supported(sys.stdout)) + + @data(None, "foo") + def test_supported_error(self, stream): + self.assertRaises(AttributeError, + colorizer.AnsiColorizer.supported, stream) + + @data(("foo", "red", "31"), ("foo", "blue", "34")) + @unpack + def test_write_string_valid_color(self, text, color, color_code): + output = six.StringIO() + c = colorizer.AnsiColorizer(output) + c.write(text, color) + self.assertIn(text, output.getvalue()) + self.assertIn(color_code, output.getvalue()) + + @data(("foo", None), ("foo", "invalid_color")) + @unpack + def test_write_string_invalid_color(self, text, color): + output = six.StringIO() + c = colorizer.AnsiColorizer(output) + self.assertRaises(KeyError, c.write, text, color) From 87ec944a0c79b44011f974e1433b1946b0535295 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Tue, 26 Jan 2016 14:25:59 +0900 Subject: [PATCH 05/20] Updated from global requirements This commit updates *requirements.txt that comes from global requirements. Change-Id: I19df7b5d7ce54d5a793018e8158d985775fb7007 --- requirements.txt | 10 +++++----- test-requirements.txt | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 39d130e..428a8b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.3,<2.0 -Babel>=1.3 -testrepository>=0.0.18 -python-subunit>=0.0.18 -testtools>=1.4.0 +pbr>=1.6 # Apache-2.0 +Babel>=1.3 # BSD +testrepository>=0.0.18 # Apache-2.0/BSD +python-subunit>=0.0.18 # Apache-2.0/BSD +testtools>=1.4.0 # MIT diff --git a/test-requirements.txt b/test-requirements.txt index 608d49e..c2b57d8 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,13 +2,13 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking<0.11,>=0.10.0 +hacking>=0.10.2,<0.11 # Apache-2.0 -coverage>=3.6 -discover -sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 +coverage>=3.6 # Apache-2.0 +discover # BSD +sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD oslosphinx>=2.2.0 # Apache-2.0 oslotest>=1.2.0 # Apache-2.0 -testscenarios>=0.4 -ddt>=0.4.0 -six>=1.9.0 +testscenarios>=0.4 # Apache-2.0/BSD +ddt>=1.0.1 # MIT +six>=1.9.0 # MIT From bef89fc8f8917be7271312f7ee7df558c03ae1cd Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 14 Jan 2016 16:22:34 -0500 Subject: [PATCH 06/20] Enable testr run passthrough arguments This commit enables passing through any unknown arguments to testr run. There are several features in testr's run cli which aren't exposed in ostestr. Instead of adding a duplicate argument for each of these this commit will capture any unidentified arguments and will pass them through to the testr run subprocess call. Change-Id: I26eb5c6a5908258c3035b93d72924646bb834d40 --- os_testr/os_testr.py | 18 ++++++++++++------ os_testr/tests/test_os_testr.py | 12 ++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/os_testr/os_testr.py b/os_testr/os_testr.py index 6222bed..166022d 100755 --- a/os_testr/os_testr.py +++ b/os_testr/os_testr.py @@ -86,7 +86,7 @@ def get_parser(args): 'prints the comment from the same line and all ' 'skipped tests before the test run') parser.set_defaults(pretty=True, slowest=True, parallel=True) - return parser.parse_args(args) + return parser.parse_known_args(args) def _get_test_list(regex, env=None): @@ -175,7 +175,8 @@ def construct_regex(blacklist_file, whitelist_file, regex, print_exclude): def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur, - until_failure, color): + until_failure, color, others=None): + others = others or [] if parallel: cmd = ['testr', 'run', '--parallel'] if concur: @@ -237,11 +238,13 @@ def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur, exit(0) # If not until-failure special case call testr like normal elif pretty and not list_tests: + cmd.extend(others) ps = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE) proc = subprocess.Popen(subunit_trace_cmd, env=env, stdin=ps.stdout) ps.stdout.close() else: + cmd.extend(others) proc = subprocess.Popen(cmd, env=env) proc.communicate() return_code = proc.returncode @@ -268,7 +271,7 @@ def call_subunit_run(test_id, pretty, subunit): testtools_run.main([sys.argv[0], test_id], sys.stdout) -def _select_and_call_runner(opts, exclude_regex): +def _select_and_call_runner(opts, exclude_regex, others): ec = 1 if not os.path.isdir('.testrepository'): subprocess.call(['testr', 'init']) @@ -276,8 +279,11 @@ def _select_and_call_runner(opts, exclude_regex): if not opts.no_discover and not opts.pdb: ec = call_testr(exclude_regex, opts.subunit, opts.pretty, opts.list, opts.slowest, opts.parallel, opts.concurrency, - opts.until_failure, opts.color) + opts.until_failure, opts.color, others) else: + if others: + print('Unexpected arguments: ' + ' '.join(others)) + return 2 test_to_run = opts.no_discover or opts.pdb if test_to_run.find('/') != -1: test_to_run = path_to_regex(test_to_run) @@ -286,7 +292,7 @@ def _select_and_call_runner(opts, exclude_regex): def main(): - opts = get_parser(sys.argv[1:]) + opts, others = get_parser(sys.argv[1:]) if opts.pretty and opts.subunit: msg = ('Subunit output and pretty output cannot be specified at the ' 'same time') @@ -313,7 +319,7 @@ def main(): opts.whitelist_file, regex, opts.print_exclude) - exit(_select_and_call_runner(opts, exclude_regex)) + exit(_select_and_call_runner(opts, exclude_regex, others)) if __name__ == '__main__': main() diff --git a/os_testr/tests/test_os_testr.py b/os_testr/tests/test_os_testr.py index 8560757..4fea945 100644 --- a/os_testr/tests/test_os_testr.py +++ b/os_testr/tests/test_os_testr.py @@ -38,25 +38,25 @@ class TestPathToRegex(base.TestCase): class TestGetParser(base.TestCase): def test_pretty(self): namespace = os_testr.get_parser(['--pretty']) - self.assertEqual(True, namespace.pretty) + self.assertEqual(True, namespace[0].pretty) namespace = os_testr.get_parser(['--no-pretty']) - self.assertEqual(False, namespace.pretty) + self.assertEqual(False, namespace[0].pretty) self.assertRaises(SystemExit, os_testr.get_parser, ['--no-pretty', '--pretty']) def test_slowest(self): namespace = os_testr.get_parser(['--slowest']) - self.assertEqual(True, namespace.slowest) + self.assertEqual(True, namespace[0].slowest) namespace = os_testr.get_parser(['--no-slowest']) - self.assertEqual(False, namespace.slowest) + self.assertEqual(False, namespace[0].slowest) self.assertRaises(SystemExit, os_testr.get_parser, ['--no-slowest', '--slowest']) def test_parallel(self): namespace = os_testr.get_parser(['--parallel']) - self.assertEqual(True, namespace.parallel) + self.assertEqual(True, namespace[0].parallel) namespace = os_testr.get_parser(['--serial']) - self.assertEqual(False, namespace.parallel) + self.assertEqual(False, namespace[0].parallel) self.assertRaises(SystemExit, os_testr.get_parser, ['--parallel', '--serial']) From 7980dde165b1ae6acc058ecd1cf8edf98bc29d97 Mon Sep 17 00:00:00 2001 From: Jake Yip Date: Tue, 2 Feb 2016 15:59:08 +1100 Subject: [PATCH 07/20] correct typo Change-Id: I39e4eacadca8caa5c249de5a2105b4674a54a27b --- doc/source/ostestr.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/ostestr.rst b/doc/source/ostestr.rst index 84b920a..ac1290f 100644 --- a/doc/source/ostestr.rst +++ b/doc/source/ostestr.rst @@ -114,7 +114,7 @@ exposed via the --regex option. For example:: This will do a straight passthrough of the provided regex to testr. Additionally, ostestr allows you to specify a blacklist file to define a set of regexes to exclude. You can specify a blacklist file with the ---blacklist-file/-b option, for example:: +--blacklist_file/-b option, for example:: $ ostestr --blacklist_file $path_to_file From 08b5418f738dde1cf3d126ae85c37c636c29ee01 Mon Sep 17 00:00:00 2001 From: OpenStack Proposal Bot Date: Wed, 10 Feb 2016 21:57:50 +0000 Subject: [PATCH 08/20] Updated from global requirements Change-Id: I2246ce4ec35e0d60ca68dc6920d6d558a43fde7d --- requirements.txt | 10 +++++----- setup.py | 3 +-- test-requirements.txt | 18 +++++++++--------- 3 files changed, 15 insertions(+), 16 deletions(-) mode change 100755 => 100644 setup.py diff --git a/requirements.txt b/requirements.txt index 428a8b1..6a4bdf2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.6 # Apache-2.0 -Babel>=1.3 # BSD -testrepository>=0.0.18 # Apache-2.0/BSD -python-subunit>=0.0.18 # Apache-2.0/BSD -testtools>=1.4.0 # MIT +pbr>=1.6 # Apache-2.0 +Babel>=1.3 # BSD +testrepository>=0.0.18 # Apache-2.0/BSD +python-subunit>=0.0.18 # Apache-2.0/BSD +testtools>=1.4.0 # MIT diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index ee81ca9..782bb21 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,5 +25,5 @@ except ImportError: pass setuptools.setup( - setup_requires=['pbr>=1.3'], + setup_requires=['pbr>=1.8'], pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt index c2b57d8..3b3e208 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,13 +2,13 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking>=0.10.2,<0.11 # Apache-2.0 +hacking<0.11,>=0.10.2 # Apache-2.0 -coverage>=3.6 # Apache-2.0 -discover # BSD -sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD -oslosphinx>=2.2.0 # Apache-2.0 -oslotest>=1.2.0 # Apache-2.0 -testscenarios>=0.4 # Apache-2.0/BSD -ddt>=1.0.1 # MIT -six>=1.9.0 # MIT +coverage>=3.6 # Apache-2.0 +discover # BSD +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD +oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 +oslotest>=1.10.0 # Apache-2.0 +testscenarios>=0.4 # Apache-2.0/BSD +ddt>=1.0.1 # MIT +six>=1.9.0 # MIT From 8502e72356cfe7d1c76c33c4f674ea0325220327 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 22 Feb 2016 16:30:26 -0500 Subject: [PATCH 09/20] Treat xfail output like success This commit updates one edge case where output from xfail was treated like a failure instead of like a success. Change-Id: I073302bc9aea6751906cb4955055c55b7c5dc3fc --- os_testr/subunit_trace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os_testr/subunit_trace.py b/os_testr/subunit_trace.py index f194c6e..2a03fdf 100755 --- a/os_testr/subunit_trace.py +++ b/os_testr/subunit_trace.py @@ -191,7 +191,7 @@ def show_outcome(stream, test, print_failures=False, failonly=False, if not print_failures: print_attachments(stream, test, all_channels=True) elif not failonly: - if status == 'success': + if status == 'success' or status == 'xfail': if abbreviate: color.write('.', 'green') else: From 7ac7fc457beaefc948bf05346a811aba5abd8fb0 Mon Sep 17 00:00:00 2001 From: Shu Muto Date: Thu, 7 Jan 2016 02:40:06 +0000 Subject: [PATCH 10/20] remove python 3.3 trove classifier OpenStack projects are no longer being tested under Python 3.3, so remove the trove classifier implying that this project supports 3.3. Change-Id: Ic189fc1f4159459457bf9ca0e55969f6b17b2d8e Closes-Bug: #1526170 --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index bb1d9ed..409a9f2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,7 +16,6 @@ classifier = Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 [files] From 28a9f32ec7e4a7af4e7438dc71a7c79761668a93 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Mon, 28 Mar 2016 13:50:58 +0900 Subject: [PATCH 11/20] Add pypi download + version badges into README.rst This commit adds pypi download and version badges into README.rst. With these badges, users can know the latest version and download statistics. Change-Id: I16eed1cf4acf84df728ba9c9dcf7706d14a484fe --- README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.rst b/README.rst index c03be76..94a8df5 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,14 @@ os-testr ======== +.. image:: https://img.shields.io/pypi/v/os-testr.svg + :target: https://pypi.python.org/pypi/os-testr/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/dm/os-testr.svg + :target: https://pypi.python.org/pypi/os-testr/ + :alt: Downloads + A testr wrapper to provide functionality for OpenStack projects. * Free software: Apache license From 9a6f4c9653fc64408665eda9f716021bb3468c28 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Mon, 4 Apr 2016 14:38:33 +0900 Subject: [PATCH 12/20] Remove openstack-common.conf This commit removes openstack-common.conf file. It was introduced by the cookiecutter when the os-testr repository was created. However, this file isn't used anymore, and it was already removed from the cookiecutter repository as a cleanup[1]. [1] I2b5377391a4422caa395f62fbd5df3049f01fdec Change-Id: Id33e4c7c4bd8cebded08f5dad55a60cf0be7cd0f --- openstack-common.conf | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 openstack-common.conf diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 29ef5fa..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] - -# The list of modules to copy from oslo-incubator.git - -# The base module to hold the copy of openstack.common -base=os_testr From 0bb53cdfcc6262d44e7ba4b81198bc691f97e0ca Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Mon, 4 Apr 2016 15:15:31 +0900 Subject: [PATCH 13/20] Add version option for ostestr and subunit-trace This commit adds a version option to os-testr commands. Users would like to confirm the version when then face unexpected behavior of the command like a bug. Change-Id: I30ee9623c25f2ce2da0fab0b5e0a2795b46a2cd6 --- os_testr/generate_subunit.py | 8 ++++++++ os_testr/os_testr.py | 6 ++++++ os_testr/subunit2html.py | 8 +++++++- os_testr/subunit_trace.py | 6 ++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/os_testr/generate_subunit.py b/os_testr/generate_subunit.py index cc38c5d..15b819f 100755 --- a/os_testr/generate_subunit.py +++ b/os_testr/generate_subunit.py @@ -17,11 +17,19 @@ import datetime import sys +import pbr.version import subunit from subunit import iso8601 +__version__ = pbr.version.VersionInfo('os_testr').version_string() + + def main(): + if '--version' in sys.argv: + print(__version__) + exit(0) + start_time = datetime.datetime.fromtimestamp(float(sys.argv[1])).replace( tzinfo=iso8601.UTC) elapsed_time = datetime.timedelta(seconds=int(sys.argv[2])) diff --git a/os_testr/os_testr.py b/os_testr/os_testr.py index 166022d..32daf9a 100755 --- a/os_testr/os_testr.py +++ b/os_testr/os_testr.py @@ -19,13 +19,19 @@ import os import subprocess import sys +import pbr.version from subunit import run as subunit_run from testtools import run as testtools_run +__version__ = pbr.version.VersionInfo('os_testr').version_string() + + def get_parser(args): parser = argparse.ArgumentParser( description='Tool to run openstack tests') + parser.add_argument('--version', action='version', + version='%s' % __version__) list_files = parser.add_mutually_exclusive_group() list_files.add_argument('--blacklist_file', '-b', help='Path to a blacklist file, this file ' diff --git a/os_testr/subunit2html.py b/os_testr/subunit2html.py index c40909e..096a91b 100755 --- a/os_testr/subunit2html.py +++ b/os_testr/subunit2html.py @@ -60,10 +60,12 @@ import sys import traceback from xml.sax import saxutils +import pbr.version import subunit import testtools -__version__ = '0.1' + +__version__ = pbr.version.VersionInfo('os_testr').version_string() class TemplateData(object): @@ -701,6 +703,10 @@ class FileAccumulator(testtools.StreamResult): def main(): + if '--version' in sys.argv: + print(__version__) + exit(0) + if len(sys.argv) < 2: print("Need at least one argument: path to subunit log.") exit(1) diff --git a/os_testr/subunit_trace.py b/os_testr/subunit_trace.py index 2a03fdf..fa9d98c 100755 --- a/os_testr/subunit_trace.py +++ b/os_testr/subunit_trace.py @@ -26,6 +26,7 @@ import os import re import sys +import pbr.version import subunit import testtools @@ -313,8 +314,13 @@ def print_summary(stream, elapsed_time): stream.write(out_str) +__version__ = pbr.version.VersionInfo('os_testr').version_string() + + def parse_args(): parser = argparse.ArgumentParser() + parser.add_argument('--version', action='version', + version='%s' % __version__) parser.add_argument('--no-failure-debug', '-n', action='store_true', dest='print_failures', help='Disable printing failure ' 'debug information in realtime') From 6e908db6dfaf43be5992b206e145f4a0588afe96 Mon Sep 17 00:00:00 2001 From: Yushiro FURUKAWA Date: Wed, 13 Apr 2016 06:58:00 +0900 Subject: [PATCH 14/20] Fix coverage option and execution --coverage-package-name option was no longer supported by 'testr'[1]. This commit replaces from 'testr' to 'test' as coverage option. [1] https://review.openstack.org/#/c/217847/ Change-Id: I0430fd696752c1cd8e33bb2d146e08e442ebc3f8 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 44404b3..c052dcb 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ commands = flake8 commands = {posargs} [testenv:cover] -commands = python setup.py testr --coverage --coverage-package-name='os_testr' --testr-args='{posargs}' +commands = python setup.py test --coverage --coverage-package-name='os_testr' --testr-args='{posargs}' [testenv:docs] commands = python setup.py build_sphinx From 23557a0bf877d8ddc8c79f15b9b8780bfa5415c3 Mon Sep 17 00:00:00 2001 From: OpenStack Proposal Bot Date: Wed, 13 Apr 2016 12:47:16 +0000 Subject: [PATCH 15/20] Updated from global requirements Change-Id: I12ace2aa7553d892e4325f59dcaeb43271af0eaa --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6a4bdf2..ec74a9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ # process, which may cause wedges in the gate later. pbr>=1.6 # Apache-2.0 -Babel>=1.3 # BSD +Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # BSD testrepository>=0.0.18 # Apache-2.0/BSD python-subunit>=0.0.18 # Apache-2.0/BSD testtools>=1.4.0 # MIT From deaabb5fb71e1cb2bc71d7c0747cdcf72239d54e Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Mon, 18 Apr 2016 16:21:30 +0900 Subject: [PATCH 16/20] Fix docs typos This commit fixes docs typos. Change-Id: I7f2369e2aad82f2883e408f56204c89e723cc376 --- doc/source/ostestr.rst | 4 ++-- os_testr/os_testr.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/ostestr.rst b/doc/source/ostestr.rst index ac1290f..894bab6 100644 --- a/doc/source/ostestr.rst +++ b/doc/source/ostestr.rst @@ -36,12 +36,12 @@ Options Disable the pretty output with subunit-trace --subunit, -s output the raw subunit v2 from the test run this is - mutuall exclusive with --pretty + mutually exclusive with --pretty --list, -l List all the tests which will be run. --no-discover TEST_ID, -n TEST_ID Takes in a single test to bypasses test discover and - just excute the test specified + just execute the test specified --slowest After the test run print the slowest tests --no-slowest diff --git a/os_testr/os_testr.py b/os_testr/os_testr.py index 166022d..8354335 100755 --- a/os_testr/os_testr.py +++ b/os_testr/os_testr.py @@ -44,7 +44,7 @@ def get_parser(args): help='A file name or directory of tests to run.') group.add_argument('--no-discover', '-n', metavar='TEST_ID', help="Takes in a single test to bypasses test " - "discover and just excute the test specified. " + "discover and just execute the test specified. " "A file name may be used in place of a test " "name.") pretty = parser.add_mutually_exclusive_group() From 24a0b840b5ec38cd30e5114d93b4738ea75f3013 Mon Sep 17 00:00:00 2001 From: OpenStack Proposal Bot Date: Fri, 6 May 2016 22:21:28 +0000 Subject: [PATCH 17/20] Updated from global requirements Change-Id: Ie11baaa6281b9879a469ebf5bae1e17f80325c9a --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ec74a9e..eefcfb4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ # process, which may cause wedges in the gate later. pbr>=1.6 # Apache-2.0 -Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # BSD +Babel>=2.3.4 # BSD testrepository>=0.0.18 # Apache-2.0/BSD python-subunit>=0.0.18 # Apache-2.0/BSD testtools>=1.4.0 # MIT From 7c2bb825c422f69964f0d0147d11111ea6ba1d2e Mon Sep 17 00:00:00 2001 From: step6829 Date: Tue, 23 Feb 2016 11:14:23 -0500 Subject: [PATCH 18/20] Split functionality out of main This commit splits out the actual output generation functionality from the main function. It also adds parameters for specifying a stdin and stdout file object. This enables external access to the output generation within python, which could be useful for integrating subunit-trace output with your own test runner. Change-Id: Id9fc13b9b70c5b2cc47b48eee6426e7e312eff7f --- os_testr/subunit_trace.py | 42 +++++++++++++++++----------- os_testr/tests/test_subunit_trace.py | 15 ++++++++++ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/os_testr/subunit_trace.py b/os_testr/subunit_trace.py index f194c6e..89b071f 100755 --- a/os_testr/subunit_trace.py +++ b/os_testr/subunit_trace.py @@ -344,21 +344,22 @@ def parse_args(): return parser.parse_args() -def main(): - args = parse_args() +def trace(stdin, stdout, print_failures=False, failonly=False, + enable_diff=False, abbreviate=False, color=False, post_fails=False, + no_summary=False): stream = subunit.ByteStreamToStreamResult( - sys.stdin, non_subunit_name='stdout') + stdin, non_subunit_name='stdout') outcomes = testtools.StreamToDict( - functools.partial(show_outcome, sys.stdout, - print_failures=args.print_failures, - failonly=args.failonly, - enable_diff=args.enable_diff, - abbreviate=args.abbreviate, - enable_color=args.color)) + functools.partial(show_outcome, stdout, + print_failures=print_failures, + failonly=failonly, + enable_diff=enable_diff, + abbreviate=abbreviate, + enable_color=color)) summary = testtools.StreamSummary() result = testtools.CopyStreamResult([outcomes, summary]) result = testtools.StreamResultRouter(result) - cat = subunit.test_results.CatFiles(sys.stdout) + cat = subunit.test_results.CatFiles(stdout) result.add_rule(cat, 'test_id', test_id=None) start_time = datetime.datetime.utcnow() result.startTestRun() @@ -371,18 +372,25 @@ def main(): if count_tests('status', '.*') == 0: print("The test run didn't actually run any tests") - exit(1) - if args.post_fails: - print_fails(sys.stdout) - if not args.no_summary: - print_summary(sys.stdout, elapsed_time) + return 1 + if post_fails: + print_fails(stdout) + if not no_summary: + print_summary(stdout, elapsed_time) # NOTE(mtreinish): Ideally this should live in testtools streamSummary # this is just in place until the behavior lands there (if it ever does) if count_tests('status', '^success$') == 0: print("\nNo tests were successful during the run") - exit(1) - exit(0 if summary.wasSuccessful() else 1) + return 1 + return 0 if summary.wasSuccessful() else 1 + + +def main(): + args = parse_args() + exit(trace(sys.stdin, sys.stdout, args.print_failures, args.failonly, + args.enable_diff, args.abbreviate, args.color, args.post_fails, + args.no_summary)) if __name__ == '__main__': diff --git a/os_testr/tests/test_subunit_trace.py b/os_testr/tests/test_subunit_trace.py index 736dff9..462bceb 100644 --- a/os_testr/tests/test_subunit_trace.py +++ b/os_testr/tests/test_subunit_trace.py @@ -14,13 +14,16 @@ # under the License. from datetime import datetime as dt +import io import os import subprocess +import sys from ddt import data from ddt import ddt from ddt import unpack from mock import patch +import six from os_testr import subunit_trace from os_testr.tests import base @@ -79,3 +82,15 @@ class TestSubunitTrace(base.TestCase): with open(regular_stream, 'rb') as stream: p.communicate(stream.read()) self.assertEqual(0, p.returncode) + + def test_trace(self): + regular_stream = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'sample_streams/successful.subunit') + bytes_ = io.BytesIO() + with open(regular_stream, 'rb') as stream: + bytes_.write(six.binary_type(stream.read())) + bytes_.seek(0) + stdin = io.TextIOWrapper(io.BufferedReader(bytes_)) + returncode = subunit_trace.trace(stdin, sys.stdout) + self.assertEqual(0, returncode) From 73bf72c71b99a05515f068d28c58dc3e9105202b Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 4 May 2016 12:59:20 -0400 Subject: [PATCH 19/20] Seperate regex builder logic into a seperate module The regex building logic is independently useful and will likely start to be used in other places. This commits splits it out from the ostestr cli and makes it an independent module that just contains the pieces necessary for building a selection regex. Change-Id: Ic8494d0f54357fdafd650b40219e6ad7fd5a65ad --- os_testr/{os_testr.py => ostestr.py} | 101 ++------------- os_testr/regex_builder.py | 102 +++++++++++++++ os_testr/tests/test_ostestr.py | 117 ++++++++++++++++++ ...test_os_testr.py => test_regex_builder.py} | 102 +-------------- setup.cfg | 2 +- 5 files changed, 231 insertions(+), 193 deletions(-) rename os_testr/{os_testr.py => ostestr.py} (77%) create mode 100644 os_testr/regex_builder.py create mode 100644 os_testr/tests/test_ostestr.py rename os_testr/tests/{test_os_testr.py => test_regex_builder.py} (65%) diff --git a/os_testr/os_testr.py b/os_testr/ostestr.py similarity index 77% rename from os_testr/os_testr.py rename to os_testr/ostestr.py index 14a45bf..17ed1bd 100755 --- a/os_testr/os_testr.py +++ b/os_testr/ostestr.py @@ -23,6 +23,8 @@ import pbr.version from subunit import run as subunit_run from testtools import run as testtools_run +from os_testr import regex_builder as rb + __version__ = pbr.version.VersionInfo('os_testr').version_string() @@ -95,91 +97,6 @@ def get_parser(args): return parser.parse_known_args(args) -def _get_test_list(regex, env=None): - env = env or copy.deepcopy(os.environ) - proc = subprocess.Popen(['testr', 'list-tests', regex], env=env, - stdout=subprocess.PIPE) - out = proc.communicate()[0] - raw_test_list = out.split('\n') - bad = False - test_list = [] - exclude_list = ['OS_', 'CAPTURE', 'TEST_TIMEOUT', 'PYTHON', - 'subunit.run discover'] - for line in raw_test_list: - for exclude in exclude_list: - if exclude in line: - bad = True - break - elif not line: - bad = True - break - if not bad: - test_list.append(line) - bad = False - return test_list - - -def print_skips(regex, message): - test_list = _get_test_list(regex) - if test_list: - if message: - print(message) - else: - print('Skipped because of regex %s:' % regex) - for test in test_list: - print(test) - # Extra whitespace to separate - print('\n') - - -def path_to_regex(path): - root, _ = os.path.splitext(path) - return root.replace('/', '.') - - -def get_regex_from_whitelist_file(file_path): - lines = [] - for line in open(file_path).read().splitlines(): - split_line = line.strip().split('#') - # Before the # is the regex - line_regex = split_line[0].strip() - if line_regex: - lines.append(line_regex) - return '|'.join(lines) - - -def construct_regex(blacklist_file, whitelist_file, regex, print_exclude): - if not blacklist_file: - exclude_regex = '' - else: - black_file = open(blacklist_file, 'r') - exclude_regex = '' - for line in black_file: - raw_line = line.strip() - split_line = raw_line.split('#') - # Before the # is the regex - line_regex = split_line[0].strip() - if len(split_line) > 1: - # After the # is a comment - comment = split_line[1].strip() - else: - comment = '' - if line_regex: - if print_exclude: - print_skips(line_regex, comment) - if exclude_regex: - exclude_regex = '|'.join([line_regex, exclude_regex]) - else: - exclude_regex = line_regex - if exclude_regex: - exclude_regex = "^((?!" + exclude_regex + ").)*$" - if regex: - exclude_regex += regex - if whitelist_file: - exclude_regex += '%s' % get_regex_from_whitelist_file(whitelist_file) - return exclude_regex - - def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur, until_failure, color, others=None): others = others or [] @@ -206,7 +123,7 @@ def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur, # This workaround is necessary because of lp bug 1411804 it's super hacky # and makes tons of unfounded assumptions, but it works for the most part if (subunit or pretty) and until_failure: - test_list = _get_test_list(regex, env) + test_list = rb._get_test_list(regex, env) count = 0 failed = False if not test_list: @@ -292,7 +209,7 @@ def _select_and_call_runner(opts, exclude_regex, others): return 2 test_to_run = opts.no_discover or opts.pdb if test_to_run.find('/') != -1: - test_to_run = path_to_regex(test_to_run) + test_to_run = rb.path_to_regex(test_to_run) ec = call_subunit_run(test_to_run, opts.pretty, opts.subunit) return ec @@ -318,13 +235,13 @@ def main(): print(msg) exit(5) if opts.path: - regex = path_to_regex(opts.path) + regex = rb.path_to_regex(opts.path) else: regex = opts.regex - exclude_regex = construct_regex(opts.blacklist_file, - opts.whitelist_file, - regex, - opts.print_exclude) + exclude_regex = rb.construct_regex(opts.blacklist_file, + opts.whitelist_file, + regex, + opts.print_exclude) exit(_select_and_call_runner(opts, exclude_regex, others)) if __name__ == '__main__': diff --git a/os_testr/regex_builder.py b/os_testr/regex_builder.py new file mode 100644 index 0000000..acba769 --- /dev/null +++ b/os_testr/regex_builder.py @@ -0,0 +1,102 @@ +# Copyright 2016 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import copy +import os +import subprocess + + +def _get_test_list(regex, env=None): + env = env or copy.deepcopy(os.environ) + proc = subprocess.Popen(['testr', 'list-tests', regex], env=env, + stdout=subprocess.PIPE) + out = proc.communicate()[0] + raw_test_list = out.split('\n') + bad = False + test_list = [] + exclude_list = ['OS_', 'CAPTURE', 'TEST_TIMEOUT', 'PYTHON', + 'subunit.run discover'] + for line in raw_test_list: + for exclude in exclude_list: + if exclude in line: + bad = True + break + elif not line: + bad = True + break + if not bad: + test_list.append(line) + bad = False + return test_list + + +def print_skips(regex, message): + test_list = _get_test_list(regex) + if test_list: + if message: + print(message) + else: + print('Skipped because of regex %s:' % regex) + for test in test_list: + print(test) + # Extra whitespace to separate + print('\n') + + +def path_to_regex(path): + root, _ = os.path.splitext(path) + return root.replace('/', '.') + + +def get_regex_from_whitelist_file(file_path): + lines = [] + for line in open(file_path).read().splitlines(): + split_line = line.strip().split('#') + # Before the # is the regex + line_regex = split_line[0].strip() + if line_regex: + lines.append(line_regex) + return '|'.join(lines) + + +def construct_regex(blacklist_file, whitelist_file, regex, print_exclude): + if not blacklist_file: + exclude_regex = '' + else: + black_file = open(blacklist_file, 'r') + exclude_regex = '' + for line in black_file: + raw_line = line.strip() + split_line = raw_line.split('#') + # Before the # is the regex + line_regex = split_line[0].strip() + if len(split_line) > 1: + # After the # is a comment + comment = split_line[1].strip() + else: + comment = '' + if line_regex: + if print_exclude: + print_skips(line_regex, comment) + if exclude_regex: + exclude_regex = '|'.join([line_regex, exclude_regex]) + else: + exclude_regex = line_regex + if exclude_regex: + exclude_regex = "^((?!" + exclude_regex + ").)*$" + if regex: + exclude_regex += regex + if whitelist_file: + exclude_regex += '%s' % get_regex_from_whitelist_file(whitelist_file) + return exclude_regex diff --git a/os_testr/tests/test_ostestr.py b/os_testr/tests/test_ostestr.py new file mode 100644 index 0000000..df76ce6 --- /dev/null +++ b/os_testr/tests/test_ostestr.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +test_os_testr +---------------------------------- + +Tests for `os_testr` module. +""" + +import mock + +from os_testr import ostestr as os_testr +from os_testr.tests import base + + +class TestGetParser(base.TestCase): + def test_pretty(self): + namespace = os_testr.get_parser(['--pretty']) + self.assertEqual(True, namespace[0].pretty) + namespace = os_testr.get_parser(['--no-pretty']) + self.assertEqual(False, namespace[0].pretty) + self.assertRaises(SystemExit, os_testr.get_parser, + ['--no-pretty', '--pretty']) + + def test_slowest(self): + namespace = os_testr.get_parser(['--slowest']) + self.assertEqual(True, namespace[0].slowest) + namespace = os_testr.get_parser(['--no-slowest']) + self.assertEqual(False, namespace[0].slowest) + self.assertRaises(SystemExit, os_testr.get_parser, + ['--no-slowest', '--slowest']) + + def test_parallel(self): + namespace = os_testr.get_parser(['--parallel']) + self.assertEqual(True, namespace[0].parallel) + namespace = os_testr.get_parser(['--serial']) + self.assertEqual(False, namespace[0].parallel) + self.assertRaises(SystemExit, os_testr.get_parser, + ['--parallel', '--serial']) + + +class TestCallers(base.TestCase): + def test_no_discover(self): + namespace = os_testr.get_parser(['-n', 'project.tests.foo']) + + def _fake_exit(arg): + self.assertTrue(arg) + + def _fake_run(*args, **kwargs): + return 'project.tests.foo' in args + + with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ + mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ + mock.patch.object(os_testr, + 'call_subunit_run', + side_effect=_fake_run): + os_testr.main() + + def test_no_discover_path(self): + namespace = os_testr.get_parser(['-n', 'project/tests/foo']) + + def _fake_exit(arg): + self.assertTrue(arg) + + def _fake_run(*args, **kwargs): + return 'project.tests.foo' in args + + with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ + mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ + mock.patch.object(os_testr, + 'call_subunit_run', + side_effect=_fake_run): + os_testr.main() + + def test_pdb(self): + namespace = os_testr.get_parser(['--pdb', 'project.tests.foo']) + + def _fake_exit(arg): + self.assertTrue(arg) + + def _fake_run(*args, **kwargs): + return 'project.tests.foo' in args + + with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ + mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ + mock.patch.object(os_testr, + 'call_subunit_run', + side_effect=_fake_run): + os_testr.main() + + def test_pdb_path(self): + namespace = os_testr.get_parser(['--pdb', 'project/tests/foo']) + + def _fake_exit(arg): + self.assertTrue(arg) + + def _fake_run(*args, **kwargs): + return 'project.tests.foo' in args + + with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ + mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ + mock.patch.object(os_testr, + 'call_subunit_run', + side_effect=_fake_run): + os_testr.main() diff --git a/os_testr/tests/test_os_testr.py b/os_testr/tests/test_regex_builder.py similarity index 65% rename from os_testr/tests/test_os_testr.py rename to os_testr/tests/test_regex_builder.py index 4fea945..e284036 100644 --- a/os_testr/tests/test_os_testr.py +++ b/os_testr/tests/test_regex_builder.py @@ -12,17 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. -""" -test_os_testr ----------------------------------- - -Tests for `os_testr` module. -""" - import mock + import six -from os_testr import os_testr +from os_testr import regex_builder as os_testr from os_testr.tests import base @@ -35,98 +29,6 @@ class TestPathToRegex(base.TestCase): self.assertEqual("openstack.tests.network.v2", result) -class TestGetParser(base.TestCase): - def test_pretty(self): - namespace = os_testr.get_parser(['--pretty']) - self.assertEqual(True, namespace[0].pretty) - namespace = os_testr.get_parser(['--no-pretty']) - self.assertEqual(False, namespace[0].pretty) - self.assertRaises(SystemExit, os_testr.get_parser, - ['--no-pretty', '--pretty']) - - def test_slowest(self): - namespace = os_testr.get_parser(['--slowest']) - self.assertEqual(True, namespace[0].slowest) - namespace = os_testr.get_parser(['--no-slowest']) - self.assertEqual(False, namespace[0].slowest) - self.assertRaises(SystemExit, os_testr.get_parser, - ['--no-slowest', '--slowest']) - - def test_parallel(self): - namespace = os_testr.get_parser(['--parallel']) - self.assertEqual(True, namespace[0].parallel) - namespace = os_testr.get_parser(['--serial']) - self.assertEqual(False, namespace[0].parallel) - self.assertRaises(SystemExit, os_testr.get_parser, - ['--parallel', '--serial']) - - -class TestCallers(base.TestCase): - def test_no_discover(self): - namespace = os_testr.get_parser(['-n', 'project.tests.foo']) - - def _fake_exit(arg): - self.assertTrue(arg) - - def _fake_run(*args, **kwargs): - return 'project.tests.foo' in args - - with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ - mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ - mock.patch.object(os_testr, - 'call_subunit_run', - side_effect=_fake_run): - os_testr.main() - - def test_no_discover_path(self): - namespace = os_testr.get_parser(['-n', 'project/tests/foo']) - - def _fake_exit(arg): - self.assertTrue(arg) - - def _fake_run(*args, **kwargs): - return 'project.tests.foo' in args - - with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ - mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ - mock.patch.object(os_testr, - 'call_subunit_run', - side_effect=_fake_run): - os_testr.main() - - def test_pdb(self): - namespace = os_testr.get_parser(['--pdb', 'project.tests.foo']) - - def _fake_exit(arg): - self.assertTrue(arg) - - def _fake_run(*args, **kwargs): - return 'project.tests.foo' in args - - with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ - mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ - mock.patch.object(os_testr, - 'call_subunit_run', - side_effect=_fake_run): - os_testr.main() - - def test_pdb_path(self): - namespace = os_testr.get_parser(['--pdb', 'project/tests/foo']) - - def _fake_exit(arg): - self.assertTrue(arg) - - def _fake_run(*args, **kwargs): - return 'project.tests.foo' in args - - with mock.patch.object(os_testr, 'exit', side_effect=_fake_exit), \ - mock.patch.object(os_testr, 'get_parser', return_value=namespace), \ - mock.patch.object(os_testr, - 'call_subunit_run', - side_effect=_fake_run): - os_testr.main() - - class TestConstructRegex(base.TestCase): def test_regex_passthrough(self): result = os_testr.construct_regex(None, None, 'fake_regex', False) diff --git a/setup.cfg b/setup.cfg index 409a9f2..27f9ced 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ packages = [entry_points] console_scripts = subunit-trace = os_testr.subunit_trace:main - ostestr = os_testr.os_testr:main + ostestr = os_testr.ostestr:main subunit2html = os_testr.subunit2html:main generate-subunit = os_testr.generate_subunit:main From 74999a5dcca1fb85f677a598a6aece825348d738 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 10 May 2016 17:18:17 -0400 Subject: [PATCH 20/20] Add whitelist file to ostestr docs This commit adds the missing details for the whitelist file to the ostestr docs. Change-Id: I863dcad9b1a77a083f7007ab76760e77295c610d --- doc/source/ostestr.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/source/ostestr.rst b/doc/source/ostestr.rst index ac1290f..bc9d65a 100644 --- a/doc/source/ostestr.rst +++ b/doc/source/ostestr.rst @@ -14,6 +14,7 @@ default behavior might change in future version. Summary ------- ostestr [-b|--blacklist_file ] [-r|--regex REGEX] + [-w|--whitelist_file ] [-p|--pretty] [--no-pretty] [-s|--subunit] [-l|--list] [-n|--no-discover ] [--slowest] [--no-slowest] [--pdb ] [--parallel] [--serial] @@ -25,6 +26,9 @@ Options --blacklist_file BLACKLIST_FILE, -b BLACKLIST_FILE Path to a blacklist file, this file contains a separate regex exclude on each newline + --whitelist_file WHITELIST_FILE, -w WHITELIST_FILE + Path to a whitelist file, this file contains a + separate regex on each newline --regex REGEX, -r REGEX A normal testr selection regex. If a blacklist file is specified, the regex will be appended to the end of @@ -134,6 +138,22 @@ regex test selection options can not be used in conjunction with the because the regex selection requires using testr under the covers to actually do the filtering, and those 2 options do not use testr. +The dual of the blacklist file is the whitelist file which works in the exact +same manner, except that instead of excluding regex matches it includes them. +You can specify the path to the file with --whitelist_file/-w, for example:: + + $ ostestr --whitelist_file $path_to_file + +The format for the file is more or less identical to the blacklist file:: + + # Whitelist File + ^regex1 # Include these tests + .*regex2 # include those tests + +However, instead of excluding the matches it will include them. Note that a +blacklist file can not be used at the same time as a whitelist file, they +are mutually exclusive. + It's also worth noting that you can use the test list option to dry run any selection arguments you are using. You just need to use --list/-l with your selection options to do this, for example::