Commit 9c416cdc authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Add missing scripts for CI reporting

parent 2d7b5f2d
Loading
Loading
Loading
Loading

util/junit_merge.py

0 → 100644
+92 −0
Original line number Diff line number Diff line
#
#   Copyright 2018 Dominik Sekotill <dom.sekotill@kodo.org.uk>
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
Simple jUnit XML merger
"""

from xml.etree import ElementTree as etree # ElementTree is a stupid module name


SUITE_METRICS = 'tests', 'failures', 'errors', 'skipped'


def merge(testsuites, tree, name_format=None):
	"""
	Merge a jUnit tree into a 'testsuites' element
	"""
	assert testsuites.tag == 'testsuites'
	total_metrics = get_suite_metrics(testsuites)

	for test_suite in get_suites(tree):
		testsuites.append(test_suite)
		metrics = get_suite_metrics(test_suite)
		for name in metrics:
			total_metrics[name] += metrics[name]
		if name_format:
			test_suite.set('name', name_format.format(test_suite.get('name')))

	for name, value in total_metrics.items():
		testsuites.set(name, str(value))


def get_suite_metrics(suite):
	"""
	Return a dict of the metric attributes of a test suite
	"""
	metrics = {name: int(suite.get(name, 0)) for name in SUITE_METRICS}
	metrics['time'] = float(suite.get('time', 0.0))

	if metrics['tests']:
		return metrics

	# No metric attributes: make some
	for testcase in suite.iter('testcase'):
		metrics['time'] += float(testcase.get('time', 0.0))
		metrics['tests'] += 1
		if testcase.find('failure'):
			metrics['failures'] += 1
		elif testcase.find('error'):
			metrics['errors'] += 1
		elif testcase.find('skipped'):
			metrics['skipped'] += 1

	for name, value in metrics.items():
		suite.set(name, str(value))

	return metrics

def get_suites(tree):
	root = tree.find('.')
	if root.tag == 'testsuite':
		return [root]
	return root.find('.//testsuite')


if __name__ == '__main__':
	import sys

	testsuites = etree.Element('testsuites')
	testsuites.text = '\n'  # .text & .tail are a deeply brain-dead design
	for arg in sys.argv[1:]:
		filename, *name_prefix = arg.split(':', 1)
		name_fmt = '{0[0]}: ({{}})'.format(name_prefix) if name_prefix else None
		tree = etree.parse(filename)
		merge(testsuites, tree, name_format=name_fmt)
		tree.getroot().tail = '\n'

	with open(1, 'wb') as stdout:
		( etree.ElementTree(testsuites)
			.write(stdout, encoding='UTF-8', xml_declaration=True) )