提交 8dad284b 编写于 作者: A Amador Pahim

avocado.core.xunit fix XUnit results fail XSD validation

The xunit plugin claims to be compatible with jenkins-ci junit-4.xsd,
but it does not pass on the validation dur to the wrong key name 'skip'.

This patch changes the key name to 'skipped' and adds a unittest to validate
the xunit output against the junit-4.xsd schema.

The junit-4.xsd file is coming from:
https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd

Reference: https://trello.com/c/ZdEb0TblSigned-off-by: NAmador Pahim <apahim@redhat.com>
上级 9caedc1b
......@@ -56,7 +56,7 @@ class XmlResult(object):
:param timestamp: Timestamp string in date/time format.
"""
self.testsuite = '<testsuite name="avocado" tests="{tests}" errors="{errors}" failures="{failures}" skip="{skip}" time="{total_time}" timestamp="%s">' % timestamp
self.testsuite = '<testsuite name="avocado" tests="{tests}" errors="{errors}" failures="{failures}" skipped="{skip}" time="{total_time}" timestamp="%s">' % timestamp
self.testcases = []
def end_testsuite(self, tests, errors, failures, skip, total_time):
......
......@@ -76,7 +76,7 @@ output in the standard output of the runner, simply use::
$ scripts/avocado --xunit - run "sleeptest failtest synctest"
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="avocado" tests="3" errors="0" failures="1" skip="0" time="2.88632893562" timestamp="2014-04-24 18:25:39.545588">
<testsuite name="avocado" tests="3" errors="0" failures="1" skipped="0" time="2.88632893562" timestamp="2014-04-24 18:25:39.545588">
<testcase classname="sleeptest" name="sleeptest.1" time="1.10091400146"/>
<testcase classname="failtest" name="failtest.1" time="0.0921177864075">
<failure><![CDATA[This test is supposed to fail]]></failure>
......@@ -135,7 +135,7 @@ stdout and the JSON result to output to a file::
$ scripts/avocado --xunit - --json /tmp/result.json run "sleeptest synctest"
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="avocado" tests="2" errors="0" failures="0" skip="0" time="3.21392536163" timestamp="2014-06-11 01:49:35.858187">
<testsuite name="avocado" tests="2" errors="0" failures="0" skipped="0" time="3.21392536163" timestamp="2014-06-11 01:49:35.858187">
<testcase classname="sleeptest" name="sleeptest.1" time="1.34533214569"/>
<testcase classname="synctest" name="synctest.1" time="1.86859321594"/>
</testsuite>
......
......@@ -24,3 +24,4 @@ aexpect>=1.0.0
psutil>=3.1.1
# stevedore for loading "new style" plugins
stevedore>=1.8.0
lxml>=3.4.4
......@@ -17,6 +17,7 @@ aexpect==1.0.0
psutil==3.1.1
# stevedore for loading "new style" plugins
stevedore==1.8.0
lxml>=3.4.4
# All python 2.6 specific requirements (backports)
argparse==1.3.0; python_version < '2.7'
logutils==0.3.3; python_version < '2.7'
......
......@@ -797,7 +797,7 @@ class PluginsXunitTest(AbsPluginsTest, unittest.TestCase):
"Unexpected number of test failures, "
"XML:\n%s" % xml_output)
n_skip = int(testsuite_tag.attributes['skip'].value)
n_skip = int(testsuite_tag.attributes['skipped'].value)
self.assertEqual(n_skip, e_nskip,
"Unexpected number of test skips, "
"XML:\n%s" % xml_output)
......
......@@ -93,7 +93,7 @@ class JobTimeOutTest(unittest.TestCase):
"Unexpected number of test failures, "
"XML:\n%s" % xml_output)
n_skip = int(testsuite_tag.attributes['skip'].value)
n_skip = int(testsuite_tag.attributes['skipped'].value)
self.assertEqual(n_skip, e_nskip,
"Unexpected number of test skips, "
"XML:\n%s" % xml_output)
......
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="failure">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string" use="optional"/>
<xs:attribute name="message" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="error">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string" use="optional"/>
<xs:attribute name="message" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="properties">
<xs:complexType>
<xs:sequence>
<xs:element ref="property" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="property">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="value" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="skipped" type="xs:string"/>
<xs:element name="system-err" type="xs:string"/>
<xs:element name="system-out" type="xs:string"/>
<xs:element name="testcase">
<xs:complexType>
<xs:sequence>
<xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
<xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="assertions" type="xs:string" use="optional"/>
<xs:attribute name="time" type="xs:string" use="optional"/>
<xs:attribute name="classname" type="xs:string" use="optional"/>
<xs:attribute name="status" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="testsuite">
<xs:complexType>
<xs:sequence>
<xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
<xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
<xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="tests" type="xs:string" use="required"/>
<xs:attribute name="failures" type="xs:string" use="optional"/>
<xs:attribute name="errors" type="xs:string" use="optional"/>
<xs:attribute name="time" type="xs:string" use="optional"/>
<xs:attribute name="disabled" type="xs:string" use="optional"/>
<xs:attribute name="skipped" type="xs:string" use="optional"/>
<xs:attribute name="timestamp" type="xs:string" use="optional"/>
<xs:attribute name="hostname" type="xs:string" use="optional"/>
<xs:attribute name="id" type="xs:string" use="optional"/>
<xs:attribute name="package" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="testsuites">
<xs:complexType>
<xs:sequence>
<xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="optional"/>
<xs:attribute name="time" type="xs:string" use="optional"/>
<xs:attribute name="tests" type="xs:string" use="optional"/>
<xs:attribute name="failures" type="xs:string" use="optional"/>
<xs:attribute name="disabled" type="xs:string" use="optional"/>
<xs:attribute name="errors" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:schema>
import argparse
import unittest
import os
from xml.dom import minidom
import tempfile
import shutil
import tempfile
import unittest
from lxml import etree
from StringIO import StringIO
from xml.dom import minidom
from avocado import Test
from avocado.core import xunit
......@@ -38,6 +40,8 @@ class xUnitSucceedTest(unittest.TestCase):
self.test1 = SimpleTest(job=job.Job(), base_logdir=self.tmpdir)
self.test1.status = 'PASS'
self.test1.time_elapsed = 1.23
unittests_path = os.path.dirname(os.path.abspath(__file__))
self.junit_schema_path = os.path.join(unittests_path, 'junit-4.xsd')
def tearDown(self):
os.close(self.tmpfile[0])
......@@ -59,6 +63,12 @@ class xUnitSucceedTest(unittest.TestCase):
els = dom.getElementsByTagName('testcase')
self.assertEqual(len(els), 1)
with open(self.junit_schema_path, 'r') as f:
xmlschema = etree.XMLSchema(etree.parse(f))
self.assertTrue(xmlschema.validate(etree.parse(StringIO(xml))),
"Failed to validate against %s, content:\n%s" %
(self.junit_schema_path, xml))
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册