Toyomasa Watarai / simple-mbed-cloud-client

Dependents:  

Committer:
MACRUM
Date:
Mon Jul 02 06:30:39 2018 +0000
Revision:
0:276e7a263c35
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MACRUM 0:276e7a263c35 1 #!/usr/bin/env python
MACRUM 0:276e7a263c35 2 import argparse
MACRUM 0:276e7a263c35 3 import logging
MACRUM 0:276e7a263c35 4 import string
MACRUM 0:276e7a263c35 5 import subprocess
MACRUM 0:276e7a263c35 6 import sys
MACRUM 0:276e7a263c35 7 import time
MACRUM 0:276e7a263c35 8 import xml.etree.cElementTree as ElementTree
MACRUM 0:276e7a263c35 9 from io import BytesIO
MACRUM 0:276e7a263c35 10 from threading import Thread
MACRUM 0:276e7a263c35 11
MACRUM 0:276e7a263c35 12 logger = logging.getLogger('ta-junit-wrapper')
MACRUM 0:276e7a263c35 13
MACRUM 0:276e7a263c35 14
MACRUM 0:276e7a263c35 15 class TeeBytesIO(BytesIO):
MACRUM 0:276e7a263c35 16 """duplicate each write command to an additional file object"""
MACRUM 0:276e7a263c35 17 def __init__(self, tee_fh):
MACRUM 0:276e7a263c35 18 self.tee_fh = tee_fh
MACRUM 0:276e7a263c35 19 super(TeeBytesIO, self).__init__()
MACRUM 0:276e7a263c35 20
MACRUM 0:276e7a263c35 21 def write(self, s):
MACRUM 0:276e7a263c35 22 self.tee_fh.write(s)
MACRUM 0:276e7a263c35 23 BytesIO.write(self, s)
MACRUM 0:276e7a263c35 24
MACRUM 0:276e7a263c35 25
MACRUM 0:276e7a263c35 26 def get_parser():
MACRUM 0:276e7a263c35 27 parser = argparse.ArgumentParser(description='JUNIT wrapper')
MACRUM 0:276e7a263c35 28
MACRUM 0:276e7a263c35 29 parser.add_argument(
MACRUM 0:276e7a263c35 30 '-o',
MACRUM 0:276e7a263c35 31 '--output-file',
MACRUM 0:276e7a263c35 32 metavar='FILE',
MACRUM 0:276e7a263c35 33 type=argparse.FileType('w'),
MACRUM 0:276e7a263c35 34 help='output JUNIT XML file name',
MACRUM 0:276e7a263c35 35 required=True
MACRUM 0:276e7a263c35 36 )
MACRUM 0:276e7a263c35 37
MACRUM 0:276e7a263c35 38 parser.add_argument(
MACRUM 0:276e7a263c35 39 '-s',
MACRUM 0:276e7a263c35 40 '--test-suite',
MACRUM 0:276e7a263c35 41 metavar='NAME',
MACRUM 0:276e7a263c35 42 help='test suite name',
MACRUM 0:276e7a263c35 43 required=True
MACRUM 0:276e7a263c35 44 )
MACRUM 0:276e7a263c35 45
MACRUM 0:276e7a263c35 46 parser.add_argument(
MACRUM 0:276e7a263c35 47 '-t',
MACRUM 0:276e7a263c35 48 '--test-case',
MACRUM 0:276e7a263c35 49 metavar='NAME',
MACRUM 0:276e7a263c35 50 help='test case name',
MACRUM 0:276e7a263c35 51 required=True
MACRUM 0:276e7a263c35 52 )
MACRUM 0:276e7a263c35 53
MACRUM 0:276e7a263c35 54 parser.add_argument(
MACRUM 0:276e7a263c35 55 '-v',
MACRUM 0:276e7a263c35 56 '--verbose',
MACRUM 0:276e7a263c35 57 action='store_true',
MACRUM 0:276e7a263c35 58 help='verbose - duplicate command output to STDOUT'
MACRUM 0:276e7a263c35 59 )
MACRUM 0:276e7a263c35 60
MACRUM 0:276e7a263c35 61 parser.add_argument(
MACRUM 0:276e7a263c35 62 '--validate',
MACRUM 0:276e7a263c35 63 action='store_true',
MACRUM 0:276e7a263c35 64 help='validate generated XML against Jenkins XSD. Requires "requests" and "lxml" libraries'
MACRUM 0:276e7a263c35 65 )
MACRUM 0:276e7a263c35 66
MACRUM 0:276e7a263c35 67 parser.add_argument(
MACRUM 0:276e7a263c35 68 '--command',
MACRUM 0:276e7a263c35 69 nargs=argparse.REMAINDER,
MACRUM 0:276e7a263c35 70 help='command to be executed'
MACRUM 0:276e7a263c35 71 )
MACRUM 0:276e7a263c35 72 return parser
MACRUM 0:276e7a263c35 73
MACRUM 0:276e7a263c35 74
MACRUM 0:276e7a263c35 75 def get_file_copy_worker(infile, outfile):
MACRUM 0:276e7a263c35 76 def do_work(_infile, _outfile):
MACRUM 0:276e7a263c35 77 for line in iter(_infile.readline, ''):
MACRUM 0:276e7a263c35 78 _outfile.write(line)
MACRUM 0:276e7a263c35 79 _infile.close()
MACRUM 0:276e7a263c35 80 thread = Thread(target=do_work, args=(infile, outfile))
MACRUM 0:276e7a263c35 81 thread.daemon = True
MACRUM 0:276e7a263c35 82 thread.start()
MACRUM 0:276e7a263c35 83 return thread
MACRUM 0:276e7a263c35 84
MACRUM 0:276e7a263c35 85
MACRUM 0:276e7a263c35 86 def generate_junit_xml(test_suite, test_case, out_fh, stdout, stderr, return_code, duration_in_sec, command):
MACRUM 0:276e7a263c35 87 test_suite_root_element = ElementTree.Element(
MACRUM 0:276e7a263c35 88 'testsuite',
MACRUM 0:276e7a263c35 89 tests='1',
MACRUM 0:276e7a263c35 90 name=test_suite.replace(' ', '_'),
MACRUM 0:276e7a263c35 91 failures=str(1 if return_code != 0 else 0),
MACRUM 0:276e7a263c35 92 time=str(duration_in_sec)
MACRUM 0:276e7a263c35 93 )
MACRUM 0:276e7a263c35 94 test_case_element = ElementTree.SubElement(
MACRUM 0:276e7a263c35 95 test_suite_root_element,
MACRUM 0:276e7a263c35 96 'testcase',
MACRUM 0:276e7a263c35 97 time=str(duration_in_sec),
MACRUM 0:276e7a263c35 98 name=test_case.replace(' ', '_')
MACRUM 0:276e7a263c35 99 )
MACRUM 0:276e7a263c35 100 ElementTree.SubElement(test_case_element, 'system-out').text = filter(
MACRUM 0:276e7a263c35 101 lambda x: x in string.printable, stdout.getvalue()
MACRUM 0:276e7a263c35 102 )
MACRUM 0:276e7a263c35 103 ElementTree.SubElement(test_case_element, 'system-err').text = filter(
MACRUM 0:276e7a263c35 104 lambda x: x in string.printable, stderr.getvalue()
MACRUM 0:276e7a263c35 105 )
MACRUM 0:276e7a263c35 106
MACRUM 0:276e7a263c35 107 if return_code != 0:
MACRUM 0:276e7a263c35 108 failure_msg = 'Command "{cmd}" returned {ret}'.format(cmd=command, ret=return_code)
MACRUM 0:276e7a263c35 109 ElementTree.SubElement(
MACRUM 0:276e7a263c35 110 test_case_element,
MACRUM 0:276e7a263c35 111 'failure',
MACRUM 0:276e7a263c35 112 type='Non-Zero return code',
MACRUM 0:276e7a263c35 113 message=failure_msg)
MACRUM 0:276e7a263c35 114
MACRUM 0:276e7a263c35 115 ElementTree.ElementTree(test_suite_root_element).write(out_fh)
MACRUM 0:276e7a263c35 116
MACRUM 0:276e7a263c35 117
MACRUM 0:276e7a263c35 118 def main():
MACRUM 0:276e7a263c35 119 parser = get_parser()
MACRUM 0:276e7a263c35 120 args = parser.parse_args()
MACRUM 0:276e7a263c35 121 logging.basicConfig(
MACRUM 0:276e7a263c35 122 level=logging.DEBUG if args.verbose else logging.INFO,
MACRUM 0:276e7a263c35 123 format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
MACRUM 0:276e7a263c35 124 stream=sys.stdout
MACRUM 0:276e7a263c35 125 )
MACRUM 0:276e7a263c35 126
MACRUM 0:276e7a263c35 127 stdout = TeeBytesIO(sys.stdout) if args.verbose else BytesIO()
MACRUM 0:276e7a263c35 128 stderr = TeeBytesIO(stdout)
MACRUM 0:276e7a263c35 129 logger.debug('Executing + ' + ' '.join(args.command))
MACRUM 0:276e7a263c35 130 start_time = time.time()
MACRUM 0:276e7a263c35 131 process = subprocess.Popen(args.command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
MACRUM 0:276e7a263c35 132 threads = [
MACRUM 0:276e7a263c35 133 get_file_copy_worker(process.stdout, stdout),
MACRUM 0:276e7a263c35 134 get_file_copy_worker(process.stderr, stderr)
MACRUM 0:276e7a263c35 135 ]
MACRUM 0:276e7a263c35 136 for t in threads: # wait for IO completion
MACRUM 0:276e7a263c35 137 t.join()
MACRUM 0:276e7a263c35 138 return_code = process.wait()
MACRUM 0:276e7a263c35 139 logger.debug('Wrapped process return code ' + str(return_code))
MACRUM 0:276e7a263c35 140 duration_in_sec = time.time() - start_time
MACRUM 0:276e7a263c35 141
MACRUM 0:276e7a263c35 142 with args.output_file as fh: # insure file object is closed - since it will be read in do_validate()
MACRUM 0:276e7a263c35 143 generate_junit_xml(
MACRUM 0:276e7a263c35 144 args.test_suite,
MACRUM 0:276e7a263c35 145 args.test_case,
MACRUM 0:276e7a263c35 146 fh,
MACRUM 0:276e7a263c35 147 stdout,
MACRUM 0:276e7a263c35 148 stderr,
MACRUM 0:276e7a263c35 149 return_code,
MACRUM 0:276e7a263c35 150 duration_in_sec,
MACRUM 0:276e7a263c35 151 args.command
MACRUM 0:276e7a263c35 152 )
MACRUM 0:276e7a263c35 153 logger.debug('Generated JUNIT report file ' + args.output_file.name)
MACRUM 0:276e7a263c35 154
MACRUM 0:276e7a263c35 155 if args.validate:
MACRUM 0:276e7a263c35 156 do_validate(args.output_file.name)
MACRUM 0:276e7a263c35 157
MACRUM 0:276e7a263c35 158 raise SystemExit(return_code)
MACRUM 0:276e7a263c35 159
MACRUM 0:276e7a263c35 160 if __name__ == '__main__':
MACRUM 0:276e7a263c35 161 main()