200 lines
7.2 KiB
Python
200 lines
7.2 KiB
Python
# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License, version 2.0,
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# This program is also distributed with certain software (including
|
|
# but not limited to OpenSSL) that is licensed under separate terms,
|
|
# as designated in a particular file or component or in included license
|
|
# documentation. The authors of MySQL hereby grant you an additional
|
|
# permission to link the program and your derivative works with the
|
|
# separately licensed software that they have included with MySQL.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License, version 2.0, for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
"""
|
|
XML Test Runner for PyUnit
|
|
"""
|
|
|
|
# Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
|
|
# the Public Domain. With contributions by Paolo Borelli and others.
|
|
# Modified by Dyre Tjeldvoll
|
|
|
|
__version__ = "0.0"
|
|
|
|
import sys
|
|
import time
|
|
import traceback
|
|
import socket
|
|
import platform
|
|
|
|
import unittest
|
|
if not hasattr(unittest, 'TextTestResult'):
|
|
import unittest2 as unittest
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
class XMLTestResult(unittest.TextTestResult):
|
|
def __init__(self, stream, descriptions, verbosity):
|
|
super(type(self), self).__init__(stream, descriptions, verbosity)
|
|
self._tb = ET.TreeBuilder()
|
|
self._ts = {}
|
|
self._tc = {}
|
|
|
|
def startTest(self, test):
|
|
"Called when the given test is about to be run"
|
|
super(type(self), self).startTest(test)
|
|
(c,m) = test.id().rsplit('.',1)
|
|
self._tc = { 'element': self._tb.start('testcase',
|
|
{'classname':c, 'name':m }),
|
|
'stime' : time.time() }
|
|
|
|
|
|
def startTestRun(self):
|
|
"""Called once before any tests are executed.
|
|
|
|
See startTest for a method called before each test.
|
|
"""
|
|
super(type(self), self).startTestRun()
|
|
self._ts = { 'element':
|
|
self._tb.start('testsuite',
|
|
{'hostname': socket.gethostname(),
|
|
'id':'0' }),
|
|
'stime': time.time() }
|
|
|
|
def _addOut(self, kind):
|
|
buf = getattr(self, '_std{0}_buffer'.format(kind))
|
|
if buf:
|
|
tag = 'system-{0}'.format(kind)
|
|
self._tb.start(tag, {})
|
|
self._tb.data(buf.getvalue())
|
|
self._tb.end(tag)
|
|
|
|
def stopTest(self, test):
|
|
"""Called when the given test has been run"""
|
|
# Need to do this before calling the inherited method, since
|
|
# that will clear the buffers
|
|
try:
|
|
try:
|
|
self._addOut('out')
|
|
self._addOut('err')
|
|
finally:
|
|
super(type(self), self).stopTest(test)
|
|
#print 'super().stopTest called'
|
|
|
|
self._tc['element'].set('time', str(time.time() - self._tc['stime']))
|
|
self._tb.end('testcase')
|
|
self._tc['element'] = None
|
|
self._tc['stime'] = None
|
|
except:
|
|
traceback.print_exc()
|
|
raise
|
|
|
|
def stopTestRun(self):
|
|
"""Called once after all tests are executed.
|
|
|
|
See stopTest for a method called after each test.
|
|
"""
|
|
#print 'Calling super().stopTestRun'
|
|
super(type(self), self).stopTestRun()
|
|
#print 'After super().stopTestRun'
|
|
self._ts['element'].set('errors',str(len(self.errors)))
|
|
# TODO - do we need to add unexpected successes here?
|
|
self._ts['element'].set('failures',str(len(self.failures)))
|
|
self._ts['element'].set('skipped',str(len(self.skipped)))
|
|
self._ts['element'].set('tests', str(self.testsRun))
|
|
self._ts['element'].set('time',str(time.time()-self._ts['stime']))
|
|
self._ts['element'].set('timestamp',str(time.localtime(time.time())))
|
|
|
|
self._tb.end('testsuite')
|
|
|
|
def _addEx(self, kind, excinf):
|
|
try:
|
|
self._tb.start(kind, {'message':str(excinf[1]),
|
|
'type':excinf[0].__name__})
|
|
self._tb.data(''.join(traceback.format_tb(excinf[2])))
|
|
self._tb.end(kind)
|
|
self._tc['element'].set('status', kind)
|
|
except:
|
|
traceback.print_exc()
|
|
raise
|
|
|
|
def addError(self, test, err):
|
|
"""Called when an error has occurred. 'err' is a tuple of values as
|
|
returned by sys.exc_info().
|
|
"""
|
|
super(type(self), self).addError(test, err)
|
|
self._addEx('error', err)
|
|
|
|
def addFailure(self, test, err):
|
|
"""Called when an error has occurred. 'err' is a tuple of values as
|
|
returned by sys.exc_info()."""
|
|
super(type(self), self).addFailure(test, err)
|
|
self._addEx('failure', err)
|
|
|
|
def addSuccess(self, test):
|
|
"Called when a test has completed successfully"
|
|
super(type(self), self).addSuccess(test)
|
|
self._tc['element'].set('status', 'success')
|
|
|
|
def addSkip(self, test, reason):
|
|
"""Called when a test is skipped."""
|
|
super(type(self), self).addSkip(test, reason)
|
|
self._tb.start('skipped', {})
|
|
self._tb.data(reason)
|
|
self._tb.end('skipped')
|
|
self._tc['element'].set('status', 'skipped because: {0}'.format(reason))
|
|
|
|
def addExpectedFailure(self, test, err):
|
|
"""Called when an expected failure/error occurred."""
|
|
super(type(self), self).addExpectedFailure(test, err)
|
|
# TODO - can we utilize this?
|
|
|
|
def addUnexpectedSuccess(self, test):
|
|
"""Called when a test was expected to fail, but succeed."""
|
|
super(type(self), self).addUnexpectedSuccess(test, err)
|
|
# TODO - can we utilize this?
|
|
|
|
|
|
###
|
|
def set_suite_name(self, suite):
|
|
self._ts['element'].set('name', suite.__class__.__name__)
|
|
if suite.__module__ != '__Main__':
|
|
self._ts['element'].set('package', suite.__module__)
|
|
|
|
def xml_str(self):
|
|
return ET.tostring(self._tb.close())
|
|
|
|
class XMLTestRunner(unittest.TextTestRunner):
|
|
def __init__(self, stream=sys.stderr, descriptions=True, verbosity=True,
|
|
failfast=False, buffer=True, resultclass=XMLTestResult):
|
|
super(type(self), self).__init__(stream, descriptions, verbosity,
|
|
failfast, True, resultclass)
|
|
|
|
def run(self, test):
|
|
XMLTestResult__ = None
|
|
junitrep = None
|
|
try:
|
|
XMLTestResult__ = super(type(self), self).run(test)
|
|
XMLTestResult__.set_suite_name(test)
|
|
xmlstr = XMLTestResult__.xml_str()
|
|
|
|
junitrep = open('junit_report_{0}.{1}.xml'.format(test.__module__, test.__class__.__name__),'w')
|
|
junitrep.write(xmlstr)
|
|
except:
|
|
traceback.print_exc()
|
|
XMLTestResult__.xml_str()
|
|
finally:
|
|
if junitrep:
|
|
junitrep.close()
|
|
|
|
return XMLTestResult__
|