Hello community,

here is the log from the commit of package python-testrepository for 
openSUSE:Factory checked in at 2014-09-17 17:26:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-testrepository (Old)
 and      /work/SRC/openSUSE:Factory/.python-testrepository.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-testrepository"

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-testrepository/python-testrepository.changes  
    2014-02-26 06:55:39.000000000 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-testrepository.new/python-testrepository.changes
 2014-09-17 17:27:26.000000000 +0200
@@ -1,0 +2,32 @@
+Tue Sep 16 06:22:45 UTC 2014 - [email protected]
+
+- update to version 0.0.20:
+  * Tests will be reliably tagged with worker-%d. The previous tagging logic
+    had an implicit race - the tag id was looked up via a closure which gets
+    the state of the pos variable at the position the overall loop has advanced
+    too, not the position when the closure was created.
+    (Robert Collins, #1316858)
+  * 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)
+  * Test filtering was failing under python3 and would only apply the
+    filters to the first test listed by discover. (Clark Boylan, #1317607)
+  * Tests that are enumerated but not executed will no longer reset the test
+    timing data. Enumeration was incorrectly recording a 0 timestamp for
+    enumerated tests. This leads to poor scheduling after an interrupted test
+    run. (Robert Collins, #1322763)
+  * Version 0.0.18 of subunit is now a hard dependency - the v2 protocol solves
+    key issues in concurrency and stream handling. Users that cannot use 
subunit
+    v2 can run an older testrepository, or contact upstream to work through
+    whatever issue is blocking them. (Robert Collins)
+  * When list-tests encounters an error, a much clearer response will
+    now be shown. (Robert Collins, #1271133)
+  * 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)
+
+-------------------------------------------------------------------

Old:
----
  testrepository-0.0.18.tar.gz

New:
----
  testrepository-0.0.20.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-testrepository.spec ++++++
--- /var/tmp/diff_new_pack.EAi3L3/_old  2014-09-17 17:27:27.000000000 +0200
+++ /var/tmp/diff_new_pack.EAi3L3/_new  2014-09-17 17:27:27.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python-testrepository
-Version:        0.0.18
+Version:        0.0.20
 Release:        0
 Summary:        A repository of test results
 License:        BSD-3-Clause or Apache-2.0

++++++ testrepository-0.0.18.tar.gz -> testrepository-0.0.20.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/INSTALL.txt 
new/testrepository-0.0.20/INSTALL.txt
--- old/testrepository-0.0.18/INSTALL.txt       2011-02-26 08:22:14.000000000 
+0100
+++ new/testrepository-0.0.20/INSTALL.txt       2014-08-23 23:38:00.000000000 
+0200
@@ -6,7 +6,7 @@
 
 * Python2.4 or newer.
 
-* subunit
+* subunit (0.0.18 or newer).
 
 * fixtures (https://launchpad.net/python-fixtures, or
    http://pypi.python.org/pypi/fixtures/).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/NEWS 
new/testrepository-0.0.20/NEWS
--- old/testrepository-0.0.18/NEWS      2013-11-05 00:52:12.000000000 +0100
+++ new/testrepository-0.0.20/NEWS      2014-08-27 01:57:23.000000000 +0200
@@ -5,6 +5,57 @@
 NEXT (In development)
 +++++++++++++++++++++
 
+0.0.20
+++++++
+
+IMPROVEMENTS
+------------
+
+* Tests will be reliably tagged with worker-%d. The previous tagging logic
+  had an implicit race - the tag id was looked up via a closure which gets
+  the state of the pos variable at the position the overall loop has advanced
+  too, not the position when the closure was created.
+  (Robert Collins, #1316858)
+
+0.0.19
+++++++
+
+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)
+
+* Test filtering was failing under python3 and would only apply the
+  filters to the first test listed by discover. (Clark Boylan, #1317607)
+
+* Tests that are enumerated but not executed will no longer reset the test
+  timing data. Enumeration was incorrectly recording a 0 timestamp for
+  enumerated tests. This leads to poor scheduling after an interrupted test
+  run. (Robert Collins, #1322763)
+
+* Version 0.0.18 of subunit is now a hard dependency - the v2 protocol solves
+  key issues in concurrency and stream handling. Users that cannot use subunit
+  v2 can run an older testrepository, or contact upstream to work through
+  whatever issue is blocking them. (Robert Collins)
+
+* When list-tests encounters an error, a much clearer response will
+  now be shown. (Robert Collins, #1271133)
+
+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)
+
 0.0.18
 ++++++
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/PKG-INFO 
new/testrepository-0.0.20/PKG-INFO
--- old/testrepository-0.0.18/PKG-INFO  2013-11-05 15:40:31.000000000 +0100
+++ new/testrepository-0.0.20/PKG-INFO  2014-08-27 02:12:15.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: testrepository
-Version: 0.0.18
+Version: 0.0.20
 Summary: A repository of test results.
 Home-page: https://launchpad.net/testrepository
 Author: Robert Collins
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/doc/DEVELOPERS.txt 
new/testrepository-0.0.20/doc/DEVELOPERS.txt
--- old/testrepository-0.0.18/doc/DEVELOPERS.txt        2013-04-08 
12:36:03.000000000 +0200
+++ new/testrepository-0.0.20/doc/DEVELOPERS.txt        2014-08-24 
09:43:39.000000000 +0200
@@ -52,3 +52,4 @@
 
 Update NEWS and testrepository/__init__.py version numbers. Release to pypi.
 Pivot the next milestone on LP to version, and make a new next milestone.
+Make a new tag and push that to github.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/setup.py 
new/testrepository-0.0.20/setup.py
--- old/testrepository-0.0.18/setup.py  2013-04-08 12:37:19.000000000 +0200
+++ new/testrepository-0.0.20/setup.py  2014-08-24 00:01:24.000000000 +0200
@@ -95,7 +95,7 @@
         ],
       install_requires=[
         'fixtures',
-        'python-subunit >= 0.0.10',
+        'python-subunit >= 0.0.18',
         'testtools >= 0.9.30',
         ],
       extras_require = dict(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/__init__.py 
new/testrepository-0.0.20/testrepository/__init__.py
--- old/testrepository-0.0.18/testrepository/__init__.py        2013-11-05 
00:55:48.000000000 +0100
+++ new/testrepository-0.0.20/testrepository/__init__.py        2014-08-27 
02:01:54.000000000 +0200
@@ -33,4 +33,4 @@
 # established at this point, and setup.py will use a version of next-$(revno).
 # If the releaselevel is 'final', then the tarball will be major.minor.micro.
 # Otherwise it is major.minor.micro~$(revno).
-__version__ = (0, 0, 18, 'final', 0)
+__version__ = (0, 0, 20, 'final', 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/commands/load.py 
new/testrepository-0.0.20/testrepository/commands/load.py
--- old/testrepository-0.0.18/testrepository/commands/load.py   2013-07-13 
13:46:33.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/commands/load.py   2014-08-25 
03:42:59.000000000 +0200
@@ -100,6 +100,8 @@
             streams = map(opener, self.ui.arguments['streams'])
         else:
             streams = self.ui.iter_streams('subunit')
+        mktagger = lambda pos, result:testtools.StreamTagger(
+            [result], add=['worker-%d' % pos])
         def make_tests():
             for pos, stream in enumerate(streams):
                 if v2_avail:
@@ -121,9 +123,8 @@
                     case = testtools.DecorateTestCaseResult(case, wrap_result,
                         methodcaller('startTestRun'),
                         methodcaller('stopTestRun'))
-                case = testtools.DecorateTestCaseResult(case,
-                    lambda result:testtools.StreamTagger(
-                        [result], add=['worker-%d' % pos]))
+                decorate = partial(mktagger, pos)
+                case = testtools.DecorateTestCaseResult(case, decorate)
                 yield (case, str(pos))
         case = testtools.ConcurrentStreamTestSuite(make_tests)
         # One unmodified copy of the stream to repository storage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/commands/run.py 
new/testrepository-0.0.20/testrepository/commands/run.py
--- old/testrepository-0.0.18/testrepository/commands/run.py    2013-11-03 
20:58:46.000000000 +0100
+++ new/testrepository-0.0.20/testrepository/commands/run.py    2014-03-08 
16:19:08.000000000 +0100
@@ -79,7 +79,7 @@
             if v2_avail:
                 stream = subunit.StreamResultToBytes(self.source)
                 stream.status(test_id='process-returncode', test_status='fail',
-                    file_name='traceback', mime_type='test/plain;charset=utf8',
+                    file_name='traceback', mime_type='text/plain;charset=utf8',
                     file_bytes=('returncode %d' % returncode).encode('utf8'))
             else:
                 self.source.write(_b('test: process-returncode\n'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/repository/file.py 
new/testrepository-0.0.20/testrepository/repository/file.py
--- old/testrepository-0.0.18/testrepository/repository/file.py 2013-04-01 
11:18:36.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/repository/file.py 2014-08-24 
12:13:09.000000000 +0200
@@ -25,7 +25,7 @@
 import sys
 import tempfile
 
-import subunit
+import subunit.v2
 from subunit import TestProtocolClient
 import testtools
 from testtools.compat import _b
@@ -188,10 +188,23 @@
         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.
@@ -227,7 +240,7 @@
 
     def _handle_test(self, test_dict):
         start, stop = test_dict['timestamps']
-        if None in (start, stop):
+        if test_dict['status'] == 'exists' or None in (start, stop):
             return
         self._times[test_dict['id']] = str(timedelta_to_seconds(stop - start))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/repository/memory.py 
new/testrepository-0.0.20/testrepository/repository/memory.py
--- old/testrepository-0.0.18/testrepository/repository/memory.py       
2013-07-17 11:03:54.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/repository/memory.py       
2014-08-24 12:13:34.000000000 +0200
@@ -102,8 +102,13 @@
 
     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 @@
             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 @@
         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])
@@ -147,7 +151,7 @@
     def _handle_test(self, test_dict):
         self._tests.append(test_dict)
         start, stop = test_dict['timestamps']
-        if None in (start, stop):
+        if test_dict['status'] == 'exists' or None in (start, stop):
             return
         duration_delta = stop - start
         duration_seconds = ((duration_delta.microseconds +
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/results.py 
new/testrepository-0.0.20/testrepository/results.py
--- old/testrepository-0.0.18/testrepository/results.py 2013-07-10 
22:28:21.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/results.py 2014-03-08 
16:19:08.000000000 +0100
@@ -13,7 +13,11 @@
 # limitations under that license.
 
 
-from testtools import StreamSummary
+import subunit
+from testtools import (
+    StreamSummary,
+    StreamResult,
+    )
 
 from testrepository.utils import timedelta_to_seconds
 
@@ -47,3 +51,23 @@
         if None in (self._last_time, self._first_time):
             return None
         return timedelta_to_seconds(self._last_time - self._first_time)
+
+
+#XXX: Should be in testtools.
+class CatFiles(StreamResult):
+    """Cat file attachments received to a stream."""
+        
+    def __init__(self, byte_stream):
+        self.stream = subunit.make_stream_binary(byte_stream)
+        self.last_file = None
+
+    def status(self, test_id=None, test_status=None, test_tags=None,
+        runnable=True, file_name=None, file_bytes=None, eof=False,
+        mime_type=None, route_code=None, timestamp=None):
+        if file_name is None:
+            return
+        if self.last_file != file_name:
+            self.stream.write(("--- %s ---\n" % file_name).encode('utf8'))
+            self.last_file = file_name
+        self.stream.write(file_bytes)
+        self.stream.flush()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/testcommand.py 
new/testrepository-0.0.20/testrepository/testcommand.py
--- old/testrepository-0.0.18/testrepository/testcommand.py     2013-07-17 
04:50:44.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/testcommand.py     2014-08-23 
22:30:39.000000000 +0200
@@ -14,10 +14,14 @@
 
 """The test command that test repository knows how to run."""
 
-from extras import try_imports
+from extras import (
+    try_import,
+    try_imports,
+    )
 
 from collections import defaultdict
 ConfigParser = try_imports(['ConfigParser', 'configparser'])
+import io
 import itertools
 import operator
 import os.path
@@ -29,7 +33,9 @@
 from textwrap import dedent
 
 from fixtures import Fixture
+v2 = try_import('subunit.v2')
 
+from testrepository import results
 from testrepository.testlist import (
     parse_enumeration,
     write_list,
@@ -273,7 +279,7 @@
         """
         if self.test_filters is None:
             return test_ids
-        filters = map(re.compile, self.test_filters)
+        filters = list(map(re.compile, self.test_filters))
         def include(test_id):
             for pred in filters:
                 if pred.search(test_id):
@@ -294,9 +300,16 @@
                 stdout=subprocess.PIPE, stdin=subprocess.PIPE)
             out, err = run_proc.communicate()
             if run_proc.returncode != 0:
+                if v2 is not None:
+                    new_out = io.BytesIO()
+                    v2.ByteStreamToStreamResult(io.BytesIO(out), 'stdout').run(
+                        results.CatFiles(new_out))
+                    out = new_out.getvalue()
+                self.ui.output_stream(io.BytesIO(out))
+                self.ui.output_stream(io.BytesIO(err))
                 raise ValueError(
                     "Non-zero exit code (%d) from test listing."
-                    " stdout=%r, stderr=%r" % (run_proc.returncode, out, err))
+                    % (run_proc.returncode))
             ids = parse_enumeration(out)
             return ids
         finally:
@@ -443,8 +456,8 @@
         out, err = run_proc.communicate()
         if run_proc.returncode:
             raise ValueError(
-                "test_run_concurrency failed: exit code %d, stderr=%r" % (
-                run_proc.returncode, err))
+                "test_run_concurrency failed: exit code %d, stderr='%s'" % (
+                run_proc.returncode, err.decode('utf8', 'replace')))
         return int(out.strip())
 
     def local_concurrency(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/commands/test_failing.py 
new/testrepository-0.0.20/testrepository/tests/commands/test_failing.py
--- old/testrepository-0.0.18/testrepository/tests/commands/test_failing.py     
2013-04-11 13:19:07.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/commands/test_failing.py     
2014-08-23 23:20:54.000000000 +0200
@@ -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 @@
         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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/commands/test_last.py 
new/testrepository-0.0.20/testrepository/tests/commands/test_last.py
--- old/testrepository-0.0.18/testrepository/tests/commands/test_last.py        
2013-04-11 13:18:22.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/commands/test_last.py        
2014-08-23 23:20:54.000000000 +0200
@@ -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 @@
         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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/commands/test_run.py 
new/testrepository-0.0.20/testrepository/tests/commands/test_run.py
--- old/testrepository-0.0.18/testrepository/tests/commands/test_run.py 
2013-11-03 20:58:46.000000000 +0100
+++ new/testrepository-0.0.20/testrepository/tests/commands/test_run.py 
2014-03-08 16:19:08.000000000 +0100
@@ -532,7 +532,7 @@
             buffer.write(b'foo\nbar\n')
             stream = subunit.StreamResultToBytes(buffer)
             stream.status(test_id='process-returncode', test_status='fail',
-                file_name='traceback', mime_type='test/plain;charset=utf8',
+                file_name='traceback', mime_type='text/plain;charset=utf8',
                 file_bytes=b'returncode 1')
             expected_content = buffer.getvalue()
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/test_repository.py 
new/testrepository-0.0.20/testrepository/tests/test_repository.py
--- old/testrepository-0.0.18/testrepository/tests/test_repository.py   
2013-04-01 11:31:50.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/test_repository.py   
2014-08-24 12:11:22.000000000 +0200
@@ -20,7 +20,10 @@
     )
 import doctest
 
-from subunit import iso8601
+from subunit import (
+    iso8601,
+    v2,
+    )
 
 from testresources import TestResource
 from testtools import (
@@ -29,7 +32,10 @@
     )
 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
@@ -113,12 +119,18 @@
     return clone_test_with_new_id(case, id)
 
 
-def run_timed(id, duration, result):
-    """Make and run a test taking duration seconds."""
+def run_timed(id, duration, result, enumeration=False):
+    """Make and run a test taking duration seconds.
+    
+    :param enumeration: If True, don't run, just enumerate.
+    """
     start = datetime.now(tz=iso8601.Utc())
-    result.status(test_id=id, test_status='inprogress', timestamp=start)
-    result.status(test_id=id, test_status='success',
-        timestamp=start + timedelta(seconds=duration))
+    if enumeration:
+        result.status(test_id=id, test_status='exists', timestamp=start)
+    else:
+        result.status(test_id=id, test_status='inprogress', timestamp=start)
+        result.status(test_id=id, test_status='success',
+            timestamp=start + timedelta(seconds=duration))
 
 
 class TestRepositoryErrors(ResourcedTestCase):
@@ -374,6 +386,61 @@
         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 +451,41 @@
         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)
@@ -423,6 +521,22 @@
         self.assertEqual({test_name: 0.1},
             repo.get_test_times([test_name])['known'])
 
+    def test_inserted_exists_no_impact_on_test_times(self):
+        repo = self.repo_impl.initialise(self.sample_url)
+        result = repo.get_inserter()
+        legacy_result = testtools.ExtendedToStreamDecorator(result)
+        legacy_result.startTestRun()
+        test_name = 'testrepository.tests.test_repository.Case.method'
+        run_timed(test_name, 0.1, legacy_result)
+        legacy_result.stopTestRun()
+        result = repo.get_inserter()
+        result.startTestRun()
+        test_name = 'testrepository.tests.test_repository.Case.method'
+        run_timed(test_name, 0.2, result, True)
+        result.stopTestRun()
+        self.assertEqual({test_name: 0.1},
+            repo.get_test_times([test_name])['known'])
+
     def test_get_test_ids(self):
         repo = self.repo_impl.initialise(self.sample_url)
         inserter = repo.get_inserter()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/test_setup.py 
new/testrepository-0.0.20/testrepository/tests/test_setup.py
--- old/testrepository-0.0.18/testrepository/tests/test_setup.py        
2013-02-06 11:01:04.000000000 +0100
+++ new/testrepository-0.0.20/testrepository/tests/test_setup.py        
2014-08-23 23:16:28.000000000 +0200
@@ -35,7 +35,7 @@
         proc = subprocess.Popen([sys.executable, path, 'bdist'],
             stdin=subprocess.PIPE, stdout=subprocess.PIPE,
             stderr=subprocess.STDOUT, universal_newlines=True)
-        output, _ = proc.communicate()
+        output, err = proc.communicate()
         self.assertThat(output, MatchesAny(
             # win32
             DocTestMatches("""...
@@ -48,4 +48,5 @@
 ...bin/testr ...
 """, doctest.ELLIPSIS)
             ))
-        self.assertEqual(0, proc.returncode)
+        self.assertEqual(0, proc.returncode,
+            "Setup failed out=%r err=%r" % (output, err))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/test_testcommand.py 
new/testrepository-0.0.20/testrepository/tests/test_testcommand.py
--- old/testrepository-0.0.18/testrepository/tests/test_testcommand.py  
2013-07-17 04:53:08.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/test_testcommand.py  
2014-05-18 20:24:04.000000000 +0200
@@ -575,3 +575,14 @@
         fixture = self.useFixture(command.get_run_command(
             test_ids=['return', 'of', 'the', 'king'], test_filters=filters))
         self.assertEqual(['return'], fixture.test_ids)
+
+    def test_filter_tests_by_regex_supplied_ids_multi_match(self):
+        ui, command = self.get_test_ui_and_cmd()
+        ui.proc_outputs = [_b('returned\nids\n')]
+        self.set_config(
+            '[DEFAULT]\ntest_command=foo $LISTOPT 
$IDLIST\ntest_id_list_default=whoo yea\n'
+            'test_list_option=--list\n')
+        filters = ['return']
+        fixture = self.useFixture(command.get_run_command(
+            test_ids=['return', 'of', 'the', 'king', 'thereisnoreturn'], 
test_filters=filters))
+        self.assertEqual(['return', 'thereisnoreturn'], fixture.test_ids)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/test_ui.py 
new/testrepository-0.0.20/testrepository/tests/test_ui.py
--- old/testrepository-0.0.18/testrepository/tests/test_ui.py   2013-04-11 
13:13:52.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/test_ui.py   2014-08-24 
11:54:08.000000000 +0200
@@ -119,6 +119,11 @@
         ui = self.get_test_ui()
         ui.output_stream(BytesIO())
 
+    def test_output_stream_non_utf8(self):
+        # When the stream has non-utf8 bytes it still outputs correctly.
+        ui = self.get_test_ui()
+        ui.output_stream(BytesIO(_b('\xfa')))
+
     def test_output_table(self):
         # output_table shows a table.
         ui = self.get_test_ui()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository/tests/ui/test_cli.py 
new/testrepository-0.0.20/testrepository/tests/ui/test_cli.py
--- old/testrepository-0.0.18/testrepository/tests/ui/test_cli.py       
2013-07-13 13:55:12.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/tests/ui/test_cli.py       
2014-08-23 23:05:41.000000000 +0200
@@ -109,7 +109,8 @@
         except Exception:
             err_tuple = sys.exc_info()
         expected = str(err_tuple[1]) + '\n'
-        stdout = StringIO()
+        bytestream = BytesIO()
+        stdout = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         stdin = StringIO()
         stderr = StringIO()
         ui = cli.UI([], stdin, stdout, stderr)
@@ -128,6 +129,9 @@
             <BLANKLINE>
             fooo
             """)
+        # This should be a BytesIO + Textwrapper, but pdb on 2.7 writes bytes
+        # - this code is the most pragmatic to test on 2.6 and up, and 3.2 and
+        # up.
         stdout = StringIO()
         stdin = StringIO(_u('c\n'))
         stderr = StringIO()
@@ -196,7 +200,8 @@
             ui._stdout.buffer.getvalue())
 
     def test_parse_error_goes_to_stderr(self):
-        stdout = StringIO()
+        bytestream = BytesIO()
+        stdout = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         stdin = StringIO()
         stderr = StringIO()
         ui = cli.UI(['one'], stdin, stdout, stderr)
@@ -206,7 +211,8 @@
         self.assertEqual("Could not find command 'one'.\n", stderr.getvalue())
 
     def test_parse_excess_goes_to_stderr(self):
-        stdout = StringIO()
+        bytestream = BytesIO()
+        stdout = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         stdin = StringIO()
         stderr = StringIO()
         ui = cli.UI(['one'], stdin, stdout, stderr)
@@ -248,7 +254,8 @@
         self.assertEqual(True, ui.options.subunit)
 
     def test_dash_dash_help_shows_help(self):
-        stdout = StringIO()
+        bytestream = BytesIO()
+        stdout = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         stdin = StringIO()
         stderr = StringIO()
         ui = cli.UI(['--help'], stdin, stdout, stderr)
@@ -263,7 +270,7 @@
             self.assertThat(exc_info, MatchesException(SystemExit(0)))
         else:
             self.fail('ui.set_command did not raise')
-        self.assertThat(stdout.getvalue(),
+        self.assertThat(bytestream.getvalue().decode('utf8'),
             DocTestMatches("""Usage: run.py bar [options] foo
 ...
 A command that can be run...
@@ -352,9 +359,11 @@
     def test_initial_stream(self):
         # CLITestResult.__init__ does not do anything to the stream it is
         # given.
-        stream = StringIO()
-        cli.CLITestResult(cli.UI(None, None, None, None), stream, lambda: None)
-        self.assertEqual('', stream.getvalue())
+        bytestream = BytesIO()
+        stream = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
+        ui = cli.UI(None, None, None, None)
+        cli.CLITestResult(ui, stream, lambda: None)
+        self.assertEqual(_b(''), bytestream.getvalue())
 
     def test_format_error(self):
         # CLITestResult formats errors by giving them a big fat line, a title
@@ -376,7 +385,8 @@
     def test_addFail_outputs_error(self):
         # CLITestResult.status test_status='fail' outputs the given error
         # immediately to the stream.
-        stream = StringIO()
+        bytestream = BytesIO()
+        stream = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         result = self.make_result(stream)[0]
         error = self.make_exc_info()
         error_text = 'foo\nbar\n'
@@ -385,7 +395,7 @@
             file_name='traceback', mime_type='text/plain;charset=utf8',
             file_bytes=error_text.encode('utf8'))
         self.assertThat(
-            stream.getvalue(),
+            bytestream.getvalue().decode('utf8'),
             DocTestMatches(result._format_error('FAIL', self, error_text)))
 
     def test_addFailure_handles_string_encoding(self):
@@ -412,7 +422,8 @@
         self.assertEqual(b'', bytestream.getvalue())
 
     def test_make_result_tag_filter(self):
-        stream = StringIO()
+        bytestream = BytesIO()
+        stream = TextIOWrapper(bytestream, 'utf8', line_buffering=True)
         result, summary = self.make_result(
             stream, filter_tags=set(['worker-0']))
         # Generate a bunch of results with tags in the same events that
@@ -438,5 +449,5 @@
 ----------------------------------------------------------------------
 Ran 1 tests
 FAILED (id=None, failures=1, skips=1)
-""", stream.getvalue())
+""", bytestream.getvalue().decode('utf8'))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/ui/cli.py 
new/testrepository-0.0.20/testrepository/ui/cli.py
--- old/testrepository-0.0.18/testrepository/ui/cli.py  2013-04-13 
18:32:47.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/ui/cli.py  2014-08-25 
03:43:29.000000000 +0200
@@ -93,6 +93,7 @@
         self._stdin = stdin
         self._stdout = stdout
         self._stderr = stderr
+        self._binary_stdout = None
 
     def _iter_streams(self, stream_type):
         # Only the first stream declared in a command can be accepted at the
@@ -155,13 +156,17 @@
             self._stdout.write(_u('\n'))
 
     def output_stream(self, stream):
+        if not self._binary_stdout:
+            self._binary_stdout = subunit.make_stream_binary(self._stdout)
         contents = stream.read(65536)
         assert type(contents) is bytes, \
             "Bad stream contents %r" % type(contents)
-        # Outputs bytes, treat them as utf8. Probably needs fixing.
+        # If there are unflushed bytes in the text wrapper, we need to sync..
+        self._stdout.flush()
         while contents:
-            self._stdout.write(contents.decode('utf8'))
+            self._binary_stdout.write(contents)
             contents = stream.read(65536)
+        self._binary_stdout.flush()
 
     def output_table(self, table):
         # stringify
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/testrepository-0.0.18/testrepository/ui/model.py 
new/testrepository-0.0.20/testrepository/ui/model.py
--- old/testrepository-0.0.18/testrepository/ui/model.py        2013-04-11 
13:14:26.000000000 +0200
+++ new/testrepository-0.0.20/testrepository/ui/model.py        2014-03-08 
16:19:08.000000000 +0100
@@ -33,7 +33,7 @@
 
     def communicate(self):
         self.ui.outputs.append(('communicate',))
-        return self.stdout.getvalue(), ''
+        return self.stdout.getvalue(), b''
 
     def wait(self):
         return self.returncode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository.egg-info/PKG-INFO 
new/testrepository-0.0.20/testrepository.egg-info/PKG-INFO
--- old/testrepository-0.0.18/testrepository.egg-info/PKG-INFO  2013-11-05 
15:40:31.000000000 +0100
+++ new/testrepository-0.0.20/testrepository.egg-info/PKG-INFO  2014-08-27 
02:12:14.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: testrepository
-Version: 0.0.18
+Version: 0.0.20
 Summary: A repository of test results.
 Home-page: https://launchpad.net/testrepository
 Author: Robert Collins
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/testrepository-0.0.18/testrepository.egg-info/requires.txt 
new/testrepository-0.0.20/testrepository.egg-info/requires.txt
--- old/testrepository-0.0.18/testrepository.egg-info/requires.txt      
2013-11-05 15:40:31.000000000 +0100
+++ new/testrepository-0.0.20/testrepository.egg-info/requires.txt      
2014-08-27 02:12:14.000000000 +0200
@@ -1,5 +1,5 @@
 fixtures
-python-subunit >= 0.0.10
+python-subunit >= 0.0.18
 testtools >= 0.9.30
 
 [test]

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to