Merge lp:~mars/zope.testing/fix-subunit-utf8-traceback-reporting into lp:zope.testing

Proposed by Māris Fogels
Status: Merged
Merge reported by: Benji York
Merged at revision: not available
Proposed branch: lp:~mars/zope.testing/fix-subunit-utf8-traceback-reporting
Merge into: lp:zope.testing
Diff against target: 122 lines (+79/-3)
3 files modified
src/zope/testing/testrunner/formatter.py (+16/-3)
src/zope/testing/testrunner/test_subunit.py (+59/-0)
src/zope/testing/testrunner/tests.py (+4/-0)
To merge this branch: bzr merge lp:~mars/zope.testing/fix-subunit-utf8-traceback-reporting
Reviewer Review Type Date Requested Status
Benji York (community) Approve
Sidnei da Silva Approve
Review via email: mp+27086@code.launchpad.net

Description of the change

Hello,

This branch fixes a problem in zope.testing's subunit support. Instead of raising an Exception when the traceback contains UTF8-encoded characters we try to handle the text in a robust way. See bug 591309 for the details.

We assume the traceback is in utf-8, as that is the encoding most people would use for a doctest or Python module, but just in case, I included a test for handling other codecs.

This entire patch would be unnecessary if the traceback were guaranteed to be a unicode object. Unfortunately, I do not know the entry points from which a bytestring can be passed into the formatter, so this defensive code feels safer than risking a testrunner to crash. The unicode-type test makes the code forward-compatible.

I exposed the SubunitOutputFormatter's 'stream' attribute to facilitate testing.

Maris

To post a comment you must log in.
378. By Māris Fogels

Removed an unused variable

Revision history for this message
Sidnei da Silva (sidnei) wrote :

Looks good to me. +1!

review: Approve
Revision history for this message
Tres Seaver (tseaver) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Māris Fogels wrote:
> Māris Fogels has proposed merging lp:~mars/zope.testing/fix-subunit-utf8-traceback-reporting into lp:zope.testing.
>
> Requested reviews:
> ZTK steering group (ztk-steering-group)
> Related bugs:
> #591309 Crash when subunit reports test failures containing UTF8-encoded data
> https://bugs.launchpad.net/bugs/591309
>
>
> Hello,
>
> This branch fixes a problem in zope.testing's subunit support.
> Instead of raising an Exception when the traceback contains
> UTF8-encoded characters we try to handle the text in a robust way.
> See bug 591309 for the details.
>
> We assume the traceback is in utf-8, as that is the encoding most
> people would use for a doctest or Python module, but just in case, I
> included a test for handling other codecs.
>
> This entire patch would be unnecessary if the traceback were
> guaranteed to be a unicode object. Unfortunately, I do not know the
> entry points from which a bytestring can be passed into the
> formatter, so this defensive code feels safer than risking a
> testrunner to crash. The unicode-type test makes the code
> forward-compatible.
>
> I exposed the SubunitOutputFormatter's 'stream' attribute to
> facilitate testing.

I'm -1 on doing any further work on the subunit stuff on the trunk until
we clean up the testing story: at the moment, the features are
completely untested in 95% of the developement environments where folks
work on zope.testing / zope.testrunner, because subunit cannot be
installed in them.

I have a branch merge pending to add distutils support to subunit for
the Python libraries and scripts, which would make releasing them to
PyPI as an sdist feasible. Once that occurs, we can make the
'subunit-python' egg a testing dependency for zope.testing /
zope.testrunner, and ensure that the features don't bitrot.

Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 <email address hidden>
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkwPrYQACgkQ+gerLs4ltQ7RUACfc/7DzxUKL8m0eVOPgY70vRdf
AzgAn3vm4VNvVyTlaEvqI/LWdEAl9GT0
=9Lzj
-----END PGP SIGNATURE-----

Revision history for this message
Māris Fogels (mars) wrote :

> I'm -1 on doing any further work on the subunit stuff on the trunk until
> we clean up the testing story: at the moment, the features are
> completely untested in 95% of the developement environments where folks
> work on zope.testing / zope.testrunner, because subunit cannot be
> installed in them.
>
> I have a branch merge pending to add distutils support to subunit for
> the Python libraries and scripts, which would make releasing them to
> PyPI as an sdist feasible. Once that occurs, we can make the
> 'subunit-python' egg a testing dependency for zope.testing /
> zope.testrunner, and ensure that the features don't bitrot.
>
>
> Tres.

Tres, I agree, but does "any further work" include bugfixes to the subunit code? I have spent weeks hunting these bugs down. It would be a pity to lose them. (I may have more fixes coming, too.)

Maris

Revision history for this message
Robert Collins (lifeless) wrote :

I don't think it makes sense to hold back things that devs with a working environment can validate simply because other devs *might* cause regressions. Yes, we should get the zope.testing buildbot testing subunit, but the lack of that isn't a reason to stop fixing code that someone can run a test on.

Revision history for this message
Māris Fogels (mars) wrote :

I'm working on a fix to make the subunit support conditional.

Revision history for this message
Māris Fogels (mars) wrote :

I used virtualenv to compare the results of running the suite with and without subunit installed. The suite skips the test_subunit module when subunit is missing, and includes it when subunit is present. This is the proper behaviour.

The branch should be good to land as-is. If desired, I can include a comment in the docstring of the test_subunit module that states that module is run conditionally.

Revision history for this message
Jonathan Lange (jml) wrote :

Tres, now that subunit has a release on PyPI (see http://pypi.python.org/pypi/python-subunit), can this patch please be landed?

Revision history for this message
Benji York (benji) wrote :

The copyright line in the new module (src/zope/testing/testrunner/test_subunit.py) should have "2010" as the date. Other than that this change looks good.

review: Approve
379. By Māris Fogels

Changed the copyright to 2010.

Revision history for this message
Māris Fogels (mars) wrote :

On Mon, Jul 19, 2010 at 9:27 AM, Benji York <email address hidden> wrote:
> Review: Approve
> The copyright line in the new module (src/zope/testing/testrunner/test_subunit.py) should have "2010" as the date.  Other than that this change looks good.

Fixed.

Revision history for this message
Benji York (benji) wrote :

I merged this in in r114856.

I added at test dependency for python-subunit on the principal that testing more is better than less as long as the test dependencies aren't too evil, and python-subunit doesn't seem evil.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/zope/testing/testrunner/formatter.py'
--- src/zope/testing/testrunner/formatter.py 2010-06-03 16:55:38 +0000
+++ src/zope/testing/testrunner/formatter.py 2010-07-19 20:51:10 +0000
@@ -711,14 +711,18 @@
711 TAG_THREADS = 'zope:threads'711 TAG_THREADS = 'zope:threads'
712 TAG_REFCOUNTS = 'zope:refcounts'712 TAG_REFCOUNTS = 'zope:refcounts'
713713
714 def __init__(self, options):714 def __init__(self, options, stream=None):
715 if subunit is None:715 if subunit is None:
716 raise Exception("Requires subunit 0.0.5 or better")716 raise Exception("Requires subunit 0.0.5 or better")
717 if content is None:717 if content is None:
718 raise Exception("Requires testtools 0.9.2 or better")718 raise Exception("Requires testtools 0.9.2 or better")
719 self.options = options719 self.options = options
720 self._stream = sys.stdout720
721 if stream is None:
722 stream = sys.stdout
723 self._stream = stream
721 self._subunit = subunit.TestProtocolClient(self._stream)724 self._subunit = subunit.TestProtocolClient(self._stream)
725
722 # Used to track the last layer that was set up or torn down. Either726 # Used to track the last layer that was set up or torn down. Either
723 # None or (layer_name, last_touched_time).727 # None or (layer_name, last_touched_time).
724 self._last_layer = None728 self._last_layer = None
@@ -912,9 +916,18 @@
912 # create an object equivalent to an instance of 'TracebackContent'.916 # create an object equivalent to an instance of 'TracebackContent'.
913 formatter = OutputFormatter(None)917 formatter = OutputFormatter(None)
914 traceback = formatter.format_traceback(exc_info)918 traceback = formatter.format_traceback(exc_info)
919
920 # We have no idea if the traceback is a unicode object or a bytestring
921 # with non-ASCII characters. We had best be careful when handling it.
922 if isinstance(traceback, unicode):
923 unicode_tb = traceback
924 else:
925 # Assume the traceback was utf-8 encoded, but still be careful.
926 unicode_tb = traceback.decode('utf8', 'replace')
927
915 return {928 return {
916 'traceback': content.Content(929 'traceback': content.Content(
917 self.TRACEBACK_CONTENT_TYPE, lambda: [traceback.encode('utf8')])}930 self.TRACEBACK_CONTENT_TYPE, lambda: [unicode_tb.encode('utf8')])}
918931
919 def test_error(self, test, seconds, exc_info):932 def test_error(self, test, seconds, exc_info):
920 """Report that an error occurred while running a test.933 """Report that an error occurred while running a test.
921934
=== added file 'src/zope/testing/testrunner/test_subunit.py'
--- src/zope/testing/testrunner/test_subunit.py 1970-01-01 00:00:00 +0000
+++ src/zope/testing/testrunner/test_subunit.py 2010-07-19 20:51:10 +0000
@@ -0,0 +1,59 @@
1##############################################################################
2#
3# Copyright (c) 2004-2010 Zope Foundation and Contributors.
4# All Rights Reserved.
5#
6# This software is subject to the provisions of the Zope Public License,
7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11# FOR A PARTICULAR PURPOSE.
12#
13##############################################################################
14"""Unit tests for the testrunner's subunit integration.
15"""
16
17
18import sys
19import unittest
20import formatter
21import subunit
22from StringIO import StringIO
23
24
25class TestSubunitTracebackPrinting(unittest.TestCase):
26
27 def makeByteStringFailure(self, text, encoding):
28 try:
29 # Note that this deliberately throws a string of bytes instead
30 # of a unicode object. This simulates errors thrown by
31 # utf8-encoded doctests.
32 bytestr = text.encode(encoding)
33 self.fail(bytestr)
34 except self.failureException:
35 return sys.exc_info()
36
37 def setUp(self):
38 class FormatterOptions:
39 verbose=False
40 options = FormatterOptions()
41
42 self.output = StringIO()
43 self.subunit_formatter = formatter.SubunitOutputFormatter(
44 options, stream=self.output)
45
46 def test_print_failure_containing_utf8_bytestrings(self):
47 exc_info = self.makeByteStringFailure(unichr(6514), 'utf8')
48 self.subunit_formatter.test_failure(self, 0, exc_info)
49 assert "AssertionError: \xe1\xa5\xb2" in self.output.getvalue()
50
51 def test_print_error_containing_utf8_bytestrings(self):
52 exc_info = self.makeByteStringFailure(unichr(6514), 'utf8')
53 self.subunit_formatter.test_error(self, 0, exc_info)
54 assert "AssertionError: \xe1\xa5\xb2" in self.output.getvalue()
55
56 def test_print_failure_containing_latin1_bytestrings(self):
57 exc_info = self.makeByteStringFailure(unichr(241), 'latin1')
58 self.subunit_formatter.test_failure(self, 0, exc_info)
59 assert "AssertionError: \xef\xbf\xbd0" in self.output.getvalue()
0\ No newline at end of file60\ No newline at end of file
161
=== modified file 'src/zope/testing/testrunner/tests.py'
--- src/zope/testing/testrunner/tests.py 2010-06-03 16:55:38 +0000
+++ src/zope/testing/testrunner/tests.py 2010-07-19 20:51:10 +0000
@@ -296,4 +296,8 @@
296 optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,296 optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
297 checker=checker))297 checker=checker))
298298
299 suites.append(
300 unittest.defaultTestLoader.loadTestsFromName(
301 'zope.testing.testrunner.test_subunit'))
302
299 return unittest.TestSuite(suites)303 return unittest.TestSuite(suites)

Subscribers

People subscribed via source and target branches