From 16c3c9034d029e352dd050778cf8d52ee8ac4d34 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 31 Jan 2012 19:49:23 +0000 Subject: Flakes --- python/subunit/tests/test_test_results.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index fe82c04..43155d5 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -16,12 +16,6 @@ import datetime import unittest -from StringIO import StringIO -import os -import sys - -from testtools.content_type import ContentType -from testtools.content import Content import subunit import subunit.iso8601 as iso8601 -- cgit v1.2.1 From a2d283cb7eeda22fb7bbcb2e1ff5c6a3e2819560 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 31 Jan 2012 19:49:33 +0000 Subject: Add a CSV filter. --- python/subunit/test_results.py | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'python') diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index 1c91daa..4d6a77d 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -16,10 +16,15 @@ """TestResult helper classes used to by subunit.""" +import csv import datetime import iso8601 import testtools +from testtools.content import ( + text_content, + TracebackContent, + ) # NOT a TestResult, because we are implementing the interface, not inheriting @@ -380,3 +385,97 @@ class TestIdPrintingResult(testtools.TestResult): def wasSuccessful(self): "Tells whether or not this result was a success" return self.failed_tests == 0 + + +class TestByTestResult(testtools.TestResult): + """Call something every time a test completes.""" + + # XXX: No tests. Naughty, naughty. + + # XXX: Arguably belongs in testtools. + + def __init__(self, on_test): + """Construct a ``TestByTestResult``. + + :param on_test: A callable that take a test case, a status (one of + "success", "failure", "error", "skip", or "xfail"), a start time + (a ``datetime`` with timezone), a stop time, an iterable of tags, + and a details dict. Is called at the end of each test (i.e. on + ``stopTest``) with the accumulated values for that test. + """ + super(TestByTestResult, self).__init__() + self._on_test = on_test + + def startTest(self, test): + super(TestByTestResult, self).startTest(test) + self._current_test = test + self._status = None + self._details = None + self._start_time = self._now() + self._stop_time = None + + def stopTest(self, test): + self._stop_time = self._now() + super(TestByTestResult, self).stopTest(test) + self._on_test( + test=test, + status=self._status, + start_time=self._start_time, + stop_time=self._stop_time, + # XXX: This is unset when I run it. Is current_tags a new part of + # the testtools API? + tags=getattr(self, 'current_tags', None), + details=self._details) + + def _err_to_details(self, test, err, details): + if details: + return details + return {'traceback': TracebackContent(err, test)} + + def addSuccess(self, test, details=None): + super(TestByTestResult, self).addSuccess(test) + self._status = 'success' + self._details = details + + def addFailure(self, test, err=None, details=None): + super(TestByTestResult, self).addFailure(test, err, details) + self._status = 'failure' + self._details = self._err_to_details(test, err, details) + + def addError(self, test, err=None, details=None): + super(TestByTestResult, self).addError(test, err, details) + self._status = 'error' + self._details = self._err_to_details(test, err, details) + + def addSkip(self, test, reason=None, details=None): + super(TestByTestResult, self).addSkip(test, reason, details) + self._status = 'skip' + if details is None: + details = {'reason': text_content(reason)} + elif reason: + # XXX: What if details already has 'reason' key? + details['reason'] = text_content(reason) + self._details = details + + def addExpectedFailure(self, test, err=None, details=None): + super(TestByTestResult, self).addExpectedFailure(test, err, details) + self._status = 'xfail' + self._details = self._err_to_details(test, err, details) + + def addUnexpectedSuccess(self, test, details=None): + super(TestByTestResult, self).addUnexpectedSuccess(test, details) + self._status = 'success' + self._details = details + + +def csv_result(stream): + writer = csv.writer(stream) + w = writer.writerow + # XXX: Not great that we write this out immediately. Probably better to + # wait for startTestRun. + w(['test', 'status', 'start_time', 'stop_time']) + def on_test(test, status, start_time, stop_time, tags, details): + # XXX: Don't really know how to serialize tags or details into csv in + # a useful way. + w([test.id(), status, start_time, stop_time]) + return TestByTestResult(on_test) -- cgit v1.2.1 From 649f8be2db11b20dece2d16613f46a0fc7b76034 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Wed, 1 Feb 2012 18:35:06 +0000 Subject: Flakes --- python/subunit/tests/test_test_protocol.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index e1287b6..c5a064e 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -18,7 +18,6 @@ import datetime import unittest from StringIO import StringIO import os -import sys from testtools.content import Content, TracebackContent from testtools.content_type import ContentType @@ -61,7 +60,6 @@ class TestProtocolServerForward(unittest.TestCase): pipe = StringIO("test old mcdonald\n" "success old mcdonald\n") protocol.readFrom(pipe) - mcdonald = subunit.RemotedTestCase("old mcdonald") self.assertEqual(client.testsRun, 1) self.assertEqual(pipe.getvalue(), out.getvalue()) @@ -74,7 +72,7 @@ class TestProtocolServerForward(unittest.TestCase): protocol.readFrom(pipe) self.assertEqual(client.testsRun, 0) self.assertEqual("", out.getvalue()) - + class TestTestProtocolServerPipe(unittest.TestCase): @@ -90,7 +88,6 @@ class TestTestProtocolServerPipe(unittest.TestCase): "test an error\n" "error an error\n") protocol.readFrom(pipe) - mcdonald = subunit.RemotedTestCase("old mcdonald") bing = subunit.RemotedTestCase("bing crosby") an_error = subunit.RemotedTestCase("an error") self.assertEqual(client.errors, @@ -680,12 +677,6 @@ class TestTestProtocolServerAddSuccess(unittest.TestCase): ('stopTest', self.test), ], self.client._events) - def test_simple_success(self): - self.simple_success_keyword("failure") - - def test_simple_success_colon(self): - self.simple_success_keyword("failure:") - def test_simple_success(self): self.simple_success_keyword("successful") @@ -946,7 +937,7 @@ class TestIsolatedTestCase(unittest.TestCase): def test_construct(self): - test = self.SampleIsolatedTestCase("test_sets_global_state") + self.SampleIsolatedTestCase("test_sets_global_state") def test_run(self): result = unittest.TestResult() @@ -982,7 +973,7 @@ class TestIsolatedTestSuite(unittest.TestCase): def test_construct(self): - suite = subunit.IsolatedTestSuite() + subunit.IsolatedTestSuite() def test_run(self): result = unittest.TestResult() -- cgit v1.2.1 From 6033d5b90991de13604f7de3ed6e42581b01d2c2 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Wed, 1 Feb 2012 18:38:26 +0000 Subject: Deal with testtools moving doubles out of helpers. --- python/subunit/tests/test_test_protocol.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index c5a064e..6297ea9 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -21,11 +21,16 @@ import os from testtools.content import Content, TracebackContent from testtools.content_type import ContentType -from testtools.tests.helpers import ( - Python26TestResult, - Python27TestResult, - ExtendedTestResult, - ) +from testtools import try_imports +Python26TestResult = try_imports( + ['testtools.testresult.doubles.Python26TestResult', + 'testtools.tests.helpers.Python26TestResult']) +Python27TestResult = try_imports( + ['testtools.testresult.doubles.Python27TestResult', + 'testtools.tests.helpers.Python27TestResult']) +ExtendedTestResult = try_imports( + ['testtools.testresult.doubles.ExtendedTestResult', + 'testtools.tests.helpers.ExtendedTestResult']) import subunit from subunit import _remote_exception_str -- cgit v1.2.1 From 73758e32e11f41e2d715d7f34db224827aa23e41 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Wed, 1 Feb 2012 19:20:05 +0000 Subject: Swathe of tests. --- python/subunit/test_results.py | 7 +- python/subunit/tests/test_test_results.py | 226 ++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 4 deletions(-) (limited to 'python') diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index a4ff372..c8b0bfe 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -503,8 +503,6 @@ class TestIdPrintingResult(testtools.TestResult): class TestByTestResult(testtools.TestResult): """Call something every time a test completes.""" - # XXX: No tests. Naughty, naughty. - # XXX: Arguably belongs in testtools. def __init__(self, on_test): @@ -521,10 +519,11 @@ class TestByTestResult(testtools.TestResult): def startTest(self, test): super(TestByTestResult, self).startTest(test) - self._current_test = test + self._start_time = self._now() + # There's no supported (i.e. tested) behaviour that relies on these + # being set, but it makes me more comfortable all the same. -- jml self._status = None self._details = None - self._start_time = self._now() self._stop_time = None def stopTest(self, test): diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 94d2274..7d1a869 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -15,15 +15,22 @@ # import datetime +import sys import unittest from testtools import TestCase +from testtools.content import ( + text_content, + TracebackContent, + ) from testtools.testresult.doubles import ExtendedTestResult import subunit import subunit.iso8601 as iso8601 import subunit.test_results +import testtools + class LoggingDecorator(subunit.test_results.HookedTestResultDecorator): @@ -294,6 +301,225 @@ class TestTimeCollapsingDecorator(TestCase): ('stopTest', foo)], result._events) +class TestByTestResultTests(testtools.TestCase): + + def setUp(self): + super(TestByTestResultTests, self).setUp() + self.log = [] + self.result = subunit.test_results.TestByTestResult(self.on_test) + self.result._now = iter(range(5)).next + + def on_test(self, **kwargs): + self.log.append(kwargs) + + def test_no_tests_nothing_reported(self): + self.result.startTestRun() + self.result.stopTestRun() + self.assertEqual([], self.log) + + def test_add_success(self): + self.result.startTest(self) + self.result.addSuccess(self) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'success', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': None}], + self.log) + + def test_add_success_details(self): + self.result.startTest(self) + details = {'foo': 'bar'} + self.result.addSuccess(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'success', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_tags(self): + if not getattr(self.result, 'tags', None): + self.skipTest("No tags in testtools") + self.result.tags(['foo']) + self.result.startTest(self) + details = {'foo': 'bar'} + self.result.addSuccess(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'success', + 'start_time': 0, + 'stop_time': 1, + 'tags': set('foo'), + 'details': details}], + self.log) + + def test_add_error(self): + self.result.startTest(self) + try: + 1/0 + except ZeroDivisionError: + error = sys.exc_info() + self.result.addError(self, error) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'error', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': {'traceback': TracebackContent(error, self)}}], + self.log) + + def test_add_error_details(self): + self.result.startTest(self) + details = {"foo": text_content("bar")} + self.result.addError(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'error', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_add_failure(self): + self.result.startTest(self) + try: + self.fail("intentional failure") + except self.failureException: + failure = sys.exc_info() + self.result.addFailure(self, failure) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'failure', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': {'traceback': TracebackContent(failure, self)}}], + self.log) + + def test_add_failure_details(self): + self.result.startTest(self) + details = {"foo": text_content("bar")} + self.result.addFailure(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'failure', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_add_xfail(self): + self.result.startTest(self) + try: + 1/0 + except ZeroDivisionError: + error = sys.exc_info() + self.result.addExpectedFailure(self, error) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'xfail', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': {'traceback': TracebackContent(error, self)}}], + self.log) + + def test_add_xfail_details(self): + self.result.startTest(self) + details = {"foo": text_content("bar")} + self.result.addExpectedFailure(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'xfail', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_add_unexpected_success(self): + self.result.startTest(self) + details = {'foo': 'bar'} + self.result.addUnexpectedSuccess(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'success', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_add_skip_reason(self): + self.result.startTest(self) + reason = self.getUniqueString() + self.result.addSkip(self, reason) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'skip', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': {'reason': text_content(reason)}}], + self.log) + + def test_add_skip_details(self): + self.result.startTest(self) + details = {'foo': 'bar'} + self.result.addSkip(self, details=details) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'skip', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': details}], + self.log) + + def test_twice(self): + self.result.startTest(self) + self.result.addSuccess(self, details={'foo': 'bar'}) + self.result.stopTest(self) + self.result.startTest(self) + self.result.addSuccess(self) + self.result.stopTest(self) + self.assertEqual( + [{'test': self, + 'status': 'success', + 'start_time': 0, + 'stop_time': 1, + 'tags': None, + 'details': {'foo': 'bar'}}, + {'test': self, + 'status': 'success', + 'start_time': 2, + 'stop_time': 3, + 'tags': None, + 'details': None}, + ], + self.log) + + def test_suite(): loader = subunit.tests.TestUtil.TestLoader() result = loader.loadTestsFromName(__name__) -- cgit v1.2.1 From 2a8e024f9f84fe20b85210b3bc35131c998283c9 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Thu, 2 Feb 2012 10:58:39 +0000 Subject: Factor out the assertions. --- python/subunit/tests/test_test_results.py | 129 +++++++----------------------- 1 file changed, 31 insertions(+), 98 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 7d1a869..d90dcba 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -309,6 +309,17 @@ class TestByTestResultTests(testtools.TestCase): self.result = subunit.test_results.TestByTestResult(self.on_test) self.result._now = iter(range(5)).next + def assertCalled(self, **kwargs): + defaults = { + 'test': self, + 'tags': None, + 'details': None, + 'start_time': 0, + 'stop_time': 1, + } + defaults.update(kwargs) + self.assertEqual([defaults], self.log) + def on_test(self, **kwargs): self.log.append(kwargs) @@ -321,45 +332,23 @@ class TestByTestResultTests(testtools.TestCase): self.result.startTest(self) self.result.addSuccess(self) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'success', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': None}], - self.log) + self.assertCalled(status='success') def test_add_success_details(self): self.result.startTest(self) details = {'foo': 'bar'} self.result.addSuccess(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'success', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='success', details=details) def test_tags(self): if not getattr(self.result, 'tags', None): self.skipTest("No tags in testtools") self.result.tags(['foo']) self.result.startTest(self) - details = {'foo': 'bar'} - self.result.addSuccess(self, details=details) + self.result.addSuccess(self) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'success', - 'start_time': 0, - 'stop_time': 1, - 'tags': set('foo'), - 'details': details}], - self.log) + self.assertCalled(status='success', tags=set('foo')) def test_add_error(self): self.result.startTest(self) @@ -369,28 +358,16 @@ class TestByTestResultTests(testtools.TestCase): error = sys.exc_info() self.result.addError(self, error) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'error', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': {'traceback': TracebackContent(error, self)}}], - self.log) + self.assertCalled( + status='error', + details={'traceback': TracebackContent(error, self)}) def test_add_error_details(self): self.result.startTest(self) details = {"foo": text_content("bar")} self.result.addError(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'error', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='error', details=details) def test_add_failure(self): self.result.startTest(self) @@ -400,28 +377,16 @@ class TestByTestResultTests(testtools.TestCase): failure = sys.exc_info() self.result.addFailure(self, failure) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'failure', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': {'traceback': TracebackContent(failure, self)}}], - self.log) + self.assertCalled( + status='failure', + details={'traceback': TracebackContent(failure, self)}) def test_add_failure_details(self): self.result.startTest(self) details = {"foo": text_content("bar")} self.result.addFailure(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'failure', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='failure', details=details) def test_add_xfail(self): self.result.startTest(self) @@ -431,70 +396,38 @@ class TestByTestResultTests(testtools.TestCase): error = sys.exc_info() self.result.addExpectedFailure(self, error) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'xfail', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': {'traceback': TracebackContent(error, self)}}], - self.log) + self.assertCalled( + status='xfail', + details={'traceback': TracebackContent(error, self)}) def test_add_xfail_details(self): self.result.startTest(self) details = {"foo": text_content("bar")} self.result.addExpectedFailure(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'xfail', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='xfail', details=details) def test_add_unexpected_success(self): self.result.startTest(self) details = {'foo': 'bar'} self.result.addUnexpectedSuccess(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'success', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='success', details=details) def test_add_skip_reason(self): self.result.startTest(self) reason = self.getUniqueString() self.result.addSkip(self, reason) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'skip', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': {'reason': text_content(reason)}}], - self.log) + self.assertCalled( + status='skip', details={'reason': text_content(reason)}) def test_add_skip_details(self): self.result.startTest(self) details = {'foo': 'bar'} self.result.addSkip(self, details=details) self.result.stopTest(self) - self.assertEqual( - [{'test': self, - 'status': 'skip', - 'start_time': 0, - 'stop_time': 1, - 'tags': None, - 'details': details}], - self.log) + self.assertCalled(status='skip', details=details) def test_twice(self): self.result.startTest(self) -- cgit v1.2.1 From 41cbeb7fc733a4aa893a1bd8ed1093f8449f1c3a Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Fri, 3 Feb 2012 09:19:07 +0000 Subject: Todos --- python/subunit/tests/test_test_results.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index d90dcba..dbadc7c 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -452,6 +452,10 @@ class TestByTestResultTests(testtools.TestCase): ], self.log) +# XXX: Tests for csv_result + +# XXX: Tests for subunit2csv + def test_suite(): loader = subunit.tests.TestUtil.TestLoader() -- cgit v1.2.1 From 6094e522b9b18c247991f02ba4ca2ce8a498d51f Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:38:18 +0100 Subject: Update to behave correctly with tags. --- python/subunit/tests/test_test_results.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index dbadc7c..36ef15d 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -312,7 +312,7 @@ class TestByTestResultTests(testtools.TestCase): def assertCalled(self, **kwargs): defaults = { 'test': self, - 'tags': None, + 'tags': set(), 'details': None, 'start_time': 0, 'stop_time': 1, @@ -344,11 +344,11 @@ class TestByTestResultTests(testtools.TestCase): def test_tags(self): if not getattr(self.result, 'tags', None): self.skipTest("No tags in testtools") - self.result.tags(['foo']) + self.result.tags(['foo'], []) self.result.startTest(self) self.result.addSuccess(self) self.result.stopTest(self) - self.assertCalled(status='success', tags=set('foo')) + self.assertCalled(status='success', tags=set(['foo'])) def test_add_error(self): self.result.startTest(self) @@ -441,13 +441,13 @@ class TestByTestResultTests(testtools.TestCase): 'status': 'success', 'start_time': 0, 'stop_time': 1, - 'tags': None, + 'tags': set(), 'details': {'foo': 'bar'}}, {'test': self, 'status': 'success', 'start_time': 2, 'stop_time': 3, - 'tags': None, + 'tags': set(), 'details': None}, ], self.log) -- cgit v1.2.1 From 8d917cbb485352c5834c1716787538888223aafc Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:42:36 +0100 Subject: Resolve XXX about testtools support for tags. --- python/subunit/test_results.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'python') diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index c8b0bfe..f64126d 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -534,8 +534,7 @@ class TestByTestResult(testtools.TestResult): status=self._status, start_time=self._start_time, stop_time=self._stop_time, - # XXX: This is unset when I run it. Is current_tags a new part of - # the testtools API? + # current_tags is new in testtools 0.9.13. tags=getattr(self, 'current_tags', None), details=self._details) -- cgit v1.2.1 From 6b8fb41b69b58bdbe639e324e45803ecdb169726 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:48:46 +0100 Subject: Test for csv output. --- python/subunit/tests/test_test_results.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 36ef15d..f3f3480 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -14,11 +14,13 @@ # limitations under that license. # +import csv import datetime import sys import unittest from testtools import TestCase +from testtools.compat import StringIO from testtools.content import ( text_content, TracebackContent, @@ -452,7 +454,26 @@ class TestByTestResultTests(testtools.TestCase): ], self.log) -# XXX: Tests for csv_result + +class TestCsvResult(testtools.TestCase): + + def test_csv_output(self): + stream = StringIO() + result = subunit.test_results.csv_result(stream) + result._now = iter(range(5)).next + result.startTestRun() + result.startTest(self) + result.addSuccess(self) + result.stopTest(self) + result.stopTestRun() + stream.seek(0) + reader = csv.reader(stream) + output = list(reader) + self.assertEqual( + [['test', 'status', 'start_time', 'stop_time'], + [self.id(), 'success', '0', '1'], + ], + output) # XXX: Tests for subunit2csv -- cgit v1.2.1 From 99e1373c7e70080b9a7d55ac66c634d9ca372ffe Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:50:47 +0100 Subject: Don't bother testing the script because no one has bothered for any of the other scripts --- python/subunit/tests/test_test_results.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index f3f3480..8ffdd42 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -475,8 +475,6 @@ class TestCsvResult(testtools.TestCase): ], output) -# XXX: Tests for subunit2csv - def test_suite(): loader = subunit.tests.TestUtil.TestLoader() -- cgit v1.2.1 From d569ecc69d7f4c78467ebc55f13b5e99b8d8f51b Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:54:00 +0100 Subject: Tighter testing. --- python/subunit/tests/test_test_results.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 8ffdd42..1a95e9e 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -457,6 +457,11 @@ class TestByTestResultTests(testtools.TestCase): class TestCsvResult(testtools.TestCase): + def parse_stream(self, stream): + stream.seek(0) + reader = csv.reader(stream) + return list(reader) + def test_csv_output(self): stream = StringIO() result = subunit.test_results.csv_result(stream) @@ -466,14 +471,20 @@ class TestCsvResult(testtools.TestCase): result.addSuccess(self) result.stopTest(self) result.stopTestRun() - stream.seek(0) - reader = csv.reader(stream) - output = list(reader) self.assertEqual( [['test', 'status', 'start_time', 'stop_time'], [self.id(), 'success', '0', '1'], ], - output) + self.parse_stream(stream)) + + def test_just_header_when_no_tests(self): + stream = StringIO() + result = subunit.test_results.csv_result(stream) + result.startTestRun() + result.stopTestRun() + self.assertEqual( + [['test', 'status', 'start_time', 'stop_time']], + self.parse_stream(stream)) def test_suite(): -- cgit v1.2.1 From cb4407b480a8e28d05d4b2a2eb720f5064997874 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:57:45 +0100 Subject: Don't write anything until startTestRun is called. --- python/subunit/test_results.py | 23 ++++++++++++----------- python/subunit/tests/test_test_results.py | 5 +++++ 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'python') diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index f64126d..73adfab 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -579,14 +579,15 @@ class TestByTestResult(testtools.TestResult): self._details = details -def csv_result(stream): - writer = csv.writer(stream) - w = writer.writerow - # XXX: Not great that we write this out immediately. Probably better to - # wait for startTestRun. - w(['test', 'status', 'start_time', 'stop_time']) - def on_test(test, status, start_time, stop_time, tags, details): - # XXX: Don't really know how to serialize tags or details into csv in - # a useful way. - w([test.id(), status, start_time, stop_time]) - return TestByTestResult(on_test) +class csv_result(TestByTestResult): + + def __init__(self, stream): + super(csv_result, self).__init__(self._on_test) + self._write_row = csv.writer(stream).writerow + + def _on_test(self, test, status, start_time, stop_time, tags, details): + self._write_row([test.id(), status, start_time, stop_time]) + + def startTestRun(self): + super(csv_result, self).startTestRun() + self._write_row(['test', 'status', 'start_time', 'stop_time']) diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 1a95e9e..0e8d81e 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -486,6 +486,11 @@ class TestCsvResult(testtools.TestCase): [['test', 'status', 'start_time', 'stop_time']], self.parse_stream(stream)) + def test_no_output_before_events(self): + stream = StringIO() + subunit.test_results.csv_result(stream) + self.assertEqual([], self.parse_stream(stream)) + def test_suite(): loader = subunit.tests.TestUtil.TestLoader() -- cgit v1.2.1 From 15af286c07c358c12676d07ce167aa210731d7c1 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 25 Mar 2012 15:58:44 +0100 Subject: Rename csv_result to CsvResult. --- python/subunit/test_results.py | 6 +++--- python/subunit/tests/test_test_results.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'python') diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index 73adfab..fb7affd 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -579,15 +579,15 @@ class TestByTestResult(testtools.TestResult): self._details = details -class csv_result(TestByTestResult): +class CsvResult(TestByTestResult): def __init__(self, stream): - super(csv_result, self).__init__(self._on_test) + super(CsvResult, self).__init__(self._on_test) self._write_row = csv.writer(stream).writerow def _on_test(self, test, status, start_time, stop_time, tags, details): self._write_row([test.id(), status, start_time, stop_time]) def startTestRun(self): - super(csv_result, self).startTestRun() + super(CsvResult, self).startTestRun() self._write_row(['test', 'status', 'start_time', 'stop_time']) diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py index 0e8d81e..6beb57a 100644 --- a/python/subunit/tests/test_test_results.py +++ b/python/subunit/tests/test_test_results.py @@ -464,7 +464,7 @@ class TestCsvResult(testtools.TestCase): def test_csv_output(self): stream = StringIO() - result = subunit.test_results.csv_result(stream) + result = subunit.test_results.CsvResult(stream) result._now = iter(range(5)).next result.startTestRun() result.startTest(self) @@ -479,7 +479,7 @@ class TestCsvResult(testtools.TestCase): def test_just_header_when_no_tests(self): stream = StringIO() - result = subunit.test_results.csv_result(stream) + result = subunit.test_results.CsvResult(stream) result.startTestRun() result.stopTestRun() self.assertEqual( @@ -488,7 +488,7 @@ class TestCsvResult(testtools.TestCase): def test_no_output_before_events(self): stream = StringIO() - subunit.test_results.csv_result(stream) + subunit.test_results.CsvResult(stream) self.assertEqual([], self.parse_stream(stream)) -- cgit v1.2.1 From 62e78eeac0762123c478586237cb1448a170e51e Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:19:19 +0100 Subject: Try to factor out the filter code. --- python/subunit/filters.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 python/subunit/filters.py (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py new file mode 100644 index 0000000..9880508 --- /dev/null +++ b/python/subunit/filters.py @@ -0,0 +1,83 @@ +# 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. +# + + +from optparse import OptionParser +import sys + +from subunit import DiscardStream, ProtocolTestCase +from subunit.test_results import CsvResult + + +def make_options(): + 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( + "-o", "--output-to", + help="Output the XML to this path rather than stdout.") + parser.add_option( + "-f", "--forward", action="store_true", default=False, + help="Forward subunit stream on stdout.") + return parser + + +def get_output_stream(output_to): + if output_to is None: + return sys.stdout + else: + return file(output_to, 'wb') + + +def filter_with_result(result, no_passthrough, forward): + if no_passthrough: + passthrough_stream = DiscardStream() + else: + passthrough_stream = None + if forward: + forward_stream = sys.stdout + else: + forward_stream = None + + test = ProtocolTestCase( + sys.stdin, passthrough=passthrough_stream, + forward=forward_stream) + result.startTestRun() + test.run(result) + result.stopTestRun() + + return result.wasSuccessful() + + +def something(result_factory, output_path, no_passthrough, forward): + output_to = get_output_stream(output_path) + result = result_factory(output_to) + try: + successful = filter_with_result(result, no_passthrough, forward) + finally: + if output_path: + output_to.close() + if successful: + return 0 + else: + return 1 + + +def main(): + parser = make_options() + (options, args) = parser.parse_args() + sys.exit( + something(CsvResult, options.output_to, options.no_passthrough, options.forward)) -- cgit v1.2.1 From b6573405687b85e3132e195e9748555975b1f599 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:24:48 +0100 Subject: More tweaking of boundaries. --- python/subunit/filters.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index 9880508..334a95b 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -42,35 +42,38 @@ def get_output_stream(output_to): return file(output_to, 'wb') -def filter_with_result(result, no_passthrough, forward): +def filter_with_result(result_factory, input_stream, output_stream, + passthrough_stream, forward_stream): + result = result_factory(output_stream) + test = ProtocolTestCase( + input_stream, passthrough=passthrough_stream, + forward=forward_stream) + result.startTestRun() + test.run(result) + result.stopTestRun() + return result + + +def something(result_factory, output_path, no_passthrough, forward): if no_passthrough: passthrough_stream = DiscardStream() else: passthrough_stream = None + if forward: forward_stream = sys.stdout else: forward_stream = None - test = ProtocolTestCase( - sys.stdin, passthrough=passthrough_stream, - forward=forward_stream) - result.startTestRun() - test.run(result) - result.stopTestRun() - - return result.wasSuccessful() - - -def something(result_factory, output_path, no_passthrough, forward): output_to = get_output_stream(output_path) - result = result_factory(output_to) try: - successful = filter_with_result(result, no_passthrough, forward) + result = filter_with_result( + result_factory, sys.stdin, output_to, passthrough_stream, + forward_stream) finally: if output_path: output_to.close() - if successful: + if result.wasSuccessful(): return 0 else: return 1 -- cgit v1.2.1 From 60ad2fb938fd2d899258c80b56879e189e3c4d5c Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:32:03 +0100 Subject: More fiddling about. --- python/subunit/filters.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index 334a95b..14486a0 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -35,13 +35,6 @@ def make_options(): return parser -def get_output_stream(output_to): - if output_to is None: - return sys.stdout - else: - return file(output_to, 'wb') - - def filter_with_result(result_factory, input_stream, output_stream, passthrough_stream, forward_stream): result = result_factory(output_stream) @@ -65,7 +58,11 @@ def something(result_factory, output_path, no_passthrough, forward): else: forward_stream = None - output_to = get_output_stream(output_path) + if output_path is None: + output_to = sys.stdout + else: + output_to = file(output_path, 'wb') + try: result = filter_with_result( result_factory, sys.stdin, output_to, passthrough_stream, @@ -79,8 +76,9 @@ def something(result_factory, output_path, no_passthrough, forward): return 1 -def main(): +def main(result_factory): parser = make_options() (options, args) = parser.parse_args() sys.exit( - something(CsvResult, options.output_to, options.no_passthrough, options.forward)) + something(CsvResult, options.output_to, options.no_passthrough, + options.forward)) -- cgit v1.2.1 From 273101fd8d7abf9cd492df4c2c6c5b17c83cce99 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:48:22 +0100 Subject: Docstrings and renaming. --- python/subunit/filters.py | 51 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index 14486a0..ac05af9 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -35,19 +35,48 @@ def make_options(): return parser -def filter_with_result(result_factory, input_stream, output_stream, - passthrough_stream, forward_stream): - result = result_factory(output_stream) +def run_tests_from_stream(input_stream, result, passthrough_stream=None, + forward_stream=None): + """Run tests from a subunit input stream through 'result'. + + :param input_stream: A stream containing subunit input. + :param result: A TestResult that will receive the test events. + :param passthrough_stream: All non-subunit input received will be + sent to this stream. If not provided, uses the ``TestProtocolServer`` + default, which is ``sys.stdout``. + :param forward_stream: All subunit input received will be forwarded + to this stream. If not provided, uses the ``TestProtocolServer`` + default, which is to not forward any input. + :return: True if the test run described by ``input_stream`` was + successful. False otherwise. + """ test = ProtocolTestCase( input_stream, passthrough=passthrough_stream, forward=forward_stream) result.startTestRun() test.run(result) result.stopTestRun() - return result + return result.wasSuccessful() + +def filter_by_result(result_factory, output_path, no_passthrough, forward, + input_stream=sys.stdin): + """Filter an input stream using a test result. -def something(result_factory, output_path, no_passthrough, forward): + :param result_factory: A callable that when passed an output stream + returns a TestResult. It is expected that this result will output + to the given stream. + :param output_path: A path send output to. If None, output will be go + to ``sys.stdout``. + :param no_passthrough: If True, all non-subunit input will be discarded. + If False, that input will be sent to ``sys.stdout``. + :param forward: If True, all subunit input will be forwarded directly to + ``sys.stdout`` as well as to the ``TestResult``. + :param input_stream: The source of subunit input. Defaults to + ``sys.stdin``. + :return: 0 if the input represents a successful test run, 1 if a failed + test run. + """ if no_passthrough: passthrough_stream = DiscardStream() else: @@ -64,13 +93,14 @@ def something(result_factory, output_path, no_passthrough, forward): output_to = file(output_path, 'wb') try: - result = filter_with_result( - result_factory, sys.stdin, output_to, passthrough_stream, + result = result_factory(output_to) + was_successful = run_tests_from_stream( + input_stream, result, output_to, passthrough_stream, forward_stream) finally: if output_path: output_to.close() - if result.wasSuccessful(): + if was_successful: return 0 else: return 1 @@ -80,5 +110,6 @@ def main(result_factory): parser = make_options() (options, args) = parser.parse_args() sys.exit( - something(CsvResult, options.output_to, options.no_passthrough, - options.forward)) + filter_by_result( + CsvResult, options.output_to, options.no_passthrough, + options.forward)) -- cgit v1.2.1 From efa4dc4ef3965c2b9b8d9867e9a80def71e452cd Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:52:50 +0100 Subject: Factor out JUnitXML --- python/subunit/filters.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index ac05af9..0bab9ed 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -21,11 +21,12 @@ from subunit import DiscardStream, ProtocolTestCase from subunit.test_results import CsvResult -def make_options(): - parser = OptionParser(description=__doc__) +def make_options(description): + parser = OptionParser(description=description) parser.add_option( "--no-passthrough", action="store_true", - help="Hide all non subunit input.", default=False, dest="no_passthrough") + help="Hide all non subunit input.", default=False, + dest="no_passthrough") parser.add_option( "-o", "--output-to", help="Output the XML to this path rather than stdout.") @@ -95,8 +96,7 @@ def filter_by_result(result_factory, output_path, no_passthrough, forward, try: result = result_factory(output_to) was_successful = run_tests_from_stream( - input_stream, result, output_to, passthrough_stream, - forward_stream) + input_stream, result, passthrough_stream, forward_stream) finally: if output_path: output_to.close() @@ -106,10 +106,10 @@ def filter_by_result(result_factory, output_path, no_passthrough, forward, return 1 -def main(result_factory): - parser = make_options() +def main(result_factory, description): + parser = make_options(description) (options, args) = parser.parse_args() sys.exit( filter_by_result( - CsvResult, options.output_to, options.no_passthrough, + result_factory, options.output_to, options.no_passthrough, options.forward)) -- cgit v1.2.1 From 2bf7d82ce68dc62bf6d05bbbd0a213dc3393f9b7 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:57:51 +0100 Subject: Rename main() and give it a docstring. --- python/subunit/filters.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index 0bab9ed..f8ce2dd 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -18,7 +18,6 @@ from optparse import OptionParser import sys from subunit import DiscardStream, ProtocolTestCase -from subunit.test_results import CsvResult def make_options(description): @@ -106,7 +105,20 @@ def filter_by_result(result_factory, output_path, no_passthrough, forward, return 1 -def main(result_factory, description): +def run_filter_script(result_factory, description): + """Main function for simple subunit filter scripts. + + Many subunit filter scripts take a stream of subunit input and use a + TestResult to handle the events generated by that stream. This function + wraps a lot of the boiler-plate around that by making a script with + options for handling passthrough information and stream forwarding, and + that will exit with a successful return code (i.e. 0) if the input stream + represents a successful test run. + + :param result_factory: A callable that takes an output stream and returns + a test result that outputs to that stream. + :param description: A description of the filter script. + """ parser = make_options(description) (options, args) = parser.parse_args() sys.exit( -- cgit v1.2.1 From 17b1f61afe903cd0053cea0476b8c60396d944e6 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 11:58:18 +0100 Subject: Not XML --- python/subunit/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index f8ce2dd..f485654 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -28,7 +28,7 @@ def make_options(description): dest="no_passthrough") parser.add_option( "-o", "--output-to", - help="Output the XML to this path rather than stdout.") + help="Send the output to this path rather than stdout.") parser.add_option( "-f", "--forward", action="store_true", default=False, help="Forward subunit stream on stdout.") -- cgit v1.2.1 From 6296d324915cb29ded094c327f84a144d9fa64b7 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 12:01:50 +0100 Subject: Try to reduce double negatives and be more explicit about what happens to the forwarded input. --- python/subunit/filters.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index f485654..9df65df 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -59,7 +59,7 @@ def run_tests_from_stream(input_stream, result, passthrough_stream=None, return result.wasSuccessful() -def filter_by_result(result_factory, output_path, no_passthrough, forward, +def filter_by_result(result_factory, output_path, passthrough, forward, input_stream=sys.stdin): """Filter an input stream using a test result. @@ -68,8 +68,8 @@ def filter_by_result(result_factory, output_path, no_passthrough, forward, to the given stream. :param output_path: A path send output to. If None, output will be go to ``sys.stdout``. - :param no_passthrough: If True, all non-subunit input will be discarded. - If False, that input will be sent to ``sys.stdout``. + :param passthrough: If True, all non-subunit input will be sent to + ``sys.stdout``. If False, that input will be discarded. :param forward: If True, all subunit input will be forwarded directly to ``sys.stdout`` as well as to the ``TestResult``. :param input_stream: The source of subunit input. Defaults to @@ -77,15 +77,15 @@ def filter_by_result(result_factory, output_path, no_passthrough, forward, :return: 0 if the input represents a successful test run, 1 if a failed test run. """ - if no_passthrough: - passthrough_stream = DiscardStream() + if passthrough: + passthrough_stream = sys.stdout else: - passthrough_stream = None + passthrough_stream = DiscardStream() if forward: forward_stream = sys.stdout else: - forward_stream = None + forward_stream = DiscardStream() if output_path is None: output_to = sys.stdout @@ -123,5 +123,5 @@ def run_filter_script(result_factory, description): (options, args) = parser.parse_args() sys.exit( filter_by_result( - result_factory, options.output_to, options.no_passthrough, + result_factory, options.output_to, not options.no_passthrough, options.forward)) -- cgit v1.2.1 From a5932aa9f9dcf9593886835adbe6193f0a8a0224 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 12:13:32 +0100 Subject: Add a post-run hook. --- python/subunit/filters.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index 9df65df..a221bf7 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -47,8 +47,6 @@ def run_tests_from_stream(input_stream, result, passthrough_stream=None, :param forward_stream: All subunit input received will be forwarded to this stream. If not provided, uses the ``TestProtocolServer`` default, which is to not forward any input. - :return: True if the test run described by ``input_stream`` was - successful. False otherwise. """ test = ProtocolTestCase( input_stream, passthrough=passthrough_stream, @@ -56,7 +54,6 @@ def run_tests_from_stream(input_stream, result, passthrough_stream=None, result.startTestRun() test.run(result) result.stopTestRun() - return result.wasSuccessful() def filter_by_result(result_factory, output_path, passthrough, forward, @@ -74,8 +71,7 @@ def filter_by_result(result_factory, output_path, passthrough, forward, ``sys.stdout`` as well as to the ``TestResult``. :param input_stream: The source of subunit input. Defaults to ``sys.stdin``. - :return: 0 if the input represents a successful test run, 1 if a failed - test run. + :return: A test result with the resultts of the run. """ if passthrough: passthrough_stream = sys.stdout @@ -94,18 +90,23 @@ def filter_by_result(result_factory, output_path, passthrough, forward, try: result = result_factory(output_to) - was_successful = run_tests_from_stream( + run_tests_from_stream( input_stream, result, passthrough_stream, forward_stream) finally: if output_path: output_to.close() - if was_successful: - return 0 + return result + + +def _default_post_run(result): + if result.wasSuccessful(): + sys.exit(0) else: - return 1 + sys.exit(1) -def run_filter_script(result_factory, description): +def run_filter_script(result_factory, description, + post_run_hook=_default_post_run): """Main function for simple subunit filter scripts. Many subunit filter scripts take a stream of subunit input and use a @@ -121,7 +122,7 @@ def run_filter_script(result_factory, description): """ parser = make_options(description) (options, args) = parser.parse_args() - sys.exit( - filter_by_result( - result_factory, options.output_to, not options.no_passthrough, - options.forward)) + result = filter_by_result( + result_factory, options.output_to, not options.no_passthrough, + options.forward) + post_run_hook(result) -- cgit v1.2.1 From e2cbb8d7bd2fb382ee710a489686fe27ab6cddf2 Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Tue, 27 Mar 2012 12:17:37 +0100 Subject: Factor out subunit-notify --- python/subunit/filters.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'python') diff --git a/python/subunit/filters.py b/python/subunit/filters.py index a221bf7..dc3fd8a 100644 --- a/python/subunit/filters.py +++ b/python/subunit/filters.py @@ -98,15 +98,7 @@ def filter_by_result(result_factory, output_path, passthrough, forward, return result -def _default_post_run(result): - if result.wasSuccessful(): - sys.exit(0) - else: - sys.exit(1) - - -def run_filter_script(result_factory, description, - post_run_hook=_default_post_run): +def run_filter_script(result_factory, description, post_run_hook=None): """Main function for simple subunit filter scripts. Many subunit filter scripts take a stream of subunit input and use a @@ -125,4 +117,9 @@ def run_filter_script(result_factory, description, result = filter_by_result( result_factory, options.output_to, not options.no_passthrough, options.forward) - post_run_hook(result) + if post_run_hook: + post_run_hook(result) + if result.wasSuccessful(): + sys.exit(0) + else: + sys.exit(1) -- cgit v1.2.1