7 import xml.etree.ElementTree as ET
8 from datetime import datetime
11 aparser = argparse.ArgumentParser(
12 description='Convert Meson test log into JUnit report')
13 aparser.add_argument('--project-name', metavar='NAME',
14 help='The project name',
16 aparser.add_argument('--job-id', metavar='ID',
17 help='The job ID for the report',
19 aparser.add_argument('--branch', metavar='NAME',
20 help='Branch of the project being tested',
22 aparser.add_argument('--output', metavar='FILE',
23 help='The output file, stdout by default',
24 type=argparse.FileType('w', encoding='UTF-8'),
26 aparser.add_argument('infile', metavar='FILE',
27 help='The input testlog.json, stdin by default',
28 type=argparse.FileType('r', encoding='UTF-8'),
30 args = aparser.parse_args()
34 testsuites = ET.Element('testsuites')
35 testsuites.set('id', '{}/{}'.format(args.job_id, args.branch))
36 testsuites.set('package', args.project_name)
37 testsuites.set('timestamp', datetime.utcnow().isoformat(timespec='minutes'))
39 testsuite = ET.SubElement(testsuites, 'testsuite')
40 testsuite.set('name', args.project_name)
47 def escape_control_chars(text):
48 return "".join(c if unicodedata.category(c)[0] != "C" else
49 "<{:02x}>".format(ord(c)) for c in text)
52 for line in args.infile:
53 unit = json.loads(line)
55 testcase = ET.SubElement(testsuite, 'testcase')
56 testcase.set('classname', '{}/{}'.format(args.project_name, unit['name']))
57 testcase.set('name', unit['name'])
58 testcase.set('time', str(unit['duration']))
60 stdout = escape_control_chars(unit.get('stdout', ''))
61 stderr = escape_control_chars(unit.get('stderr', ''))
63 ET.SubElement(testcase, 'system-out').text = stdout
65 ET.SubElement(testcase, 'system-out').text = stderr
67 result = unit['result'].lower()
70 ET.SubElement(testcase, 'skipped')
71 elif result == 'fail':
73 failure = ET.SubElement(testcase, 'failure')
74 failure.set('message', "{} failed".format(unit['name']))
75 failure.text = "### stdout\n{}\n### stderr\n{}\n".format(stdout,
79 assert unit['returncode'] == 0
81 testsuite.set('tests', str(successes + failures + skips))
82 testsuite.set('skipped', str(skips))
83 testsuite.set('errors', str(failures))
84 testsuite.set('failures', str(failures))
86 print('{}: {} pass, {} fail, {} skip'.format(args.project_name,
91 output = ET.tostring(testsuites, encoding='unicode')