mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
Change: 'thread.setDaemon(val)' to 'thread.daemon = val' 'thread.isDaemon()' to 'thread.daemon' 'condition.notifyAll()' to 'condition.notify_all()' 'event.isSet()' to 'event.is_set()' GitOrigin-RevId: 76191fde184b407251303684cb85be9cfda3c7ae
325 lines
13 KiB
Python
325 lines
13 KiB
Python
'''
|
|
Entry point module (keep at root):
|
|
|
|
Used to run with tests with unittest/pytest/nose.
|
|
'''
|
|
|
|
|
|
import os
|
|
|
|
try:
|
|
xrange
|
|
except:
|
|
xrange = range
|
|
|
|
def main():
|
|
import sys
|
|
|
|
# Separate the nose params and the pydev params.
|
|
pydev_params = []
|
|
other_test_framework_params = []
|
|
found_other_test_framework_param = None
|
|
|
|
NOSE_PARAMS = '--nose-params'
|
|
PY_TEST_PARAMS = '--py-test-params'
|
|
|
|
for arg in sys.argv[1:]:
|
|
if not found_other_test_framework_param and arg != NOSE_PARAMS and arg != PY_TEST_PARAMS:
|
|
pydev_params.append(arg)
|
|
|
|
else:
|
|
if not found_other_test_framework_param:
|
|
found_other_test_framework_param = arg
|
|
else:
|
|
other_test_framework_params.append(arg)
|
|
|
|
try:
|
|
# Convert to the case stored in the filesystem
|
|
import win32api
|
|
def get_with_filesystem_case(f):
|
|
return win32api.GetLongPathName(win32api.GetShortPathName(f))
|
|
except:
|
|
def get_with_filesystem_case(f):
|
|
return f
|
|
|
|
# Here we'll run either with nose or with the pydev_runfiles.
|
|
from _pydev_runfiles import pydev_runfiles
|
|
from _pydev_runfiles import pydev_runfiles_xml_rpc
|
|
from _pydevd_bundle import pydevd_constants
|
|
from pydevd_file_utils import _NormFile
|
|
|
|
DEBUG = 0
|
|
if DEBUG:
|
|
sys.stdout.write('Received parameters: %s\n' % (sys.argv,))
|
|
sys.stdout.write('Params for pydev: %s\n' % (pydev_params,))
|
|
if found_other_test_framework_param:
|
|
sys.stdout.write('Params for test framework: %s, %s\n' % (found_other_test_framework_param, other_test_framework_params))
|
|
|
|
try:
|
|
configuration = pydev_runfiles.parse_cmdline([sys.argv[0]] + pydev_params)
|
|
except:
|
|
sys.stderr.write('Command line received: %s\n' % (sys.argv,))
|
|
raise
|
|
pydev_runfiles_xml_rpc.initialize_server(configuration.port) # Note that if the port is None, a Null server will be initialized.
|
|
|
|
NOSE_FRAMEWORK = 1
|
|
PY_TEST_FRAMEWORK = 2
|
|
try:
|
|
if found_other_test_framework_param:
|
|
test_framework = 0 # Default (pydev)
|
|
if found_other_test_framework_param == NOSE_PARAMS:
|
|
import nose
|
|
test_framework = NOSE_FRAMEWORK
|
|
|
|
elif found_other_test_framework_param == PY_TEST_PARAMS:
|
|
import pytest
|
|
test_framework = PY_TEST_FRAMEWORK
|
|
|
|
else:
|
|
raise ImportError('Test framework: %s not supported.' % (found_other_test_framework_param,))
|
|
|
|
else:
|
|
raise ImportError()
|
|
|
|
except ImportError:
|
|
if found_other_test_framework_param:
|
|
raise
|
|
|
|
test_framework = None
|
|
|
|
# Clear any exception that may be there so that clients don't see it.
|
|
# See: https://sourceforge.net/tracker/?func=detail&aid=3408057&group_id=85796&atid=577329
|
|
if hasattr(sys, 'exc_clear'):
|
|
sys.exc_clear()
|
|
|
|
if test_framework == 0:
|
|
|
|
return pydev_runfiles.main(configuration) # Note: still doesn't return a proper value.
|
|
|
|
else:
|
|
# We'll convert the parameters to what nose or py.test expects.
|
|
# The supported parameters are:
|
|
# runfiles.py --config-file|-t|--tests <Test.test1,Test2> dirs|files --nose-params xxx yyy zzz
|
|
# (all after --nose-params should be passed directly to nose)
|
|
|
|
# In java:
|
|
# --tests = Constants.ATTR_UNITTEST_TESTS
|
|
# --config-file = Constants.ATTR_UNITTEST_CONFIGURATION_FILE
|
|
|
|
|
|
# The only thing actually handled here are the tests that we want to run, which we'll
|
|
# handle and pass as what the test framework expects.
|
|
|
|
py_test_accept_filter = {}
|
|
files_to_tests = configuration.files_to_tests
|
|
|
|
if files_to_tests:
|
|
# Handling through the file contents (file where each line is a test)
|
|
files_or_dirs = []
|
|
for file, tests in files_to_tests.items():
|
|
if test_framework == NOSE_FRAMEWORK:
|
|
for test in tests:
|
|
files_or_dirs.append(file + ':' + test)
|
|
|
|
elif test_framework == PY_TEST_FRAMEWORK:
|
|
file = _NormFile(file)
|
|
py_test_accept_filter[file] = tests
|
|
files_or_dirs.append(file)
|
|
|
|
else:
|
|
raise AssertionError('Cannot handle test framework: %s at this point.' % (test_framework,))
|
|
|
|
else:
|
|
if configuration.tests:
|
|
# Tests passed (works together with the files_or_dirs)
|
|
files_or_dirs = []
|
|
for file in configuration.files_or_dirs:
|
|
if test_framework == NOSE_FRAMEWORK:
|
|
for t in configuration.tests:
|
|
files_or_dirs.append(file + ':' + t)
|
|
|
|
elif test_framework == PY_TEST_FRAMEWORK:
|
|
file = _NormFile(file)
|
|
py_test_accept_filter[file] = configuration.tests
|
|
files_or_dirs.append(file)
|
|
|
|
else:
|
|
raise AssertionError('Cannot handle test framework: %s at this point.' % (test_framework,))
|
|
else:
|
|
# Only files or dirs passed (let it do the test-loading based on those paths)
|
|
files_or_dirs = configuration.files_or_dirs
|
|
|
|
argv = other_test_framework_params + files_or_dirs
|
|
|
|
|
|
if test_framework == NOSE_FRAMEWORK:
|
|
# Nose usage: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html
|
|
# show_stdout_option = ['-s']
|
|
# processes_option = ['--processes=2']
|
|
argv.insert(0, sys.argv[0])
|
|
if DEBUG:
|
|
sys.stdout.write('Final test framework args: %s\n' % (argv[1:],))
|
|
|
|
from _pydev_runfiles import pydev_runfiles_nose
|
|
PYDEV_NOSE_PLUGIN_SINGLETON = pydev_runfiles_nose.start_pydev_nose_plugin_singleton(configuration)
|
|
argv.append('--with-pydevplugin')
|
|
# Return 'not' because it will return 'success' (so, exit == 0 if success)
|
|
return not nose.run(argv=argv, addplugins=[PYDEV_NOSE_PLUGIN_SINGLETON])
|
|
|
|
elif test_framework == PY_TEST_FRAMEWORK:
|
|
|
|
if '--coverage_output_dir' in pydev_params and '--coverage_include' in pydev_params:
|
|
coverage_output_dir = pydev_params[pydev_params.index('--coverage_output_dir') + 1]
|
|
coverage_include = pydev_params[pydev_params.index('--coverage_include') + 1]
|
|
try:
|
|
import pytest_cov
|
|
except ImportError:
|
|
sys.stderr.write('To do a coverage run with pytest the pytest-cov library is needed (i.e.: pip install pytest-cov).\n\n')
|
|
raise
|
|
|
|
argv.insert(0, '--cov-append')
|
|
argv.insert(1, '--cov-report=')
|
|
argv.insert(2, '--cov=%s' % (coverage_include,))
|
|
|
|
import time
|
|
os.environ['COVERAGE_FILE'] = os.path.join(coverage_output_dir, '.coverage.%s' % (time.time(),))
|
|
|
|
if DEBUG:
|
|
sys.stdout.write('Final test framework args: %s\n' % (argv,))
|
|
sys.stdout.write('py_test_accept_filter: %s\n' % (py_test_accept_filter,))
|
|
|
|
def dotted(p):
|
|
# Helper to convert path to have dots instead of slashes
|
|
return os.path.normpath(p).replace(os.sep, "/").replace('/', '.')
|
|
|
|
curr_dir = os.path.realpath('.')
|
|
curr_dotted = dotted(curr_dir) + '.'
|
|
|
|
# Overcome limitation on py.test:
|
|
# When searching conftest if we have a structure as:
|
|
# /my_package
|
|
# /my_package/conftest.py
|
|
# /my_package/tests
|
|
# /my_package/tests/test_my_package.py
|
|
# The test_my_package won't have access to the conftest contents from the
|
|
# test_my_package.py file unless the working dir is set to /my_package.
|
|
#
|
|
# See related issue (for which we work-around below):
|
|
# https://bitbucket.org/hpk42/pytest/issue/639/conftest-being-loaded-twice-giving
|
|
|
|
for path in sys.path:
|
|
path_dotted = dotted(path)
|
|
if curr_dotted.startswith(path_dotted):
|
|
os.chdir(path)
|
|
break
|
|
|
|
remove = []
|
|
for i in xrange(len(argv)):
|
|
arg = argv[i]
|
|
# Workaround bug in py.test: if we pass the full path it ends up importing conftest
|
|
# more than once (so, always work with relative paths).
|
|
if os.path.isfile(arg) or os.path.isdir(arg):
|
|
|
|
# Args must be passed with the proper case in the filesystem (otherwise
|
|
# python itself may not recognize it).
|
|
arg = get_with_filesystem_case(arg)
|
|
argv[i] = arg
|
|
|
|
from os.path import relpath
|
|
try:
|
|
# May fail if on different drives
|
|
arg = relpath(arg)
|
|
except ValueError:
|
|
pass
|
|
else:
|
|
argv[i] = arg
|
|
elif '<unable to get>' in arg:
|
|
remove.append(i)
|
|
|
|
for i in reversed(remove):
|
|
del argv[i]
|
|
|
|
# To find our runfile helpers (i.e.: plugin)...
|
|
d = os.path.dirname(__file__)
|
|
if d not in sys.path:
|
|
sys.path.insert(0, d)
|
|
|
|
import pickle, zlib, base64
|
|
|
|
# Update environment PYTHONPATH so that it finds our plugin if using xdist.
|
|
os.environ['PYTHONPATH'] = os.pathsep.join(sys.path)
|
|
|
|
# Set what should be skipped in the plugin through an environment variable
|
|
s = base64.b64encode(zlib.compress(pickle.dumps(py_test_accept_filter)))
|
|
if pydevd_constants.IS_PY3K:
|
|
s = s.decode('ascii') # Must be str in py3.
|
|
os.environ['PYDEV_PYTEST_SKIP'] = s
|
|
|
|
# Identifies the main pid (i.e.: if it's not the main pid it has to connect back to the
|
|
# main pid to give xml-rpc notifications).
|
|
os.environ['PYDEV_MAIN_PID'] = str(os.getpid())
|
|
os.environ['PYDEV_PYTEST_SERVER'] = str(configuration.port)
|
|
|
|
argv.append('-p')
|
|
argv.append('_pydev_runfiles.pydev_runfiles_pytest2')
|
|
if 'unittest' in sys.modules or 'unittest2' in sys.modules:
|
|
sys.stderr.write('pydev test runner error: imported unittest before running pytest.main\n')
|
|
return pytest.main(argv)
|
|
|
|
else:
|
|
raise AssertionError('Cannot handle test framework: %s at this point.' % (test_framework,))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
main()
|
|
finally:
|
|
try:
|
|
# The server is not a daemon thread, so, we have to ask for it to be killed!
|
|
from _pydev_runfiles import pydev_runfiles_xml_rpc
|
|
pydev_runfiles_xml_rpc.force_server_kill()
|
|
except:
|
|
pass # Ignore any errors here
|
|
|
|
import sys
|
|
import threading
|
|
if hasattr(sys, '_current_frames') and hasattr(threading, 'enumerate'):
|
|
import time
|
|
import traceback
|
|
|
|
class DumpThreads(threading.Thread):
|
|
def run(self):
|
|
time.sleep(10)
|
|
|
|
thread_id_to_name = {}
|
|
try:
|
|
for t in threading.enumerate():
|
|
thread_id_to_name[t.ident] = '%s (daemon: %s)' % (t.name, t.daemon)
|
|
except:
|
|
pass
|
|
|
|
stack_trace = [
|
|
'===============================================================================',
|
|
'pydev pyunit runner: Threads still found running after tests finished',
|
|
'================================= Thread Dump =================================']
|
|
|
|
for thread_id, stack in sys._current_frames().items():
|
|
stack_trace.append('\n-------------------------------------------------------------------------------')
|
|
stack_trace.append(" Thread %s" % thread_id_to_name.get(thread_id, thread_id))
|
|
stack_trace.append('')
|
|
|
|
if 'self' in stack.f_locals:
|
|
sys.stderr.write(str(stack.f_locals['self']) + '\n')
|
|
|
|
for filename, lineno, name, line in traceback.extract_stack(stack):
|
|
stack_trace.append(' File "%s", line %d, in %s' % (filename, lineno, name))
|
|
if line:
|
|
stack_trace.append(" %s" % (line.strip()))
|
|
stack_trace.append('\n=============================== END Thread Dump ===============================')
|
|
sys.stderr.write('\n'.join(stack_trace))
|
|
|
|
|
|
dump_current_frames_thread = DumpThreads()
|
|
dump_current_frames_thread.daemon = True # Daemon so that this thread doesn't halt it!
|
|
dump_current_frames_thread.start()
|