Exit non-zero when listing includes import failures.
authorRobert Collins <robertc@robertcollins.net>
Sat, 30 Nov 2013 02:01:09 +0000 (15:01 +1300)
committerRobert Collins <robertc@robertcollins.net>
Sat, 30 Nov 2013 02:01:09 +0000 (15:01 +1300)
NEWS
python/subunit/run.py
python/subunit/tests/test_run.py
setup.py

diff --git a/NEWS b/NEWS
index b7f24bf..f909969 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,11 @@ BUG FIXES
 * V2 parser errors now set appropriate mime types for the encapsulated packet
   data and the error message. (Robert Collins)
 
+* When tests fail to import ``python subunit.run -l ...`` will now write a 
+  subunit file attachment listing the failed imports and exit 2, rather than
+  listing the stub objects from the importer and exiting 0.
+  (Robert Collins, #1245672)
+
 IMPROVEMENTS
 ~~~~~~~~~~~~
 
index b4ffdb3..7e4d783 100755 (executable)
@@ -33,6 +33,7 @@ from testtools.run import (
     BUFFEROUTPUT,
     CATCHBREAK,
     FAILFAST,
+    list_test,
     TestProgram,
     USAGE_AS_MAIN,
     )
@@ -51,7 +52,7 @@ class SubunitTestRunner(object):
 
     def run(self, test):
         "Run the given test case or test suite."
-        result = self._list(test)
+        result, _ = self._list(test)
         result = ExtendedToStreamDecorator(result)
         result = AutoTimingTestResultDecorator(result)
         if self.failfast is not None:
@@ -65,9 +66,15 @@ class SubunitTestRunner(object):
 
     def list(self, test):
         "List the test."
-        self._list(test)
+        result, errors = self._list(test)
+        if errors:
+            failed_descr = '\n'.join(errors).encode('utf8')
+            result.status(file_name="import errors", runnable=False,
+                file_bytes=failed_descr, mime_type="text/plain;charset=utf8")
+            sys.exit(2)
 
     def _list(self, test):
+        test_ids, errors = list_test(test)
         try:
             fileno = self.stream.fileno()
         except:
@@ -77,9 +84,9 @@ class SubunitTestRunner(object):
         else:
             stream = self.stream
         result = StreamResultToBytes(stream)
-        for case in iterate_tests(test):
-            result.status(test_id=case.id(), test_status='exists')
-        return result
+        for test_id in test_ids:
+            result.status(test_id=test_id, test_status='exists')
+        return result, errors
 
 
 class SubunitTestProgram(TestProgram):
index 0ca5a51..6ac84e1 100644 (file)
 from testtools.compat import BytesIO
 import unittest
 
-from testtools import PlaceHolder
+from testtools import PlaceHolder, TestCase
 from testtools.testresult.doubles import StreamResult
 
 import subunit
+from subunit import run
 from subunit.run import SubunitTestRunner
 
 
-class TestSubunitTestRunner(unittest.TestCase):
+class TestSubunitTestRunner(TestCase):
 
     def test_includes_timing_output(self):
         io = BytesIO()
@@ -52,3 +53,12 @@ class TestSubunitTestRunner(unittest.TestCase):
             ('status', 'name1', 'exists'),
             ('status', 'name2', 'exists'),
             ], [event[:3] for event in eventstream._events[:2]])
+
+    def test_list_errors_if_errors_from_list_test(self):
+        io = BytesIO()
+        runner = SubunitTestRunner(stream=io)
+        def list_test(test):
+            return [], ['failed import']
+        self.patch(run, 'list_test', list_test)
+        exc = self.assertRaises(SystemExit, runner.list, None)
+        self.assertEqual((2,), exc.args)
index 1649b16..9917977 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ else:
     extra = {
         'install_requires': [
             'extras',
-            'testtools>=0.9.30',
+            'testtools>=0.9.34',
         ]
     }