From 05cf8b497befd75207a910450d9eeafc7affa5e1 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 1 Nov 2018 14:46:36 -0400 Subject: Switch to setuptools entrypoint console scripts for filters This commit switches from using scripts to setuptools entrypoint console scripts for the filter scripts. This should fix the issues for windows users trying to execute the scripts. To accomplish this the filter scripts are moved into the subunit package namespace and a callable to run the script is added to each module. Closes-Bug: #1322888 --- python/subunit/filter_scripts/__init__.py | 0 python/subunit/filter_scripts/subunit2csv.py | 31 +++ python/subunit/filter_scripts/subunit2disk.py | 27 +++ python/subunit/filter_scripts/subunit2gtk.py | 246 ++++++++++++++++++++++ python/subunit/filter_scripts/subunit2junitxml.py | 41 ++++ python/subunit/filter_scripts/subunit2pyunit.py | 65 ++++++ python/subunit/filter_scripts/subunit_1to2.py | 42 ++++ python/subunit/filter_scripts/subunit_2to1.py | 53 +++++ python/subunit/filter_scripts/subunit_filter.py | 177 ++++++++++++++++ python/subunit/filter_scripts/subunit_ls.py | 64 ++++++ python/subunit/filter_scripts/subunit_notify.py | 53 +++++ python/subunit/filter_scripts/subunit_output.py | 28 +++ python/subunit/filter_scripts/subunit_stats.py | 38 ++++ python/subunit/filter_scripts/subunit_tags.py | 33 +++ python/subunit/filter_scripts/tap2subunit.py | 33 +++ 15 files changed, 931 insertions(+) create mode 100644 python/subunit/filter_scripts/__init__.py create mode 100755 python/subunit/filter_scripts/subunit2csv.py create mode 100755 python/subunit/filter_scripts/subunit2disk.py create mode 100755 python/subunit/filter_scripts/subunit2gtk.py create mode 100755 python/subunit/filter_scripts/subunit2junitxml.py create mode 100755 python/subunit/filter_scripts/subunit2pyunit.py create mode 100755 python/subunit/filter_scripts/subunit_1to2.py create mode 100755 python/subunit/filter_scripts/subunit_2to1.py create mode 100755 python/subunit/filter_scripts/subunit_filter.py create mode 100755 python/subunit/filter_scripts/subunit_ls.py create mode 100755 python/subunit/filter_scripts/subunit_notify.py create mode 100755 python/subunit/filter_scripts/subunit_output.py create mode 100755 python/subunit/filter_scripts/subunit_stats.py create mode 100755 python/subunit/filter_scripts/subunit_tags.py create mode 100755 python/subunit/filter_scripts/tap2subunit.py (limited to 'python') diff --git a/python/subunit/filter_scripts/__init__.py b/python/subunit/filter_scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python/subunit/filter_scripts/subunit2csv.py b/python/subunit/filter_scripts/subunit2csv.py new file mode 100755 index 0000000..4802314 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2csv.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is d on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Turn a subunit stream into a CSV""" + +from testtools import StreamToExtendedDecorator + +from subunit.filters import run_filter_script +from subunit.test_results import CsvResult + + +def main() + run_filter_script(lambda output:StreamToExtendedDecorator( + CsvResult(output)), __doc__, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2disk.py b/python/subunit/filter_scripts/subunit2disk.py new file mode 100755 index 0000000..a674d28 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2disk.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Subunit Contributors +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + + +"""Export a stream to files and directories on disk.""" + +from subunit._to_disk import to_disk + + +def main(): + exit(to_disk()) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2gtk.py b/python/subunit/filter_scripts/subunit2gtk.py new file mode 100755 index 0000000..013b07a --- /dev/null +++ b/python/subunit/filter_scripts/subunit2gtk.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +### The GTK progress bar __init__ function is derived from the pygtk tutorial: +# The PyGTK Tutorial is Copyright (C) 2001-2005 John Finlay. +# +# The GTK Tutorial is Copyright (C) 1997 Ian Main. +# +# Copyright (C) 1998-1999 Tony Gale. +# +# Permission is granted to make and distribute verbatim copies of this manual +# provided the copyright notice and this permission notice are preserved on all +# copies. +# +# Permission is granted to copy and distribute modified versions of this +# document under the conditions for verbatim copying, provided that this +# copyright notice is included exactly as in the original, and that the entire +# resulting derived work is distributed under the terms of a permission notice +# identical to this one. +# +# Permission is granted to copy and distribute translations of this document +# into another language, under the above conditions for modified versions. +# +# If you are intending to incorporate this document into a published work, +# please contact the maintainer, and we will make an effort to ensure that you +# have the most up to date information available. +# +# There is no guarantee that this document lives up to its intended purpose. +# This is simply provided as a free resource. As such, the authors and +# maintainers of the information provided within can not make any guarantee +# that the information is even accurate. + +"""Display a subunit stream in a gtk progress window.""" + +import sys +import threading +import unittest + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GObject + +from testtools import StreamToExtendedDecorator + +from subunit import ( + PROGRESS_POP, + PROGRESS_PUSH, + PROGRESS_SET, + ByteStreamToStreamResult, + ) +from subunit.progress_model import ProgressModel + + +class GTKTestResult(unittest.TestResult): + + def __init__(self): + super(GTKTestResult, self).__init__() + # Instance variables (in addition to TestResult) + self.window = None + self.run_label = None + self.ok_label = None + self.not_ok_label = None + self.total_tests = None + + self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) + self.window.set_resizable(True) + + self.window.connect("destroy", Gtk.main_quit) + self.window.set_title("Tests...") + self.window.set_border_width(0) + + vbox = Gtk.VBox(False, 5) + vbox.set_border_width(10) + self.window.add(vbox) + vbox.show() + + # Create a centering alignment object + align = Gtk.Alignment.new(0.5, 0.5, 0, 0) + vbox.pack_start(align, False, False, 5) + align.show() + + # Create the ProgressBar + self.pbar = Gtk.ProgressBar() + align.add(self.pbar) + self.pbar.set_text("Running") + self.pbar.show() + self.progress_model = ProgressModel() + + separator = Gtk.HSeparator() + vbox.pack_start(separator, False, False, 0) + separator.show() + + # rows, columns, homogeneous + table = Gtk.Table(2, 3, False) + vbox.pack_start(table, False, True, 0) + table.show() + # Show summary details about the run. Could use an expander. + label = Gtk.Label(label="Run:") + table.attach(label, 0, 1, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.run_label = Gtk.Label(label="N/A") + table.attach(self.run_label, 1, 2, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.run_label.show() + + label = Gtk.Label(label="OK:") + table.attach(label, 0, 1, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.ok_label = Gtk.Label(label="N/A") + table.attach(self.ok_label, 1, 2, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.ok_label.show() + + label = Gtk.Label(label="Not OK:") + table.attach(label, 0, 1, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.not_ok_label = Gtk.Label(label="N/A") + table.attach(self.not_ok_label, 1, 2, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.not_ok_label.show() + + self.window.show() + # For the demo. + self.window.set_keep_above(True) + self.window.present() + + def stopTest(self, test): + super(GTKTestResult, self).stopTest(test) + GObject.idle_add(self._stopTest) + + def _stopTest(self): + self.progress_model.advance() + if self.progress_model.width() == 0: + self.pbar.pulse() + else: + pos = self.progress_model.pos() + width = self.progress_model.width() + percentage = (pos / float(width)) + self.pbar.set_fraction(percentage) + + def stopTestRun(self): + try: + super(GTKTestResult, self).stopTestRun() + except AttributeError: + pass + GObject.idle_add(self.pbar.set_text, 'Finished') + + def addError(self, test, err): + super(GTKTestResult, self).addError(test, err) + GObject.idle_add(self.update_counts) + + def addFailure(self, test, err): + super(GTKTestResult, self).addFailure(test, err) + GObject.idle_add(self.update_counts) + + def addSuccess(self, test): + super(GTKTestResult, self).addSuccess(test) + GObject.idle_add(self.update_counts) + + def addSkip(self, test, reason): + # addSkip is new in Python 2.7/3.1 + addSkip = getattr(super(GTKTestResult, self), 'addSkip', None) + if callable(addSkip): + addSkip(test, reason) + GObject.idle_add(self.update_counts) + + def addExpectedFailure(self, test, err): + # addExpectedFailure is new in Python 2.7/3.1 + addExpectedFailure = getattr(super(GTKTestResult, self), + 'addExpectedFailure', None) + if callable(addExpectedFailure): + addExpectedFailure(test, err) + GObject.idle_add(self.update_counts) + + def addUnexpectedSuccess(self, test): + # addUnexpectedSuccess is new in Python 2.7/3.1 + addUnexpectedSuccess = getattr(super(GTKTestResult, self), + 'addUnexpectedSuccess', None) + if callable(addUnexpectedSuccess): + addUnexpectedSuccess(test) + GObject.idle_add(self.update_counts) + + def progress(self, offset, whence): + if whence == PROGRESS_PUSH: + self.progress_model.push() + elif whence == PROGRESS_POP: + self.progress_model.pop() + elif whence == PROGRESS_SET: + self.total_tests = offset + self.progress_model.set_width(offset) + else: + self.total_tests += offset + self.progress_model.adjust_width(offset) + + def time(self, a_datetime): + # We don't try to estimate completion yet. + pass + + def update_counts(self): + self.run_label.set_text(str(self.testsRun)) + bad = len(self.failures + self.errors) + self.ok_label.set_text(str(self.testsRun - bad)) + self.not_ok_label.set_text(str(bad)) + + +def main(): + GObject.threads_init() + result = StreamToExtendedDecorator(GTKTestResult()) + test = ByteStreamToStreamResult(sys.stdin, non_subunit_name='stdout') + # Get setup + while Gtk.events_pending(): + Gtk.main_iteration() + # Start IO + def run_and_finish(): + test.run(result) + result.stopTestRun() + t = threading.Thread(target=run_and_finish) + t.daemon = True + result.startTestRun() + t.start() + Gtk.main() + if result.decorated.wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2junitxml.py b/python/subunit/filter_scripts/subunit2junitxml.py new file mode 100755 index 0000000..59f3c62 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2junitxml.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Filter a subunit stream to get aggregate statistics.""" + + +import sys + +from testtools import StreamToExtendedDecorator + +from subunit.filters import run_filter_script + +try: + from junitxml import JUnitXmlResult +except ImportError: + sys.stderr.write("python-junitxml (https://launchpad.net/pyjunitxml or " + "http://pypi.python.org/pypi/junitxml) is required for this filter.") + raise + + +def main(): + run_filter_script( + lambda output:StreamToExtendedDecorator( + JUnitXmlResult(output)), __doc__, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2pyunit.py b/python/subunit/filter_scripts/subunit2pyunit.py new file mode 100755 index 0000000..89b5f26 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2pyunit.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Display a subunit stream through python's unittest test runner.""" + +from operator import methodcaller +from optparse import OptionParser +import sys +import unittest + +from testtools import StreamToExtendedDecorator, DecorateTestCaseResult, StreamResultRouter + +from subunit import ByteStreamToStreamResult +from subunit.filters import find_stream +from subunit.test_results import CatFiles + + +def main(): + parser = OptionParser(description=__doc__) + parser.add_option("--no-passthrough", action="store_true", + help="Hide all non subunit input.", default=False, dest="no_passthrough") + parser.add_option("--progress", action="store_true", + help="Use bzrlib's test reporter (requires bzrlib)", + default=False) + (options, args) = parser.parse_args() + test = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name='stdout') + def wrap_result(result): + result = StreamToExtendedDecorator(result) + if not options.no_passthrough: + result = StreamResultRouter(result) + result.add_rule(CatFiles(sys.stdout), 'test_id', test_id=None) + return result + test = DecorateTestCaseResult(test, wrap_result, + before_run=methodcaller('startTestRun'), + after_run=methodcaller('stopTestRun')) + if options.progress: + from bzrlib.tests import TextTestRunner + from bzrlib import ui + ui.ui_factory = ui.make_ui_for_terminal(None, sys.stdout, sys.stderr) + runner = TextTestRunner() + else: + runner = unittest.TextTestRunner(verbosity=2) + if runner.run(test).wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_1to2.py b/python/subunit/filter_scripts/subunit_1to2.py new file mode 100755 index 0000000..9725820 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_1to2.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Convert a version 1 subunit stream to version 2 stream.""" + +from optparse import OptionParser +import sys + +from testtools import ExtendedToStreamDecorator + +from subunit import StreamResultToBytes +from subunit.filters import find_stream, run_tests_from_stream + + +def make_options(description): + parser = OptionParser(description=__doc__) + return parser + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + run_tests_from_stream(find_stream(sys.stdin, args), + ExtendedToStreamDecorator(StreamResultToBytes(sys.stdout))) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_2to1.py b/python/subunit/filter_scripts/subunit_2to1.py new file mode 100755 index 0000000..d358f66 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_2to1.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Convert a version 2 subunit stream to a version 1 stream.""" + +from optparse import OptionParser +import sys + +from testtools import ( + StreamToExtendedDecorator, + StreamResultRouter, + ) + +from subunit import ByteStreamToStreamResult, TestProtocolClient +from subunit.filters import find_stream, run_tests_from_stream +from subunit.test_results import CatFiles + + +def make_options(description): + parser = OptionParser(description=__doc__) + return parser + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + case = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name='stdout') + result = StreamToExtendedDecorator(TestProtocolClient(sys.stdout)) + result = StreamResultRouter(result) + cat = CatFiles(sys.stdout) + result.add_rule(cat, 'test_id', test_id=None) + result.startTestRun() + case.run(result) + result.stopTestRun() + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_filter.py b/python/subunit/filter_scripts/subunit_filter.py new file mode 100755 index 0000000..7314531 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_filter.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 200-2013 Robert Collins +# (C) 2009 Martin Pool +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Filter a subunit stream to include/exclude tests. + +The default is to strip successful tests. + +Tests can be filtered by Python regular expressions with --with and --without, +which match both the test name and the error text (if any). The result +contains tests which match any of the --with expressions and none of the +--without expressions. For case-insensitive matching prepend '(?i)'. +Remember to quote shell metacharacters. +""" + +from optparse import OptionParser +import sys +import re + +from testtools import ExtendedToStreamDecorator, StreamToExtendedDecorator + +from subunit import ( + DiscardStream, + ProtocolTestCase, + StreamResultToBytes, + read_test_list, + ) +from subunit.filters import filter_by_result, find_stream +from subunit.test_results import ( + and_predicates, + make_tag_filter, + TestResultFilter, + ) + + +def make_options(description): + parser = OptionParser(description=__doc__) + parser.add_option("--error", action="store_false", + help="include errors", default=False, dest="error") + parser.add_option("-e", "--no-error", action="store_true", + help="exclude errors", dest="error") + parser.add_option("--failure", action="store_false", + help="include failures", default=False, dest="failure") + parser.add_option("-f", "--no-failure", action="store_true", + help="exclude failures", dest="failure") + parser.add_option("--passthrough", action="store_false", + help="Forward non-subunit input as 'stdout'.", default=False, + dest="no_passthrough") + parser.add_option("--no-passthrough", action="store_true", + help="Discard all non subunit input.", default=False, + dest="no_passthrough") + parser.add_option("-s", "--success", action="store_false", + help="include successes", dest="success") + parser.add_option("--no-success", action="store_true", + help="exclude successes", default=True, dest="success") + parser.add_option("--no-skip", action="store_true", + help="exclude skips", dest="skip") + parser.add_option("--xfail", action="store_false", + help="include expected failures", default=True, dest="xfail") + parser.add_option("--no-xfail", action="store_true", + help="exclude expected failures", default=True, dest="xfail") + parser.add_option( + "--with-tag", type=str, + help="include tests with these tags", action="append", dest="with_tags") + parser.add_option( + "--without-tag", type=str, + help="exclude tests with these tags", action="append", dest="without_tags") + parser.add_option("-m", "--with", type=str, + help="regexp to include (case-sensitive by default)", + action="append", dest="with_regexps") + parser.add_option("--fixup-expected-failures", type=str, + help="File with list of test ids that are expected to fail; on failure " + "their result will be changed to xfail; on success they will be " + "changed to error.", dest="fixup_expected_failures", action="append") + parser.add_option("--without", type=str, + help="regexp to exclude (case-sensitive by default)", + action="append", dest="without_regexps") + parser.add_option("-F", "--only-genuine-failures", action="callback", + callback=only_genuine_failures_callback, + help="Only pass through failures and exceptions.") + parser.add_option("--rename", action="append", nargs=2, + help="Apply specified regex subsitutions to test names.", + dest="renames", default=[]) + return parser + + +def only_genuine_failures_callback(option, opt, value, parser): + parser.rargs.insert(0, '--no-passthrough') + parser.rargs.insert(0, '--no-xfail') + parser.rargs.insert(0, '--no-skip') + parser.rargs.insert(0, '--no-success') + + +def _compile_re_from_list(l): + return re.compile("|".join(l), re.MULTILINE) + + +def _make_regexp_filter(with_regexps, without_regexps): + """Make a callback that checks tests against regexps. + + with_regexps and without_regexps are each either a list of regexp strings, + or None. + """ + with_re = with_regexps and _compile_re_from_list(with_regexps) + without_re = without_regexps and _compile_re_from_list(without_regexps) + + def check_regexps(test, outcome, err, details, tags): + """Check if this test and error match the regexp filters.""" + test_str = str(test) + outcome + str(err) + str(details) + if with_re and not with_re.search(test_str): + return False + if without_re and without_re.search(test_str): + return False + return True + return check_regexps + + +def _compile_rename(patterns): + def rename(name): + for (from_pattern, to_pattern) in patterns: + name = re.sub(from_pattern, to_pattern, name) + return name + return rename + + +def _make_result(output, options, predicate): + """Make the result that we'll send the test outcomes to.""" + fixup_expected_failures = set() + for path in options.fixup_expected_failures or (): + fixup_expected_failures.update(read_test_list(path)) + return StreamToExtendedDecorator(TestResultFilter( + ExtendedToStreamDecorator( + StreamResultToBytes(output)), + filter_error=options.error, + filter_failure=options.failure, + filter_success=options.success, + filter_skip=options.skip, + filter_xfail=options.xfail, + filter_predicate=predicate, + fixup_expected_failures=fixup_expected_failures, + rename=_compile_rename(options.renames))) + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + + regexp_filter = _make_regexp_filter( + options.with_regexps, options.without_regexps) + tag_filter = make_tag_filter(options.with_tags, options.without_tags) + filter_predicate = and_predicates([regexp_filter, tag_filter]) + + filter_by_result( + lambda output_to: _make_result(sys.stdout, options, filter_predicate), + output_path=None, + passthrough=(not options.no_passthrough), + forward=False, + protocol_version=2, + input_stream=find_stream(sys.stdin, args)) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_ls.py b/python/subunit/filter_scripts/subunit_ls.py new file mode 100755 index 0000000..ef4c225 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_ls.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2008 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""List tests in a subunit stream.""" + +from optparse import OptionParser +import sys + +from testtools import ( + CopyStreamResult, StreamToExtendedDecorator, StreamResultRouter, + StreamSummary) + +from subunit import ByteStreamToStreamResult +from subunit.filters import find_stream, run_tests_from_stream +from subunit.test_results import ( + CatFiles, + TestIdPrintingResult, + ) + + +def main(): + parser = OptionParser(description=__doc__) + parser.add_option("--times", action="store_true", + help="list the time each test took (requires a timestamped stream)", + default=False) + parser.add_option("--exists", action="store_true", + help="list tests that are reported as existing (as well as ran)", + default=False) + parser.add_option("--no-passthrough", action="store_true", + help="Hide all non subunit input.", default=False, dest="no_passthrough") + (options, args) = parser.parse_args() + test = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name="stdout") + result = TestIdPrintingResult(sys.stdout, options.times, options.exists) + if not options.no_passthrough: + result = StreamResultRouter(result) + cat = CatFiles(sys.stdout) + result.add_rule(cat, 'test_id', test_id=None) + summary = StreamSummary() + result = CopyStreamResult([result, summary]) + result.startTestRun() + test.run(result) + result.stopTestRun() + if summary.wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + +if __name__ = '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_notify.py b/python/subunit/filter_scripts/subunit_notify.py new file mode 100755 index 0000000..af04327 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_notify.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2010 Jelmer Vernooij +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Notify the user of a finished test run.""" + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Notify +from testtools import StreamToExtendedDecorator + +from subunit import TestResultStats +from subunit.filters import run_filter_script + +if not Notify.init("Subunit-notify"): + sys.exit(1) + + +def notify_of_result(result): + result = result.decorated + if result.failed_tests > 0: + summary = "Test run failed" + else: + summary = "Test run successful" + body = "Total tests: %d; Passed: %d; Failed: %d" % ( + result.total_tests, + result.passed_tests, + result.failed_tests, + ) + nw = Notify.Notification(summary, body) + nw.show() + + +def main(): + run_filter_script( + lambda output:StreamToExtendedDecorator(TestResultStats(output)), + __doc__, notify_of_result, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_output.py b/python/subunit/filter_scripts/subunit_output.py new file mode 100755 index 0000000..9447ad1 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_output.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Subunit Contributors +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + + +"""A command-line tool to generate a subunit result byte-stream.""" + +import sys + +from subunit._output import output_main + +def main(): + sys.exit(output_main() + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_stats.py b/python/subunit/filter_scripts/subunit_stats.py new file mode 100755 index 0000000..a152250 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_stats.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""Filter a subunit stream to get aggregate statistics.""" + +import sys + +from testtools import StreamToExtendedDecorator + +from subunit import TestResultStats +from subunit.filters import run_filter_script + + +def main(): + result = TestResultStats(sys.stdout) + + def show_stats(r): + r.decorated.formatStats() + + run_filter_script( + lambda output:StreamToExtendedDecorator(result), + __doc__, show_stats, protocol_version=2, passthrough_subunit=False) + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_tags.py b/python/subunit/filter_scripts/subunit_tags.py new file mode 100755 index 0000000..e2b40d6 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_tags.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""A filter to change tags on a subunit stream. + +subunit-tags foo -> adds foo +subunit-tags foo -bar -> adds foo and removes bar +""" + +import sys + +from subunit import tag_stream + + +def main(): + sys.exit(tag_stream(sys.stdin, sys.stdout, sys.argv[1:])) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/tap2subunit.py b/python/subunit/filter_scripts/tap2subunit.py new file mode 100755 index 0000000..4263335 --- /dev/null +++ b/python/subunit/filter_scripts/tap2subunit.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + +"""A filter that reads a TAP stream and outputs a subunit stream. + +More information on TAP is available at +http://testanything.org/wiki/index.php/Main_Page. +""" + +import sys + +from subunit import TAP2SubUnit + + +def main(): + sys.exit(TAP2SubUnit(sys.stdin, sys.stdout)) + + +if __name__ == '__main__': + main() -- cgit v1.2.1