test_import_patched_defaults bended to play with pyopenssl>=16.1.0

Basically this patch replaces urllib with custom module that is guaranteed not imported before patching.
https://github.com/eventlet/eventlet/issues/362

More general issue here https://github.com/eventlet/eventlet/issues/368
This commit is contained in:
Sergey Shepelev
2016-12-30 06:54:11 +03:00
parent 79292bd16a
commit b7b357189d
9 changed files with 70 additions and 44 deletions

View File

@@ -302,16 +302,23 @@ def get_database_auth():
return retval
def run_python(path, env=None, args=None, timeout=None):
def run_python(path, env=None, args=None, timeout=None, pythonpath_extend=None, expect_pass=False):
new_argv = [sys.executable]
new_env = os.environ.copy()
new_env.setdefault('eventlet_test_in_progress', 'yes')
src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if path:
path = os.path.abspath(path)
new_argv.append(path)
src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
new_env['PYTHONPATH'] = os.pathsep.join(sys.path + [src_dir])
if env:
new_env.update(env)
if pythonpath_extend:
new_path = [p for p in new_env.get('PYTHONPATH', '').split(os.pathsep) if p]
new_path.extend(
p if os.path.isabs(p) else os.path.join(src_dir, p) for p in pythonpath_extend
)
new_env['PYTHONPATH'] = os.pathsep.join(new_path)
if args:
new_argv.extend(args)
p = subprocess.Popen(
@@ -329,21 +336,25 @@ def run_python(path, env=None, args=None, timeout=None):
p.kill()
output, _ = p.communicate(timeout=timeout)
return '{0}\nFAIL - timed out'.format(output).encode()
if expect_pass:
if output.startswith(b'skip'):
parts = output.rstrip().split(b':', 1)
skip_args = []
if len(parts) > 1:
skip_args.append(parts[1])
raise SkipTest(*skip_args)
ok = output.rstrip() == b'pass'
if not ok:
sys.stderr.write('Program {0} output:\n---\n{1}\n---\n'.format(path, output.decode()))
assert ok, 'Expected single line "pass" in stdout'
return output
def run_isolated(path, prefix='tests/isolated/', env=None, args=None, timeout=None):
output = run_python(prefix + path, env=env, args=args, timeout=timeout).rstrip()
if output.startswith(b'skip'):
parts = output.split(b':', 1)
skip_args = []
if len(parts) > 1:
skip_args.append(parts[1])
raise SkipTest(*skip_args)
ok = output == b'pass'
if not ok:
sys.stderr.write('Isolated test {0} output:\n---\n{1}\n---\n'.format(path, output.decode()))
assert ok, 'Expected single line "pass" in stdout'
def run_isolated(path, prefix='tests/isolated/', **kwargs):
kwargs.setdefault('expect_pass', True)
run_python(prefix + path, **kwargs)
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
@@ -353,3 +364,10 @@ private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
def test_run_python_timeout():
output = run_python('', args=('-c', 'import time; time.sleep(0.5)'), timeout=0.1)
assert output.endswith(b'FAIL - timed out')
def test_run_python_pythonpath_extend():
code = '''import os, sys ; print('\\n'.join(sys.path))'''
output = run_python('', args=('-c', code), pythonpath_extend=('dira', 'dirb'))
assert b'/dira\n' in output
assert b'/dirb\n' in output

View File

@@ -19,12 +19,12 @@ socket.gethostbyname('localhost')
socket.getaddrinfo('localhost', 80)
print('pass')
'''
output = tests.run_python(
tests.run_python(
path=None,
env={'EVENTLET_TPOOL_DNS': 'yes'},
args=['-c', code],
expect_pass=True,
)
assert output.rstrip() == b'pass'
@tests.skip_with_pyevent

View File

@@ -1,15 +1,18 @@
import os
__test__ = False
if __name__ == '__main__':
import sys
# On eventlet<=0.20.0 uncommenting this unpatched import fails test
# because import_patched did not agressively repatch sub-imported modules cached in sys.modules
# to be fixed in https://github.com/eventlet/eventlet/issues/368
# import tests.patcher.shared_import_socket
if os.environ.get('eventlet_test_import_patched_defaults') == '1':
try:
import urllib.request as target
except ImportError:
import urllib as target
import eventlet
target = eventlet.import_patched('tests.patcher.shared1').shared
t = target.socket.socket
import eventlet.green.socket
if issubclass(t, eventlet.green.socket.socket):
print('pass')
else:
import eventlet.green.socket as g
if not issubclass(t, g.socket):
print('Fail. Target socket not green: {0} bases {1}'.format(t, t.__bases__))
sys.exit(1)
print('pass')

View File

11
tests/patcher/shared1.py Normal file
View File

@@ -0,0 +1,11 @@
import os
__test__ = False
shared = None
if os.environ.get('eventlet_test_in_progress') == 'yes':
# pyopenssl imported urllib before we could patch it
# we can ensure this shared module was not imported
# https://github.com/eventlet/eventlet/issues/362
import tests.patcher.shared_import_socket as shared
_ = shared # mask unused import error

View File

@@ -0,0 +1,7 @@
import os
import socket
__test__ = False
_ = socket # mask unused import error
# prevent accidental imports
assert os.environ.get('eventlet_test_in_progress') == 'yes'

View File

@@ -84,17 +84,7 @@ class ImportPatched(ProcessBase):
def test_import_patched_defaults():
code = '''\
import eventlet
eventlet.import_patched('patcher_import_patched_defaults')
'''
isolated_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/tests/isolated'
env = {
'eventlet_test_import_patched_defaults': '1',
'PYTHONPATH': os.pathsep.join(sys.path + [isolated_path]),
}
output = tests.run_python(path=None, env=env, args=['-c', code])
assert output.rstrip() == b'pass', repr(output)
tests.run_isolated('patcher_import_patched_defaults.py')
class MonkeyPatch(ProcessBase):

View File

@@ -72,10 +72,7 @@ def test_dns_methods_are_green():
with open(mock_sys_pkg_dir + '/dns.py', 'wb') as f:
f.write(b'raise Exception("Your IP address string is so illegal ' +
b'it prevents installing packages.")\n')
tests.run_isolated(
'socket_resolve_green.py',
env={'PYTHONPATH': os.pathsep.join(sys.path + [mock_sys_pkg_dir])},
)
tests.run_isolated('socket_resolve_green.py', pythonpath_extend=[mock_sys_pkg_dir])
finally:
shutil.rmtree(mock_sys_pkg_dir)

View File

@@ -42,12 +42,12 @@ basepython =
py35: python3.5
pypy: pypy
deps =
nose==1.3.1
setuptools==5.4.1
nose==1.3.7
setuptools==32.3.1
py{26,27}: subprocess32==3.2.7
py{26,27}-{selects,poll,epolls}: MySQL-python==1.2.5
py26-{selects,poll,epolls}: pyopenssl==0.13
py{27,33,34}-{selects,poll,epolls}: pyopenssl==16.0.0
py{27,33,34}-{selects,poll,epolls}: pyopenssl==16.2.0
{selects,poll,epolls}: psycopg2cffi-compat==1.1
{selects,poll,epolls}: pyzmq==13.1.0
commands =