[PATCH RFC] run-tests: add support for xunit test reports
Augie Fackler
raf at durin42.com
Mon Jun 30 10:13:33 CDT 2014
# HG changeset patch
# User Augie Fackler <raf at durin42.com>
# Date 1403842355 14400
# Fri Jun 27 00:12:35 2014 -0400
# Node ID e783e767f540a61eeb877a5b307f1ad76d2d86a6
# Parent becb61de90a1a0384af535a393fb32e7da7a9059
run-tests: add support for xunit test reports
The Jenkins CI system understands xunit reports natively, so this will
be helpful for anyone that wants to use Jenkins for testing hg.
diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -52,6 +52,7 @@
import sys
import tempfile
import time
+import traceback
import random
import re
import threading
@@ -190,6 +191,8 @@
" (implies --keep-tmpdir)")
parser.add_option("-v", "--verbose", action="store_true",
help="output verbose messages")
+ parser.add_option("--xunit", type="string",
+ help="record xunit results at specified path")
parser.add_option("--view", type="string",
help="external diff viewer")
parser.add_option("--with-hg", type="string",
@@ -304,6 +307,24 @@
return log(*msg)
+
+# Bytes that break XML even in a CDATA block: control characters 0-31
+# sans \t, \n and \r
+CDATA_EVIL = re.compile(r"[\000-\010\013\014\016-\037]")
+
+def xmlsafe(data):
+ return CDATA_EVIL.sub('?', data).replace(']]>', ']]>]]><![CDATA[')
+
+allsuccess = []
+allfailures = {}
+def xunitfail(test, lines):
+ """Log a failure to the xunit output file if one is in use."""
+ allfailures[test.name] = xmlsafe(''.join(lines))
+
+allerrors = {}
+def xuniterr(test, err):
+ allerrors[test] = xmlsafe(err)
+
def log(*msg):
"""Log something to stdout.
@@ -1088,8 +1109,14 @@
self.stream.write('!')
- def addError(self, *args, **kwargs):
- super(TestResult, self).addError(*args, **kwargs)
+ def addSuccess(self, test):
+ super(TestResult, self).addSuccess(test)
+ allsuccess.append(test)
+
+ def addError(self, test, err):
+ super(TestResult, self).addError(test, err)
+ tb = traceback.format_exception(*err)
+ xuniterr(test, tb)
if self._options.first:
self.stop()
@@ -1130,6 +1157,8 @@
"""Record a mismatch in test output for a particular test."""
accepted = False
+ failed = False
+ lines = []
iolock.acquire()
if self._options.nodiff:
@@ -1157,7 +1186,8 @@
else:
rename(test.errpath, '%s.out' % test.path)
accepted = True
-
+ if not accepted and not failed:
+ xunitfail(test, lines)
iolock.release()
return accepted
@@ -1321,6 +1351,40 @@
for test, msg in result.errors:
self.stream.writeln('Errored %s: %s' % (test.name, msg))
+ if self._runner.options.xunit:
+ xuf = open(self._runner.options.xunit, 'wb')
+ try:
+ timesd = dict(result.times)
+ xuf.write(
+ '<?xml version="1.0" encoding="%(encoding)s"?>'
+ '<testsuite name="run-tests" tests="%(total)d" '
+ 'errors="%(errors)d" failures="%(failures)d" '
+ 'skip="%(skipped)d">\n' % {
+ 'total': result.testsRun,
+ 'encoding': 'utf-8',
+ 'failures': failed,
+ 'skipped': skipped + ignored,
+ 'errors': 0,
+ })
+ for tc in allsuccess:
+ xuf.write(' <testcase name="%(test)s" '
+ 'time="%(time).3f"></testcase>\n' % {
+ 'test': tc.name,
+ 'time': timesd[tc.name],
+ })
+ for tc, err in sorted(allfailures.iteritems()):
+ xuf.write(
+ ' <testcase name="%(test)s" time="%(time).3f">\n'
+ ' <failure><![CDATA[%(error)s]]>\n'
+ ' </failure>\n'
+ ' </testcase>\n' % {'test': tc,
+ 'error': err,
+ 'time': timesd[tc]
+ })
+ xuf.write('</testsuite>\n')
+ finally:
+ xuf.close()
+
self._runner._checkhglib('Tested')
# When '--retest' is enabled, only failure tests run. At this point
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -42,6 +42,36 @@
# Ran 2 tests, 0 skipped, 0 warned, 1 failed.
python hash seed: * (glob)
[1]
+test --xunit support
+ $ $TESTDIR/run-tests.py --with-hg=`which hg` --xunit=xunit.xml
+
+ --- $TESTTMP/test-failure.t
+ +++ $TESTTMP/test-failure.t.err
+ @@ -1,2 +1,2 @@
+ $ echo babar
+ - rataxes
+ + babar
+
+ ERROR: test-failure.t output changed
+ !.
+ Failed test-failure.t: output changed
+ # Ran 2 tests, 0 skipped, 0 warned, 1 failed.
+ python hash seed: * (glob)
+ [1]
+ $ cat xunit.xml
+ <?xml version="1.0" encoding="utf-8"?><testsuite name="run-tests" tests="2" errors="0" failures="1" skip="0">
+ <testcase name="test-success.t" time="*"></testcase> (glob)
+ <testcase name="test-failure.t" time="*"> (glob)
+ <failure><![CDATA[--- $TESTTMP/test-failure.t
+ +++ $TESTTMP/test-failure.t.err
+ @@ -1,2 +1,2 @@
+ $ echo babar
+ - rataxes
+ + babar
+ ]]>
+ </failure>
+ </testcase>
+ </testsuite>
test for --retest
====================
More information about the Mercurial-devel
mailing list