6 from eventlet.support import six
10 base_module_contents = """
13 print("base {0} {1}".format(socket, urllib))
16 patching_module_contents = """
17 from eventlet.green import socket
18 from eventlet.green import urllib
19 from eventlet import patcher
20 print('patcher {0} {1}'.format(socket, urllib))
21 patcher.inject('base', globals(), ('socket', socket), ('urllib', urllib))
25 import_module_contents = """
28 print("importing {0} {1} {2} {3}".format(patching, socket, patching.socket, patching.urllib))
32 class ProcessBase(tests.LimitedTestCase):
33 TEST_TIMEOUT = 3 # starting processes is time-consuming
36 super(ProcessBase, self).setUp()
37 self._saved_syspath = sys.path
38 self.tempdir = tempfile.mkdtemp('_patcher_test')
41 super(ProcessBase, self).tearDown()
42 sys.path = self._saved_syspath
43 shutil.rmtree(self.tempdir)
45 def write_to_tempfile(self, name, contents):
46 filename = os.path.join(self.tempdir, name)
47 if not filename.endswith('.py'):
48 filename = filename + '.py'
49 with open(filename, "w") as fd:
52 def launch_subprocess(self, filename):
53 path = os.path.join(self.tempdir, filename)
54 output = tests.run_python(path)
56 output = output.decode('utf-8')
60 lines = output.split(separator)
63 def run_script(self, contents, modname=None):
66 self.write_to_tempfile(modname, contents)
67 return self.launch_subprocess(modname)
70 class ImportPatched(ProcessBase):
71 def test_patch_a_module(self):
72 self.write_to_tempfile("base", base_module_contents)
73 self.write_to_tempfile("patching", patching_module_contents)
74 self.write_to_tempfile("importing", import_module_contents)
75 output, lines = self.launch_subprocess('importing.py')
76 assert lines[0].startswith('patcher'), repr(output)
77 assert lines[1].startswith('base'), repr(output)
78 assert lines[2].startswith('importing'), repr(output)
79 assert 'eventlet.green.socket' in lines[1], repr(output)
80 assert 'eventlet.green.urllib' in lines[1], repr(output)
81 assert 'eventlet.green.socket' in lines[2], repr(output)
82 assert 'eventlet.green.urllib' in lines[2], repr(output)
83 assert 'eventlet.green.httplib' not in lines[2], repr(output)
85 def test_import_patched_defaults(self):
86 self.write_to_tempfile("base", """
89 import urllib.request as urllib
92 print("base {0} {1}".format(socket, urllib))""")
95 from eventlet import patcher
96 base = patcher.import_patched('base')
97 print("newmod {0} {1} {2}".format(base, base.socket, base.urllib.socket.socket))
99 self.write_to_tempfile("newmod", new_mod)
100 output, lines = self.launch_subprocess('newmod.py')
101 assert lines[0].startswith('base'), repr(output)
102 assert lines[1].startswith('newmod'), repr(output)
103 assert 'eventlet.green.socket' in lines[1], repr(output)
104 assert 'GreenSocket' in lines[1], repr(output)
107 class MonkeyPatch(ProcessBase):
108 def test_patched_modules(self):
110 from eventlet import patcher
111 patcher.monkey_patch()
114 import urllib.request as urllib
117 print("newmod {0} {1}".format(socket.socket, urllib.socket.socket))
119 self.write_to_tempfile("newmod", new_mod)
120 output, lines = self.launch_subprocess('newmod.py')
121 assert lines[0].startswith('newmod'), repr(output)
122 self.assertEqual(lines[0].count('GreenSocket'), 2, repr(output))
124 def test_early_patching(self):
126 from eventlet import patcher
127 patcher.monkey_patch()
132 self.write_to_tempfile("newmod", new_mod)
133 output, lines = self.launch_subprocess('newmod.py')
134 self.assertEqual(len(lines), 2, repr(output))
135 assert lines[0].startswith('newmod'), repr(output)
137 def test_late_patching(self):
141 from eventlet import patcher
142 patcher.monkey_patch()
146 self.write_to_tempfile("newmod", new_mod)
147 output, lines = self.launch_subprocess('newmod.py')
148 self.assertEqual(len(lines), 2, repr(output))
149 assert lines[0].startswith('newmod'), repr(output)
151 def test_typeerror(self):
153 from eventlet import patcher
154 patcher.monkey_patch(finagle=True)
156 self.write_to_tempfile("newmod", new_mod)
157 output, lines = self.launch_subprocess('newmod.py')
158 assert lines[-2].startswith('TypeError'), repr(output)
159 assert 'finagle' in lines[-2], repr(output)
161 def assert_boolean_logic(self, call, expected, not_expected=''):
162 expected_list = ", ".join(['"%s"' % x for x in expected.split(',') if len(x)])
163 not_expected_list = ", ".join(['"%s"' % x for x in not_expected.split(',') if len(x)])
165 from eventlet import patcher
168 assert patcher.is_monkey_patched(mod), mod
170 assert not patcher.is_monkey_patched(mod), mod
171 print("already_patched {0}".format(",".join(sorted(patcher.already_patched.keys()))))
172 """ % (call, expected_list, not_expected_list)
173 self.write_to_tempfile("newmod", new_mod)
174 output, lines = self.launch_subprocess('newmod.py')
175 ap = 'already_patched'
176 assert lines[0].startswith(ap), repr(output)
177 patched_modules = lines[0][len(ap):].strip()
178 # psycopg might or might not be patched based on installed modules
179 patched_modules = patched_modules.replace("psycopg,", "")
181 patched_modules = patched_modules.replace("MySQLdb,", "")
183 patched_modules, expected,
184 "Logic:%s\nExpected: %s != %s" % (call, expected, patched_modules))
186 def test_boolean(self):
187 self.assert_boolean_logic("patcher.monkey_patch()",
188 'os,select,socket,thread,time')
190 def test_boolean_all(self):
191 self.assert_boolean_logic("patcher.monkey_patch(all=True)",
192 'os,select,socket,thread,time')
194 def test_boolean_all_single(self):
195 self.assert_boolean_logic("patcher.monkey_patch(all=True, socket=True)",
196 'os,select,socket,thread,time')
198 def test_boolean_all_negative(self):
199 self.assert_boolean_logic(
200 "patcher.monkey_patch(all=False, socket=False, select=True)",
203 def test_boolean_single(self):
204 self.assert_boolean_logic("patcher.monkey_patch(socket=True)",
207 def test_boolean_double(self):
208 self.assert_boolean_logic("patcher.monkey_patch(socket=True, select=True)",
211 def test_boolean_negative(self):
212 self.assert_boolean_logic("patcher.monkey_patch(socket=False)",
213 'os,select,thread,time')
215 def test_boolean_negative2(self):
216 self.assert_boolean_logic("patcher.monkey_patch(socket=False, time=False)",
219 def test_conflicting_specifications(self):
220 self.assert_boolean_logic("patcher.monkey_patch(socket=False, select=True)",
224 test_monkey_patch_threading = """
225 def test_monkey_patch_threading():
229 from eventlet.support import six
230 for i in six.moves.range(1000):
235 tpool.execute(time.sleep, 0.5)
238 w1 = eventlet.spawn(do_sleep)
241 assert tickcount[0] > 900
246 class Tpool(ProcessBase):
249 @tests.skip_with_pyevent
250 def test_simple(self):
253 from eventlet import patcher
254 patcher.monkey_patch()
255 from eventlet import tpool
256 print("newmod {0}".format(tpool.execute(len, "hi")))
257 print("newmod {0}".format(tpool.execute(len, "hi2")))
260 self.write_to_tempfile("newmod", new_mod)
261 output, lines = self.launch_subprocess('newmod.py')
262 self.assertEqual(len(lines), 3, output)
263 assert lines[0].startswith('newmod'), repr(output)
264 assert '2' in lines[0], repr(output)
265 assert '3' in lines[1], repr(output)
267 @tests.skip_with_pyevent
268 def test_unpatched_thread(self):
269 new_mod = """import eventlet
270 eventlet.monkey_patch(time=False, thread=False)
271 from eventlet import tpool
274 new_mod += test_monkey_patch_threading
275 new_mod += "\ntest_monkey_patch_threading()\n"
276 self.write_to_tempfile("newmod", new_mod)
277 output, lines = self.launch_subprocess('newmod.py')
278 self.assertEqual(len(lines), 2, lines)
280 @tests.skip_with_pyevent
281 def test_patched_thread(self):
282 new_mod = """import eventlet
283 eventlet.monkey_patch(time=False, thread=True)
284 from eventlet import tpool
287 new_mod += test_monkey_patch_threading
288 new_mod += "\ntest_monkey_patch_threading()\n"
289 self.write_to_tempfile("newmod", new_mod)
290 output, lines = self.launch_subprocess('newmod.py')
291 self.assertEqual(len(lines), 2, "\n".join(lines))
294 def test_subprocess_after_monkey_patch():
298 eventlet.monkey_patch()
299 from eventlet.green import subprocess
300 subprocess.Popen([sys.executable, '-c', ''], stdin=subprocess.PIPE).wait()
303 output = tests.run_python(
307 assert output.rstrip() == b'pass'
310 class Threading(ProcessBase):
311 def test_orig_thread(self):
312 new_mod = """import eventlet
313 eventlet.monkey_patch()
314 from eventlet import patcher
316 _threading = patcher.original('threading')
318 print(repr(threading.currentThread()))
319 t = _threading.Thread(target=test)
322 print(len(threading._active))
323 print(len(_threading._active))
325 self.write_to_tempfile("newmod", new_mod)
326 output, lines = self.launch_subprocess('newmod')
327 self.assertEqual(len(lines), 4, "\n".join(lines))
328 assert lines[0].startswith('<Thread'), lines[0]
329 assert lines[1] == '1', lines
330 assert lines[2] == '1', lines
332 def test_threading(self):
333 new_mod = """import eventlet
334 eventlet.monkey_patch()
337 print(repr(threading.currentThread()))
338 t = threading.Thread(target=test)
341 print(len(threading._active))
343 self.write_to_tempfile("newmod", new_mod)
344 output, lines = self.launch_subprocess('newmod')
345 self.assertEqual(len(lines), 3, "\n".join(lines))
346 assert lines[0].startswith('<_MainThread'), lines[0]
347 self.assertEqual(lines[1], "1", lines[1])
349 def test_tpool(self):
350 new_mod = """import eventlet
351 eventlet.monkey_patch()
352 from eventlet import tpool
355 print(repr(threading.currentThread()))
357 print(len(threading._active))
359 self.write_to_tempfile("newmod", new_mod)
360 output, lines = self.launch_subprocess('newmod')
361 self.assertEqual(len(lines), 3, "\n".join(lines))
362 assert lines[0].startswith('<Thread'), lines[0]
363 self.assertEqual(lines[1], "1", lines[1])
365 def test_greenlet(self):
366 new_mod = """import eventlet
367 eventlet.monkey_patch()
368 from eventlet import event
372 print(repr(threading.currentThread()))
374 eventlet.spawn_n(test)
376 print(len(threading._active))
378 self.write_to_tempfile("newmod", new_mod)
379 output, lines = self.launch_subprocess('newmod')
380 self.assertEqual(len(lines), 3, "\n".join(lines))
381 assert lines[0].startswith('<_MainThread'), lines[0]
382 self.assertEqual(lines[1], "1", lines[1])
384 def test_greenthread(self):
385 new_mod = """import eventlet
386 eventlet.monkey_patch()
389 print(repr(threading.currentThread()))
390 t = eventlet.spawn(test)
392 print(len(threading._active))
394 self.write_to_tempfile("newmod", new_mod)
395 output, lines = self.launch_subprocess('newmod')
396 self.assertEqual(len(lines), 3, "\n".join(lines))
397 assert lines[0].startswith('<_GreenThread'), lines[0]
398 self.assertEqual(lines[1], "1", lines[1])
400 def test_keyerror(self):
401 new_mod = """import eventlet
402 eventlet.monkey_patch()
404 self.write_to_tempfile("newmod", new_mod)
405 output, lines = self.launch_subprocess('newmod')
406 self.assertEqual(len(lines), 1, "\n".join(lines))
409 class Os(ProcessBase):
410 def test_waitpid(self):
411 new_mod = """import subprocess
413 eventlet.monkey_patch(all=False, os=True)
414 process = subprocess.Popen("sleep 0.1 && false", shell=True)
415 print(process.wait())"""
416 self.write_to_tempfile("newmod", new_mod)
417 output, lines = self.launch_subprocess('newmod')
418 self.assertEqual(len(lines), 2, "\n".join(lines))
419 self.assertEqual('1', lines[0], repr(output))
422 class GreenThreadWrapper(ProcessBase):
423 prologue = """import eventlet
424 eventlet.monkey_patch()
427 t = threading.currentThread()
430 t = eventlet.spawn(test)
435 self.write_to_tempfile("newmod", self.prologue + """
438 t2 = threading.currentThread()
439 eventlet.spawn(test2)
440 """ + self.epilogue + """
444 output, lines = self.launch_subprocess('newmod')
445 self.assertEqual(len(lines), 2, "\n".join(lines))
446 assert lines[0].startswith('<_GreenThread'), lines[0]
449 self.write_to_tempfile("newmod", self.prologue + """
462 output, lines = self.launch_subprocess('newmod')
463 self.assertEqual(len(lines), 10, "\n".join(lines))
464 for i in range(0, 3):
465 self.assertEqual(lines[i], "GreenThread-1", lines[i])
466 for i in range(3, 6):
467 self.assertEqual(lines[i], "foo", lines[i])
468 for i in range(6, 9):
469 self.assertEqual(lines[i], "bar", lines[i])
471 def test_ident(self):
472 self.write_to_tempfile("newmod", self.prologue + """
476 output, lines = self.launch_subprocess('newmod')
477 self.assertEqual(len(lines), 3, "\n".join(lines))
478 self.assertEqual(lines[0], lines[1])
480 def test_is_alive(self):
481 self.write_to_tempfile("newmod", self.prologue + """
485 output, lines = self.launch_subprocess('newmod')
486 self.assertEqual(len(lines), 3, "\n".join(lines))
487 self.assertEqual(lines[0], "True", lines[0])
488 self.assertEqual(lines[1], "True", lines[1])
490 def test_is_daemon(self):
491 self.write_to_tempfile("newmod", self.prologue + """
495 output, lines = self.launch_subprocess('newmod')
496 self.assertEqual(len(lines), 3, "\n".join(lines))
497 self.assertEqual(lines[0], "True", lines[0])
498 self.assertEqual(lines[1], "True", lines[1])
501 def test_importlib_lock():
502 tests.run_isolated('patcher_importlib_lock.py')
505 def test_threading_condition():
506 tests.run_isolated('patcher_threading_condition.py')
509 def test_threading_join():
510 tests.run_isolated('patcher_threading_join.py')
513 def test_socketserver_selectors():
514 tests.run_isolated('patcher_socketserver_selectors.py')
517 def test_blocking_select_methods_are_deleted():
518 tests.run_isolated('patcher_blocking_select_methods_are_deleted.py')