summaryrefslogtreecommitdiff
path: root/python/helpers/pydev/pydev_runfiles_nose.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/helpers/pydev/pydev_runfiles_nose.py')
-rw-r--r--python/helpers/pydev/pydev_runfiles_nose.py180
1 files changed, 180 insertions, 0 deletions
diff --git a/python/helpers/pydev/pydev_runfiles_nose.py b/python/helpers/pydev/pydev_runfiles_nose.py
new file mode 100644
index 000000000000..422d2a62a83a
--- /dev/null
+++ b/python/helpers/pydev/pydev_runfiles_nose.py
@@ -0,0 +1,180 @@
+from nose.plugins.multiprocess import MultiProcessTestRunner # @UnresolvedImport
+from nose.plugins.base import Plugin # @UnresolvedImport
+import sys
+import pydev_runfiles_xml_rpc
+import time
+from pydev_runfiles_coverage import StartCoverageSupport
+
+#=======================================================================================================================
+# PydevPlugin
+#=======================================================================================================================
+class PydevPlugin(Plugin):
+
+ def __init__(self, configuration):
+ self.configuration = configuration
+ Plugin.__init__(self)
+
+
+ def begin(self):
+ # Called before any test is run (it's always called, with multiprocess or not)
+ self.start_time = time.time()
+ self.coverage_files, self.coverage = StartCoverageSupport(self.configuration)
+
+
+ def finalize(self, result):
+ # Called after all tests are run (it's always called, with multiprocess or not)
+ self.coverage.stop()
+ self.coverage.save()
+
+ pydev_runfiles_xml_rpc.notifyTestRunFinished('Finished in: %.2f secs.' % (time.time() - self.start_time,))
+
+
+
+ #===================================================================================================================
+ # Methods below are not called with multiprocess (so, we monkey-patch MultiProcessTestRunner.consolidate
+ # so that they're called, but unfortunately we loose some info -- i.e.: the time for each test in this
+ # process).
+ #===================================================================================================================
+
+
+ def reportCond(self, cond, test, captured_output, error=''):
+ '''
+ @param cond: fail, error, ok
+ '''
+
+ # test.address() is something as:
+ # ('D:\\workspaces\\temp\\test_workspace\\pytesting1\\src\\mod1\\hello.py', 'mod1.hello', 'TestCase.testMet1')
+ #
+ # and we must pass: location, test
+ # E.g.: ['D:\\src\\mod1\\hello.py', 'TestCase.testMet1']
+ try:
+ if hasattr(test, 'address'):
+ address = test.address()
+ address = address[0], address[2]
+ else:
+ # multiprocess
+ try:
+ address = test[0], test[1]
+ except TypeError:
+ # It may be an error at setup, in which case it's not really a test, but a Context object.
+ f = test.context.__file__
+ if f.endswith('.pyc'):
+ f = f[:-1]
+ address = f, '?'
+ except:
+ sys.stderr.write("PyDev: Internal pydev error getting test address. Please report at the pydev bug tracker\n")
+ import traceback;traceback.print_exc()
+ sys.stderr.write("\n\n\n")
+ address = '?', '?'
+
+ error_contents = self.getIoFromError(error)
+ try:
+ time_str = '%.2f' % (time.time() - test._pydev_start_time)
+ except:
+ time_str = '?'
+
+ pydev_runfiles_xml_rpc.notifyTest(cond, captured_output, error_contents, address[0], address[1], time_str)
+
+
+ def startTest(self, test):
+ test._pydev_start_time = time.time()
+ if hasattr(test, 'address'):
+ address = test.address()
+ file, test = address[0], address[2]
+ else:
+ # multiprocess
+ file, test = test
+ pydev_runfiles_xml_rpc.notifyStartTest(file, test)
+
+
+ def getIoFromError(self, err):
+ if type(err) == type(()):
+ if len(err) != 3:
+ if len(err) == 2:
+ return err[1] # multiprocess
+ try:
+ from StringIO import StringIO
+ except:
+ from io import StringIO
+ s = StringIO()
+ etype, value, tb = err
+ import traceback;traceback.print_exception(etype, value, tb, file=s)
+ return s.getvalue()
+ return err
+
+
+ def getCapturedOutput(self, test):
+ if hasattr(test, 'capturedOutput') and test.capturedOutput:
+ return test.capturedOutput
+ return ''
+
+
+ def addError(self, test, err):
+ self.reportCond(
+ 'error',
+ test,
+ self.getCapturedOutput(test),
+ err,
+ )
+
+
+ def addFailure(self, test, err):
+ self.reportCond(
+ 'fail',
+ test,
+ self.getCapturedOutput(test),
+ err,
+ )
+
+
+ def addSuccess(self, test):
+ self.reportCond(
+ 'ok',
+ test,
+ self.getCapturedOutput(test),
+ '',
+ )
+
+
+PYDEV_NOSE_PLUGIN_SINGLETON = None
+def StartPydevNosePluginSingleton(configuration):
+ global PYDEV_NOSE_PLUGIN_SINGLETON
+ PYDEV_NOSE_PLUGIN_SINGLETON = PydevPlugin(configuration)
+ return PYDEV_NOSE_PLUGIN_SINGLETON
+
+
+
+
+original = MultiProcessTestRunner.consolidate
+#=======================================================================================================================
+# NewConsolidate
+#=======================================================================================================================
+def NewConsolidate(self, result, batch_result):
+ '''
+ Used so that it can work with the multiprocess plugin.
+ Monkeypatched because nose seems a bit unsupported at this time (ideally
+ the plugin would have this support by default).
+ '''
+ ret = original(self, result, batch_result)
+
+ parent_frame = sys._getframe().f_back
+ # addr is something as D:\pytesting1\src\mod1\hello.py:TestCase.testMet4
+ # so, convert it to what reportCond expects
+ addr = parent_frame.f_locals['addr']
+ i = addr.rindex(':')
+ addr = [addr[:i], addr[i + 1:]]
+
+ output, testsRun, failures, errors, errorClasses = batch_result
+ if failures or errors:
+ for failure in failures:
+ PYDEV_NOSE_PLUGIN_SINGLETON.reportCond('fail', addr, output, failure)
+
+ for error in errors:
+ PYDEV_NOSE_PLUGIN_SINGLETON.reportCond('error', addr, output, error)
+ else:
+ PYDEV_NOSE_PLUGIN_SINGLETON.reportCond('ok', addr, output)
+
+
+ return ret
+
+MultiProcessTestRunner.consolidate = NewConsolidate