changeset 741:77ddb8c210d8

Fix and tests for failure when parsing py.test --junitxml tracebacks (patch from Torsten Landschoff). See #562.
author hodgestar
date Tue, 20 Apr 2010 19:45:19 +0000
parents 7c8b6a329e12
children 5e274fc552c3
files bitten/build/javatools.py bitten/build/tests/__init__.py bitten/build/tests/javatools.py
diffstat 3 files changed, 84 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/build/javatools.py
+++ b/bitten/build/javatools.py
@@ -101,6 +101,24 @@
     if not error_logged and cmdline.returncode != 0:
         ctxt.error('Ant failed (%s)' % cmdline.returncode)
 
+
+def _fix_traceback(result):
+    """
+    Sometimes the traceback isn't prefixed with the exception type and
+    message, so add it in if needed.
+    """
+    attr = result[0].attr
+    tracebackprefix = ""
+    # py.test does not include the type tag in some cases so don't do this
+    # fix when it is missing
+    if "type" in attr:
+        tracebackprefix = "%s: %s" % (attr['type'], attr.get('message', ''))
+    if result[0].gettext().startswith(tracebackprefix):
+        return result[0].gettext()
+    else:
+        return "\n".join((tracebackprefix, result[0].gettext()))
+
+
 def junit(ctxt, file_=None, srcdir=None):
     """Extract test results from a JUnit XML report.
     
@@ -132,16 +150,7 @@
                     result = list(testcase.children())
                     if result:
                         test.attr['status'] = result[0].name
-                        # Sometimes the traceback isn't prefixed with the
-                        # exception type and message, so add it in if needed
-                        tracebackprefix = "%s: %s" % (result[0].attr['type'],
-                                    result[0].attr.get('message', ''))
-                        if result[0].gettext().startswith(tracebackprefix):
-                            test.append(xmlio.Element('traceback')[
-                                        result[0].gettext()])
-                        else:
-                            test.append(xmlio.Element('traceback')[
-                                        "\n".join((tracebackprefix, result[0].gettext()))])
+                        test.append(xmlio.Element('traceback')[_fix_traceback(result)])
                         failed += 1
                     else:
                         test.attr['status'] = 'success'
--- a/bitten/build/tests/__init__.py
+++ b/bitten/build/tests/__init__.py
@@ -12,7 +12,7 @@
 
 from bitten.build.tests import api, config, ctools, hgtools, \
                                monotools, phptools, pythontools, \
-                               xmltools
+                               xmltools, javatools
 
 def suite():
     suite = unittest.TestSuite()
@@ -23,6 +23,7 @@
     suite.addTest(monotools.suite())
     suite.addTest(phptools.suite())
     suite.addTest(pythontools.suite())
+    suite.addTest(javatools.suite())
     suite.addTest(xmltools.suite())
     return suite
 
--- a/bitten/build/tests/javatools.py
+++ b/bitten/build/tests/javatools.py
@@ -9,6 +9,7 @@
 # you should have received as part of this distribution. The terms
 # are also available at http://bitten.edgewall.org/wiki/License.
 
+import os
 import os.path
 import shutil
 import tempfile
@@ -119,10 +120,72 @@
         self.assertEqual(0, elem.attr['lines'])
         self.assertEqual(0, elem.attr['percentage'])
 
+class PyTestTestCase(unittest.TestCase):
+    xml_template = """<testsuite name="%(name)s" errors="%(errors)d"
+        failures="%(failures)d" skips="%(skips)d" tests="%(tests)d" time="%(time)f">
+    %(body)s
+</testsuite>
+"""
+    def setUp(self):
+        self.basedir = os.path.realpath(tempfile.mkdtemp())
+        self.ctxt = Context(self.basedir)
+
+    def tearDown(self):
+        shutil.rmtree(self.basedir)
+
+    def _xml_file(self, body, name="", errors=0, failures=0, skips=0, tests=0, time=0.01):
+        if tests == 0:
+            tests = errors + failures + skips
+        (fd, path) = tempfile.mkstemp(prefix="junit", suffix=".xml", dir=self.basedir, text=True)
+        stream = os.fdopen(fd, "w")
+        content = self.xml_template % dict(body=body, name=name, errors=errors,
+                failures=failures, skips=skips, tests=tests, time=time)
+        stream.write(content)
+        stream.close()
+        return path
+
+    def test_simple(self):
+        body = '<testcase classname="_test.test_event" name="test_simple" time="0.0002"></testcase>'
+        filename = self._xml_file(body, tests=1)
+        javatools.junit(self.ctxt, file_=filename)
+        type, category, generator, xml = self.ctxt.output.pop()
+        self.assertEqual('report', type)
+        self.assertEqual('test', category)
+        self.assertEqual(1, len(xml.children))
+
+        elem = xml.children[0]
+        self.assertEqual('test', elem.name)
+        self.assertEqual('test_simple', elem.attr['name'])
+        self.assertEqual('success', elem.attr['status'])
+        self.assertEqual(0, len(elem.children))
+
+    def test_setup_fail(self):
+        """Check that py.test setup failures are handled"""
+        body = '<testcase classname="_test.test_event" name="test_simple" time="0">' \
+             + '<error message="test setup failure">request = &lt;FuncargRequest for &lt;Function...</error>' \
+             + '</testcase>'
+        filename = self._xml_file(body, errors=1)
+        javatools.junit(self.ctxt, file_=filename)
+        type, category, generator, xml = self.ctxt.output.pop()
+        self.assertEqual('report', type)
+        self.assertEqual('test', category)
+        self.assertEqual(1, len(xml.children))
+
+        elem = xml.children[0]
+        self.assertEqual('test', elem.name)
+        self.assertEqual('test_simple', elem.attr['name'])
+        self.assertEqual('error', elem.attr['status'])
+        self.assertEqual(1, len(elem.children))
+
+        trace = elem.children[0]
+        self.assertEqual('traceback', trace.name)
+        self.assertEqual(1, len(trace.children))
+        self.assertEqual('request = <FuncargRequest for <Function...', trace.children[0])
 
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(CoberturaTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(PyTestTestCase, 'test'))
     return suite
 
 if __name__ == '__main__':
Copyright (C) 2012-2017 Edgewall Software