[Piglit] [PATCH 8/9] backend/junit.py: Make writes atomic
Dylan Baker
baker.dylan.c at gmail.com
Tue Sep 23 17:55:55 PDT 2014
This patch similarly changes the junit backend to have atomic writes,
like the json backend.
Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
framework/backends/junit.py | 64 +++++++++++++++++++++++++++++----------
framework/programs/run.py | 4 ---
framework/tests/backends_tests.py | 23 ++++++++++++++
3 files changed, 71 insertions(+), 20 deletions(-)
diff --git a/framework/backends/junit.py b/framework/backends/junit.py
index 10f65b3..ed21471 100644
--- a/framework/backends/junit.py
+++ b/framework/backends/junit.py
@@ -23,6 +23,8 @@
import os
import re
import posixpath
+import itertools
+import shutil
try:
from lxml import etree
except ImportError:
@@ -43,25 +45,53 @@ class JUnitBackend(FSyncMixin, Backend):
"""
_REPLACE = re.compile(r'[/\\]')
- def __init__(self, dest, junit_test_suffix='', **options):
- self._file = open(os.path.join(dest, 'results.xml'), 'w')
+ def __init__(self, dest, junit_test_suffix='', start_count=0, **options):
FSyncMixin.__init__(self, **options)
+ self._dest = dest
self._test_suffix = junit_test_suffix
+ self._counter = itertools.count(start_count)
def initialize(self, metadata):
- # Write initial headers and other data that etree cannot write for us
- self._file.write('<?xml version="1.0" encoding="UTF-8" ?>\n')
- self._file.write('<testsuites>\n')
- self._file.write(
- '<testsuite name="piglit" tests="{}">\n'.format(
- metadata['test_count']))
- self._fsync(self._file)
+ """ Do nothing
+
+ Junit doesn't support restore, and doesn't have an initial metadata
+ block to write, so all this method does is create the tests directory
+
+ """
+ tests = os.path.join(self._dest, 'tests')
+ if os.path.exists(tests):
+ shutil.rmtree(tests)
+ os.mkdir(tests)
def finalize(self, metadata=None):
- self._file.write('</testsuite>\n')
- self._file.write('</testsuites>\n')
- self._fsync(self._file)
- self._file.close()
+ """ Scoop up all of the individual peices and put them together """
+ root = etree.Element('testsuites')
+ piglit = etree.Element('testsuite', name='piglit')
+ root.append(piglit)
+ for each in os.listdir(os.path.join(self._dest, 'tests')):
+ with open(os.path.join(self._dest, 'tests', each), 'r') as f:
+ # parse returns an element tree, and that's not what we want,
+ # we want the first (and only) Element node
+ # If the element cannot be properly parsed then consider it a
+ # failed transaction and ignore it.
+ try:
+ piglit.append(etree.parse(f).getroot())
+ except etree.XMLSyntaxError:
+ continue
+
+ # set the test count by counting the number of tests.
+ # This must be bytes or unicode
+ piglit.attrib['tests'] = str(len(piglit))
+
+ with open(os.path.join(self._dest, 'results.xml'), 'w') as f:
+ f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+ # lxml has a pretty print we want to use
+ if etree.__name__ == 'lxml.etree':
+ f.write(etree.tostring(root, pretty_print=True))
+ else:
+ f.write(etree.tostring(root))
+
+ shutil.rmtree(os.path.join(self._dest, 'tests'))
def write_test(self, name, data):
# Split the name of the test and the group (what junit refers to as
@@ -102,6 +132,8 @@ class JUnitBackend(FSyncMixin, Backend):
elif data['result'] == 'crash':
etree.SubElement(element, 'error')
- self._file.write(etree.tostring(element))
- self._file.write('\n')
- self._fsync(self._file)
+ t = os.path.join(self._dest, 'tests',
+ '{}.xml'.format(self._counter.next()))
+ with open(t, 'w') as f:
+ f.write(etree.tostring(element))
+ self._fsync(f)
diff --git a/framework/programs/run.py b/framework/programs/run.py
index 749fb07..e7ec65f 100644
--- a/framework/programs/run.py
+++ b/framework/programs/run.py
@@ -250,10 +250,6 @@ def run(input_):
options['platform'] = args.platform
options['name'] = results.name
options['env'] = core.collect_system_info()
- # FIXME: this should be the actual count, but profile needs to be
- # refactored to make that possible because of the flattening pass that is
- # part of profile.run
- options['test_count'] = 0
backend = backends.get_backend(args.backend)(
args.results_path,
diff --git a/framework/tests/backends_tests.py b/framework/tests/backends_tests.py
index d1b3d23..177225d 100644
--- a/framework/tests/backends_tests.py
+++ b/framework/tests/backends_tests.py
@@ -272,3 +272,26 @@ class TestJSONTestFinalize(utils.StaticDirectory):
test = json.load(f)
nt.assert_equal(baseline, test)
+
+
+def test_junit_skips_bad_tests():
+ """ backends.JUnitBackend skips illformed tests """
+ with utils.tempdir() as tdir:
+ test = backends.JUnitBackend(tdir)
+ test.initialize(BACKEND_INITIAL_META)
+ test.write_test(
+ 'a/test/group/test1',
+ results.TestResult({
+ 'time': 1.2345,
+ 'result': 'pass',
+ 'out': 'this is stdout',
+ 'err': 'this is stderr',
+ })
+ )
+ with open(os.path.join(tdir, 'tests', '1.xml'), 'w') as f:
+ f.write('bad data')
+
+ try:
+ test.finalize()
+ except etree.XMLSyntaxError as e:
+ raise AssertionError(e)
--
2.1.1
More information about the Piglit
mailing list