Add python-eventlet package to MOS 9.0 repository
[packages/trusty/python-eventlet.git] / python-eventlet / tests / patcher_test.py
1 import os
2 import shutil
3 import sys
4 import tempfile
5
6 from eventlet.support import six
7 import tests
8
9
10 base_module_contents = """
11 import socket
12 import urllib
13 print("base {0} {1}".format(socket, urllib))
14 """
15
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))
22 del patcher
23 """
24
25 import_module_contents = """
26 import patching
27 import socket
28 print("importing {0} {1} {2} {3}".format(patching, socket, patching.socket, patching.urllib))
29 """
30
31
32 class ProcessBase(tests.LimitedTestCase):
33     TEST_TIMEOUT = 3  # starting processes is time-consuming
34
35     def setUp(self):
36         super(ProcessBase, self).setUp()
37         self._saved_syspath = sys.path
38         self.tempdir = tempfile.mkdtemp('_patcher_test')
39
40     def tearDown(self):
41         super(ProcessBase, self).tearDown()
42         sys.path = self._saved_syspath
43         shutil.rmtree(self.tempdir)
44
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:
50             fd.write(contents)
51
52     def launch_subprocess(self, filename):
53         path = os.path.join(self.tempdir, filename)
54         output = tests.run_python(path)
55         if six.PY3:
56             output = output.decode('utf-8')
57             separator = '\n'
58         else:
59             separator = b'\n'
60         lines = output.split(separator)
61         return output, lines
62
63     def run_script(self, contents, modname=None):
64         if modname is None:
65             modname = "testmod"
66         self.write_to_tempfile(modname, contents)
67         return self.launch_subprocess(modname)
68
69
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)
84
85     def test_import_patched_defaults(self):
86         self.write_to_tempfile("base", """
87 import socket
88 try:
89     import urllib.request as urllib
90 except ImportError:
91     import urllib
92 print("base {0} {1}".format(socket, urllib))""")
93
94         new_mod = """
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))
98 """
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)
105
106
107 class MonkeyPatch(ProcessBase):
108     def test_patched_modules(self):
109         new_mod = """
110 from eventlet import patcher
111 patcher.monkey_patch()
112 import socket
113 try:
114     import urllib.request as urllib
115 except ImportError:
116     import urllib
117 print("newmod {0} {1}".format(socket.socket, urllib.socket.socket))
118 """
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))
123
124     def test_early_patching(self):
125         new_mod = """
126 from eventlet import patcher
127 patcher.monkey_patch()
128 import eventlet
129 eventlet.sleep(0.01)
130 print("newmod")
131 """
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)
136
137     def test_late_patching(self):
138         new_mod = """
139 import eventlet
140 eventlet.sleep(0.01)
141 from eventlet import patcher
142 patcher.monkey_patch()
143 eventlet.sleep(0.01)
144 print("newmod")
145 """
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)
150
151     def test_typeerror(self):
152         new_mod = """
153 from eventlet import patcher
154 patcher.monkey_patch(finagle=True)
155 """
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)
160
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)])
164         new_mod = """
165 from eventlet import patcher
166 %s
167 for mod in [%s]:
168     assert patcher.is_monkey_patched(mod), mod
169 for mod in [%s]:
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,", "")
180         # ditto for MySQLdb
181         patched_modules = patched_modules.replace("MySQLdb,", "")
182         self.assertEqual(
183             patched_modules, expected,
184             "Logic:%s\nExpected: %s != %s" % (call, expected, patched_modules))
185
186     def test_boolean(self):
187         self.assert_boolean_logic("patcher.monkey_patch()",
188                                   'os,select,socket,thread,time')
189
190     def test_boolean_all(self):
191         self.assert_boolean_logic("patcher.monkey_patch(all=True)",
192                                   'os,select,socket,thread,time')
193
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')
197
198     def test_boolean_all_negative(self):
199         self.assert_boolean_logic(
200             "patcher.monkey_patch(all=False, socket=False, select=True)",
201             'select')
202
203     def test_boolean_single(self):
204         self.assert_boolean_logic("patcher.monkey_patch(socket=True)",
205                                   'socket')
206
207     def test_boolean_double(self):
208         self.assert_boolean_logic("patcher.monkey_patch(socket=True, select=True)",
209                                   'select,socket')
210
211     def test_boolean_negative(self):
212         self.assert_boolean_logic("patcher.monkey_patch(socket=False)",
213                                   'os,select,thread,time')
214
215     def test_boolean_negative2(self):
216         self.assert_boolean_logic("patcher.monkey_patch(socket=False, time=False)",
217                                   'os,select,thread')
218
219     def test_conflicting_specifications(self):
220         self.assert_boolean_logic("patcher.monkey_patch(socket=False, select=True)",
221                                   'select')
222
223
224 test_monkey_patch_threading = """
225 def test_monkey_patch_threading():
226     tickcount = [0]
227
228     def tick():
229         from eventlet.support import six
230         for i in six.moves.range(1000):
231             tickcount[0] += 1
232             eventlet.sleep()
233
234     def do_sleep():
235         tpool.execute(time.sleep, 0.5)
236
237     eventlet.spawn(tick)
238     w1 = eventlet.spawn(do_sleep)
239     w1.wait()
240     print(tickcount[0])
241     assert tickcount[0] > 900
242     tpool.killall()
243 """
244
245
246 class Tpool(ProcessBase):
247     TEST_TIMEOUT = 3
248
249     @tests.skip_with_pyevent
250     def test_simple(self):
251         new_mod = """
252 import eventlet
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")))
258 tpool.killall()
259 """
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)
266
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
272 import time
273 """
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)
279
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
285 import time
286 """
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))
292
293
294 def test_subprocess_after_monkey_patch():
295     code = '''\
296 import sys
297 import eventlet
298 eventlet.monkey_patch()
299 from eventlet.green import subprocess
300 subprocess.Popen([sys.executable, '-c', ''], stdin=subprocess.PIPE).wait()
301 print('pass')
302 '''
303     output = tests.run_python(
304         path=None,
305         args=['-c', code],
306     )
307     assert output.rstrip() == b'pass'
308
309
310 class Threading(ProcessBase):
311     def test_orig_thread(self):
312         new_mod = """import eventlet
313 eventlet.monkey_patch()
314 from eventlet import patcher
315 import threading
316 _threading = patcher.original('threading')
317 def test():
318     print(repr(threading.currentThread()))
319 t = _threading.Thread(target=test)
320 t.start()
321 t.join()
322 print(len(threading._active))
323 print(len(_threading._active))
324 """
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
331
332     def test_threading(self):
333         new_mod = """import eventlet
334 eventlet.monkey_patch()
335 import threading
336 def test():
337     print(repr(threading.currentThread()))
338 t = threading.Thread(target=test)
339 t.start()
340 t.join()
341 print(len(threading._active))
342 """
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])
348
349     def test_tpool(self):
350         new_mod = """import eventlet
351 eventlet.monkey_patch()
352 from eventlet import tpool
353 import threading
354 def test():
355     print(repr(threading.currentThread()))
356 tpool.execute(test)
357 print(len(threading._active))
358 """
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])
364
365     def test_greenlet(self):
366         new_mod = """import eventlet
367 eventlet.monkey_patch()
368 from eventlet import event
369 import threading
370 evt = event.Event()
371 def test():
372     print(repr(threading.currentThread()))
373     evt.send()
374 eventlet.spawn_n(test)
375 evt.wait()
376 print(len(threading._active))
377 """
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])
383
384     def test_greenthread(self):
385         new_mod = """import eventlet
386 eventlet.monkey_patch()
387 import threading
388 def test():
389     print(repr(threading.currentThread()))
390 t = eventlet.spawn(test)
391 t.wait()
392 print(len(threading._active))
393 """
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])
399
400     def test_keyerror(self):
401         new_mod = """import eventlet
402 eventlet.monkey_patch()
403 """
404         self.write_to_tempfile("newmod", new_mod)
405         output, lines = self.launch_subprocess('newmod')
406         self.assertEqual(len(lines), 1, "\n".join(lines))
407
408
409 class Os(ProcessBase):
410     def test_waitpid(self):
411         new_mod = """import subprocess
412 import eventlet
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))
420
421
422 class GreenThreadWrapper(ProcessBase):
423     prologue = """import eventlet
424 eventlet.monkey_patch()
425 import threading
426 def test():
427     t = threading.currentThread()
428 """
429     epilogue = """
430 t = eventlet.spawn(test)
431 t.wait()
432 """
433
434     def test_join(self):
435         self.write_to_tempfile("newmod", self.prologue + """
436     def test2():
437         global t2
438         t2 = threading.currentThread()
439     eventlet.spawn(test2)
440 """ + self.epilogue + """
441 print(repr(t2))
442 t2.join()
443 """)
444         output, lines = self.launch_subprocess('newmod')
445         self.assertEqual(len(lines), 2, "\n".join(lines))
446         assert lines[0].startswith('<_GreenThread'), lines[0]
447
448     def test_name(self):
449         self.write_to_tempfile("newmod", self.prologue + """
450     print(t.name)
451     print(t.getName())
452     print(t.get_name())
453     t.name = 'foo'
454     print(t.name)
455     print(t.getName())
456     print(t.get_name())
457     t.setName('bar')
458     print(t.name)
459     print(t.getName())
460     print(t.get_name())
461 """ + self.epilogue)
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])
470
471     def test_ident(self):
472         self.write_to_tempfile("newmod", self.prologue + """
473     print(id(t._g))
474     print(t.ident)
475 """ + self.epilogue)
476         output, lines = self.launch_subprocess('newmod')
477         self.assertEqual(len(lines), 3, "\n".join(lines))
478         self.assertEqual(lines[0], lines[1])
479
480     def test_is_alive(self):
481         self.write_to_tempfile("newmod", self.prologue + """
482     print(t.is_alive())
483     print(t.isAlive())
484 """ + self.epilogue)
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])
489
490     def test_is_daemon(self):
491         self.write_to_tempfile("newmod", self.prologue + """
492     print(t.is_daemon())
493     print(t.isDaemon())
494 """ + self.epilogue)
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])
499
500
501 def test_importlib_lock():
502     tests.run_isolated('patcher_importlib_lock.py')
503
504
505 def test_threading_condition():
506     tests.run_isolated('patcher_threading_condition.py')
507
508
509 def test_threading_join():
510     tests.run_isolated('patcher_threading_join.py')
511
512
513 def test_socketserver_selectors():
514     tests.run_isolated('patcher_socketserver_selectors.py')
515
516
517 def test_blocking_select_methods_are_deleted():
518     tests.run_isolated('patcher_blocking_select_methods_are_deleted.py')