From 54243f705d9d8883418c9f091c44c3743cb613e8 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Sun, 24 Aug 2014 09:34:06 +1200 Subject: Move to subunit v2 for output of stored streams. Passing --subunit to all testr commands will now consistently output subunit v2. Previously it would output v1 for stored streams and v2 for live streams. --- NEWS | 8 ++ testrepository/repository/file.py | 19 ++++- testrepository/repository/memory.py | 16 ++-- testrepository/tests/commands/test_failing.py | 23 +++++- testrepository/tests/commands/test_last.py | 30 +++++--- testrepository/tests/test_repository.py | 104 ++++++++++++++++++++++++-- 6 files changed, 173 insertions(+), 27 deletions(-) diff --git a/NEWS b/NEWS index a3221e0..063a596 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ NEXT (In development) CHANGES ------- +* Passing --subunit to all testr commands will now consistently output subunit + v2. Previously it would output v1 for stored streams and v2 for live + streams. (Robert Collins) + * ``run`` was outputting bad MIME types - test/plain, not text/plain. (Robert Collins) @@ -20,6 +24,10 @@ CHANGES INTERNALS --------- +* The ``get_subunit_stream`` methods now return subunit v2 streams rather + than v1 streams, preparing the way for storage of native v2 streams in + the repository. (Robert Collins) + * ``UI.output_stream`` is now tested for handling of non-utf8 bytestreams. (Robert Collins) diff --git a/testrepository/repository/file.py b/testrepository/repository/file.py index 85ee1a3..5de131d 100644 --- a/testrepository/repository/file.py +++ b/testrepository/repository/file.py @@ -25,7 +25,7 @@ import os.path import sys import tempfile -import subunit +import subunit.v2 from subunit import TestProtocolClient import testtools from testtools.compat import _b @@ -188,10 +188,23 @@ class _DiskRun(AbstractTestRun): return self._run_id def get_subunit_stream(self): - return BytesIO(self._content) + # Transcode - we want V2. + v1_stream = BytesIO(self._content) + v1_case = subunit.ProtocolTestCase(v1_stream) + output = BytesIO() + output_stream = subunit.v2.StreamResultToBytes(output) + output_stream = testtools.ExtendedToStreamDecorator(output_stream) + output_stream.startTestRun() + try: + v1_case.run(output_stream) + finally: + output_stream.stopTestRun() + output.seek(0) + return output def get_test(self): - case = subunit.ProtocolTestCase(self.get_subunit_stream()) + #case = subunit.ProtocolTestCase(self.get_subunit_stream()) + case = subunit.ProtocolTestCase(BytesIO(self._content)) def wrap_result(result): # Wrap in a router to mask out startTestRun/stopTestRun from the # ExtendedToStreamDecorator. diff --git a/testrepository/repository/memory.py b/testrepository/repository/memory.py index 594128a..647a81b 100644 --- a/testrepository/repository/memory.py +++ b/testrepository/repository/memory.py @@ -102,8 +102,13 @@ class _Failures(AbstractTestRun): def get_subunit_stream(self): result = BytesIO() - serialiser = subunit.TestProtocolClient(result) - self.run(serialiser) + serialiser = subunit.v2.StreamResultToBytes(result) + serialiser = testtools.ExtendedToStreamDecorator(serialiser) + serialiser.startTestRun() + try: + self.run(serialiser) + finally: + serialiser.stopTestRun() result.seek(0) return result @@ -120,7 +125,7 @@ class _Failures(AbstractTestRun): methodcaller('stopTestRun')) def run(self, result): - # Speaks original. + # Speaks original V1 protocol. for case in self._repository._failing.values(): case.run(result) @@ -132,13 +137,12 @@ class _Inserter(AbstractTestRun): self._repository = repository self._partial = partial self._tests = [] - # Subunit V1 stream for get_subunit_stream + # Subunit V2 stream for get_subunit_stream self._subunit = None def startTestRun(self): self._subunit = BytesIO() - serialiser = subunit.TestProtocolClient(self._subunit) - serialiser = testtools.StreamToExtendedDecorator(serialiser) + serialiser = subunit.v2.StreamResultToBytes(self._subunit) self._hook = testtools.CopyStreamResult([ testtools.StreamToDict(self._handle_test), serialiser]) diff --git a/testrepository/tests/commands/test_failing.py b/testrepository/tests/commands/test_failing.py index a37f326..56c97ef 100644 --- a/testrepository/tests/commands/test_failing.py +++ b/testrepository/tests/commands/test_failing.py @@ -15,13 +15,16 @@ """Tests for the failing command.""" import doctest +from io import BytesIO +from subunit.v2 import ByteStreamToStreamResult import testtools from testtools.compat import _b from testtools.matchers import ( DocTestMatches, Equals, ) +from testtools.testresult.doubles import StreamResult from testrepository.commands import failing from testrepository.ui.model import UI @@ -78,9 +81,23 @@ class TestCommand(ResourcedTestCase): self.assertEqual(0, cmd.execute()) self.assertEqual(1, len(ui.outputs)) self.assertEqual('stream', ui.outputs[0][0]) - self.assertThat(ui.outputs[0][1].decode('utf8'), - DocTestMatches("""...test: ...failing -...failure: ...failing...""", doctest.ELLIPSIS)) + as_subunit = BytesIO(ui.outputs[0][1]) + stream = ByteStreamToStreamResult(as_subunit) + log = StreamResult() + log.startTestRun() + try: + stream.run(log) + finally: + log.stopTestRun() + self.assertEqual( + log._events, [ + ('startTestRun',), + ('status', 'failing', 'inprogress', None, True, None, None, False, + None, None, Wildcard), + ('status', 'failing', 'fail', None, True, None, None, False, None, + None, Wildcard), + ('stopTestRun',) + ]) def test_with_subunit_no_failures_exit_0(self): ui, cmd = self.get_test_ui_and_cmd(options=[('subunit', True)]) diff --git a/testrepository/tests/commands/test_last.py b/testrepository/tests/commands/test_last.py index 672051e..80571b9 100644 --- a/testrepository/tests/commands/test_last.py +++ b/testrepository/tests/commands/test_last.py @@ -14,9 +14,12 @@ """Tests for the last command.""" +from io import BytesIO + +from subunit.v2 import ByteStreamToStreamResult import testtools -from testtools.compat import _b from testtools.matchers import Equals +from testtools.testresult.doubles import StreamResult from testrepository.commands import last from testrepository.ui.model import UI @@ -104,11 +107,20 @@ class TestCommand(ResourcedTestCase): self.assertEqual([ ('stream', Wildcard), ], ui.outputs) - self.assertThat(ui.outputs[0][1], Equals(_b("""\ -test: failing -failure: failing [ multipart -] -test: ok -successful: ok [ multipart -] -"""))) + as_subunit = BytesIO(ui.outputs[0][1]) + stream = ByteStreamToStreamResult(as_subunit) + log = StreamResult() + log.startTestRun() + try: + stream.run(log) + finally: + log.stopTestRun() + self.assertEqual( + log._events, [ + ('startTestRun',), + ('status', 'failing', 'fail', None, True, None, None, False, + None, None, None), + ('status', 'ok', 'success', None, True, None, None, False, None, + None, None), + ('stopTestRun',) + ]) diff --git a/testrepository/tests/test_repository.py b/testrepository/tests/test_repository.py index f3e68d9..1bc9162 100644 --- a/testrepository/tests/test_repository.py +++ b/testrepository/tests/test_repository.py @@ -20,7 +20,10 @@ from datetime import ( ) import doctest -from subunit import iso8601 +from subunit import ( + iso8601, + v2, + ) from testresources import TestResource from testtools import ( @@ -29,7 +32,10 @@ from testtools import ( ) import testtools from testtools.compat import _b -from testtools.testresult.doubles import ExtendedTestResult +from testtools.testresult.doubles import ( + ExtendedTestResult, + StreamResult, + ) from testtools.matchers import DocTestMatches, raises from testrepository import repository @@ -374,6 +380,61 @@ class TestRepositoryContract(ResourcedTestCase): run = repo.get_failing() self.assertEqual(None, run.get_id()) + def test_get_failing_get_subunit_stream(self): + repo = self.repo_impl.initialise(self.sample_url) + result = repo.get_inserter() + legacy_result = testtools.ExtendedToStreamDecorator(result) + legacy_result.startTestRun() + make_test('testrepository.tests.test_repository.Case.method', False).run(legacy_result) + legacy_result.stopTestRun() + run = repo.get_failing() + as_subunit = run.get_subunit_stream() + stream = v2.ByteStreamToStreamResult(as_subunit) + log = StreamResult() + log.startTestRun() + try: + stream.run(log) + finally: + log.stopTestRun() + self.assertEqual( + log._events, [ + ('startTestRun',), + ('status', + 'testrepository.tests.test_repository.Case.method', + 'inprogress', + None, + True, + None, + None, + False, + None, + None, + Wildcard), + ('status', + 'testrepository.tests.test_repository.Case.method', + None, + None, + True, + 'traceback', + Wildcard, + True, + Wildcard, + None, + Wildcard), + ('status', + 'testrepository.tests.test_repository.Case.method', + 'fail', + None, + True, + None, + None, + False, + None, + None, + Wildcard), + ('stopTestRun',) + ]) + def test_get_subunit_from_test_run(self): repo = self.repo_impl.initialise(self.sample_url) result = repo.get_inserter() @@ -384,10 +445,41 @@ class TestRepositoryContract(ResourcedTestCase): inserted = result.get_id() run = repo.get_test_run(inserted) as_subunit = run.get_subunit_stream() - self.assertThat(as_subunit.read().decode('utf8'), - DocTestMatches("""...test: testrepository.tests.test_repository.Case.method... -successful: testrepository.tests.test_repository.Case.method... -""", doctest.ELLIPSIS)) + stream = v2.ByteStreamToStreamResult(as_subunit) + log = StreamResult() + log.startTestRun() + try: + stream.run(log) + finally: + log.stopTestRun() + self.assertEqual( + log._events, + [ + ('startTestRun',), + ('status', + 'testrepository.tests.test_repository.Case.method', + 'inprogress', + None, + True, + None, + None, + False, + None, + None, + Wildcard), + ('status', + 'testrepository.tests.test_repository.Case.method', + 'success', + None, + True, + None, + None, + False, + None, + None, + Wildcard), + ('stopTestRun',) + ]) def test_get_test_from_test_run(self): repo = self.repo_impl.initialise(self.sample_url) -- cgit v1.2.1