Add python-eventlet 0.16.1
[packages/trusty/python-eventlet.git] / 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 from tests import LimitedTestCase, main, run_python, skip_with_pyevent
8
9
10 base_module_contents = """
11 import socket
12 try:
13     import urllib.request as urllib
14 except ImportError:
15     import urllib
16 print("base {0} {1}".format(socket, urllib))
17 """
18
19 patching_module_contents = """
20 from eventlet.green import socket
21 from eventlet.green import urllib
22 from eventlet import patcher
23 print('patcher {0} {1}'.format(socket, urllib))
24 patcher.inject('base', globals(), ('socket', socket), ('urllib', urllib))
25 del patcher
26 """
27
28 import_module_contents = """
29 import patching
30 import socket
31 print("importing {0} {1} {2} {3}".format(patching, socket, patching.socket, patching.urllib))
32 """
33
34
35 class ProcessBase(LimitedTestCase):
36     TEST_TIMEOUT = 3  # starting processes is time-consuming
37
38     def setUp(self):
39         super(ProcessBase, self).setUp()
40         self._saved_syspath = sys.path
41         self.tempdir = tempfile.mkdtemp('_patcher_test')
42
43     def tearDown(self):
44         super(ProcessBase, self).tearDown()
45         sys.path = self._saved_syspath
46         shutil.rmtree(self.tempdir)
47
48     def write_to_tempfile(self, name, contents):
49         filename = os.path.join(self.tempdir, name)
50         if not filename.endswith('.py'):
51             filename = filename + '.py'
52         with open(filename, "w") as fd:
53             fd.write(contents)
54
55     def launch_subprocess(self, filename):
56         path = os.path.join(self.tempdir, filename)
57         output = run_python(path)
58         if six.PY3:
59             output = output.decode('utf-8')
60             separator = '\n'
61         else:
62             separator = b'\n'
63         lines = output.split(separator)
64         return output, lines
65
66     def run_script(self, contents, modname=None):
67         if modname is None:
68             modname = "testmod"
69         self.write_to_tempfile(modname, contents)
70         return self.launch_subprocess(modname)
71
72
73 class ImportPatched(ProcessBase):
74     def test_patch_a_module(self):
75         self.write_to_tempfile("base", base_module_contents)
76         self.write_to_tempfile("patching", patching_module_contents)
77         self.write_to_tempfile("importing", import_module_contents)
78         output, lines = self.launch_subprocess('importing.py')
79         assert lines[0].startswith('patcher'), repr(output)
80         assert lines[1].startswith('base'), repr(output)
81         assert lines[2].startswith('importing'), repr(output)
82         assert 'eventlet.green.socket' in lines[1], repr(output)
83         assert 'eventlet.green.urllib' in lines[1], repr(output)
84         assert 'eventlet.green.socket' in lines[2], repr(output)
85         assert 'eventlet.green.urllib' in lines[2], repr(output)
86         assert 'eventlet.green.httplib' not in lines[2], repr(output)
87
88     def test_import_patched_defaults(self):
89         self.write_to_tempfile("base", base_module_contents)
90         new_mod = """
91 from eventlet import patcher
92 base = patcher.import_patched('base')
93 print("newmod {0} {1} {2}".format(base, base.socket, base.urllib.socket.socket))
94 """
95         self.write_to_tempfile("newmod", new_mod)
96         output, lines = self.launch_subprocess('newmod.py')
97         assert lines[0].startswith('base'), repr(output)
98         assert lines[1].startswith('newmod'), repr(output)
99         assert 'eventlet.green.socket' in lines[1], repr(output)
100         assert 'GreenSocket' in lines[1], repr(output)
101
102
103 class MonkeyPatch(ProcessBase):
104     def test_patched_modules(self):
105         new_mod = """
106 from eventlet import patcher
107 patcher.monkey_patch()
108 import socket
109 try:
110     import urllib.request as urllib
111 except ImportError:
112     import urllib
113 print("newmod {0} {1}".format(socket.socket, urllib.socket.socket))
114 """
115         self.write_to_tempfile("newmod", new_mod)
116         output, lines = self.launch_subprocess('newmod.py')
117         assert lines[0].startswith('newmod'), repr(output)
118         self.assertEqual(lines[0].count('GreenSocket'), 2, repr(output))
119
120     def test_early_patching(self):
121         new_mod = """
122 from eventlet import patcher
123 patcher.monkey_patch()
124 import eventlet
125 eventlet.sleep(0.01)
126 print("newmod")
127 """
128         self.write_to_tempfile("newmod", new_mod)
129         output, lines = self.launch_subprocess('newmod.py')
130         self.assertEqual(len(lines), 2, repr(output))
131         assert lines[0].startswith('newmod'), repr(output)
132
133     def test_late_patching(self):
134         new_mod = """
135 import eventlet
136 eventlet.sleep(0.01)
137 from eventlet import patcher
138 patcher.monkey_patch()
139 eventlet.sleep(0.01)
140 print("newmod")
141 """
142         self.write_to_tempfile("newmod", new_mod)
143         output, lines = self.launch_subprocess('newmod.py')
144         self.assertEqual(len(lines), 2, repr(output))
145         assert lines[0].startswith('newmod'), repr(output)
146
147     def test_typeerror(self):
148         new_mod = """
149 from eventlet import patcher
150 patcher.monkey_patch(finagle=True)
151 """
152         self.write_to_tempfile("newmod", new_mod)
153         output, lines = self.launch_subprocess('newmod.py')
154         assert lines[-2].startswith('TypeError'), repr(output)
155         assert 'finagle' in lines[-2], repr(output)
156
157     def assert_boolean_logic(self, call, expected, not_expected=''):
158         expected_list = ", ".join(['"%s"' % x for x in expected.split(',') if len(x)])
159         not_expected_list = ", ".join(['"%s"' % x for x in not_expected.split(',') if len(x)])
160         new_mod = """
161 from eventlet import patcher
162 %s
163 for mod in [%s]:
164     assert patcher.is_monkey_patched(mod), mod
165 for mod in [%s]:
166     assert not patcher.is_monkey_patched(mod), mod
167 print("already_patched {0}".format(",".join(sorted(patcher.already_patched.keys()))))
168 """ % (call, expected_list, not_expected_list)
169         self.write_to_tempfile("newmod", new_mod)
170         output, lines = self.launch_subprocess('newmod.py')
171         ap = 'already_patched'
172         assert lines[0].startswith(ap), repr(output)
173         patched_modules = lines[0][len(ap):].strip()
174         # psycopg might or might not be patched based on installed modules
175         patched_modules = patched_modules.replace("psycopg,", "")
176         # ditto for MySQLdb
177         patched_modules = patched_modules.replace("MySQLdb,", "")
178         self.assertEqual(
179             patched_modules, expected,
180             "Logic:%s\nExpected: %s != %s" % (call, expected, patched_modules))
181
182     def test_boolean(self):
183         self.assert_boolean_logic("patcher.monkey_patch()",
184                                   'os,select,socket,thread,time')
185
186     def test_boolean_all(self):
187         self.assert_boolean_logic("patcher.monkey_patch(all=True)",
188                                   'os,select,socket,thread,time')
189
190     def test_boolean_all_single(self):
191         self.assert_boolean_logic("patcher.monkey_patch(all=True, socket=True)",
192                                   'os,select,socket,thread,time')
193
194     def test_boolean_all_negative(self):
195         self.assert_boolean_logic(
196             "patcher.monkey_patch(all=False, socket=False, select=True)",
197             'select')
198
199     def test_boolean_single(self):
200         self.assert_boolean_logic("patcher.monkey_patch(socket=True)",
201                                   'socket')
202
203     def test_boolean_double(self):
204         self.assert_boolean_logic("patcher.monkey_patch(socket=True, select=True)",
205                                   'select,socket')
206
207     def test_boolean_negative(self):
208         self.assert_boolean_logic("patcher.monkey_patch(socket=False)",
209                                   'os,select,thread,time')
210
211     def test_boolean_negative2(self):
212         self.assert_boolean_logic("patcher.monkey_patch(socket=False, time=False)",
213                                   'os,select,thread')
214
215     def test_conflicting_specifications(self):
216         self.assert_boolean_logic("patcher.monkey_patch(socket=False, select=True)",
217                                   'select')
218
219
220 test_monkey_patch_threading = """
221 def test_monkey_patch_threading():
222     tickcount = [0]
223
224     def tick():
225         from eventlet.support import six
226         for i in six.moves.range(1000):
227             tickcount[0] += 1
228             eventlet.sleep()
229
230     def do_sleep():
231         tpool.execute(time.sleep, 0.5)
232
233     eventlet.spawn(tick)
234     w1 = eventlet.spawn(do_sleep)
235     w1.wait()
236     print(tickcount[0])
237     assert tickcount[0] > 900
238     tpool.killall()
239 """
240
241
242 class Tpool(ProcessBase):
243     TEST_TIMEOUT = 3
244
245     @skip_with_pyevent
246     def test_simple(self):
247         new_mod = """
248 import eventlet
249 from eventlet import patcher
250 patcher.monkey_patch()
251 from eventlet import tpool
252 print("newmod {0}".format(tpool.execute(len, "hi")))
253 print("newmod {0}".format(tpool.execute(len, "hi2")))
254 tpool.killall()
255 """
256         self.write_to_tempfile("newmod", new_mod)
257         output, lines = self.launch_subprocess('newmod.py')
258         self.assertEqual(len(lines), 3, output)
259         assert lines[0].startswith('newmod'), repr(output)
260         assert '2' in lines[0], repr(output)
261         assert '3' in lines[1], repr(output)
262
263     @skip_with_pyevent
264     def test_unpatched_thread(self):
265         new_mod = """import eventlet
266 eventlet.monkey_patch(time=False, thread=False)
267 from eventlet import tpool
268 import time
269 """
270         new_mod += test_monkey_patch_threading
271         new_mod += "\ntest_monkey_patch_threading()\n"
272         self.write_to_tempfile("newmod", new_mod)
273         output, lines = self.launch_subprocess('newmod.py')
274         self.assertEqual(len(lines), 2, lines)
275
276     @skip_with_pyevent
277     def test_patched_thread(self):
278         new_mod = """import eventlet
279 eventlet.monkey_patch(time=False, thread=True)
280 from eventlet import tpool
281 import time
282 """
283         new_mod += test_monkey_patch_threading
284         new_mod += "\ntest_monkey_patch_threading()\n"
285         self.write_to_tempfile("newmod", new_mod)
286         output, lines = self.launch_subprocess('newmod.py')
287         self.assertEqual(len(lines), 2, "\n".join(lines))
288
289
290 class Subprocess(ProcessBase):
291     def test_monkeypatched_subprocess(self):
292         new_mod = """import eventlet
293 eventlet.monkey_patch()
294 from eventlet.green import subprocess
295
296 subprocess.Popen(['true'], stdin=subprocess.PIPE)
297 print("done")
298 """
299         self.write_to_tempfile("newmod", new_mod)
300         output, lines = self.launch_subprocess('newmod')
301         self.assertEqual(output, "done\n", output)
302
303
304 class Threading(ProcessBase):
305     def test_orig_thread(self):
306         new_mod = """import eventlet
307 eventlet.monkey_patch()
308 from eventlet import patcher
309 import threading
310 _threading = patcher.original('threading')
311 def test():
312     print(repr(threading.currentThread()))
313 t = _threading.Thread(target=test)
314 t.start()
315 t.join()
316 print(len(threading._active))
317 print(len(_threading._active))
318 """
319         self.write_to_tempfile("newmod", new_mod)
320         output, lines = self.launch_subprocess('newmod')
321         self.assertEqual(len(lines), 4, "\n".join(lines))
322         assert lines[0].startswith('<Thread'), lines[0]
323         self.assertEqual(lines[1], "1", lines[1])
324         self.assertEqual(lines[2], "1", lines[2])
325
326     def test_threading(self):
327         new_mod = """import eventlet
328 eventlet.monkey_patch()
329 import threading
330 def test():
331     print(repr(threading.currentThread()))
332 t = threading.Thread(target=test)
333 t.start()
334 t.join()
335 print(len(threading._active))
336 """
337         self.write_to_tempfile("newmod", new_mod)
338         output, lines = self.launch_subprocess('newmod')
339         self.assertEqual(len(lines), 3, "\n".join(lines))
340         assert lines[0].startswith('<_MainThread'), lines[0]
341         self.assertEqual(lines[1], "1", lines[1])
342
343     def test_tpool(self):
344         new_mod = """import eventlet
345 eventlet.monkey_patch()
346 from eventlet import tpool
347 import threading
348 def test():
349     print(repr(threading.currentThread()))
350 tpool.execute(test)
351 print(len(threading._active))
352 """
353         self.write_to_tempfile("newmod", new_mod)
354         output, lines = self.launch_subprocess('newmod')
355         self.assertEqual(len(lines), 3, "\n".join(lines))
356         assert lines[0].startswith('<Thread'), lines[0]
357         self.assertEqual(lines[1], "1", lines[1])
358
359     def test_greenlet(self):
360         new_mod = """import eventlet
361 eventlet.monkey_patch()
362 from eventlet import event
363 import threading
364 evt = event.Event()
365 def test():
366     print(repr(threading.currentThread()))
367     evt.send()
368 eventlet.spawn_n(test)
369 evt.wait()
370 print(len(threading._active))
371 """
372         self.write_to_tempfile("newmod", new_mod)
373         output, lines = self.launch_subprocess('newmod')
374         self.assertEqual(len(lines), 3, "\n".join(lines))
375         assert lines[0].startswith('<_MainThread'), lines[0]
376         self.assertEqual(lines[1], "1", lines[1])
377
378     def test_greenthread(self):
379         new_mod = """import eventlet
380 eventlet.monkey_patch()
381 import threading
382 def test():
383     print(repr(threading.currentThread()))
384 t = eventlet.spawn(test)
385 t.wait()
386 print(len(threading._active))
387 """
388         self.write_to_tempfile("newmod", new_mod)
389         output, lines = self.launch_subprocess('newmod')
390         self.assertEqual(len(lines), 3, "\n".join(lines))
391         assert lines[0].startswith('<_GreenThread'), lines[0]
392         self.assertEqual(lines[1], "1", lines[1])
393
394     def test_keyerror(self):
395         new_mod = """import eventlet
396 eventlet.monkey_patch()
397 """
398         self.write_to_tempfile("newmod", new_mod)
399         output, lines = self.launch_subprocess('newmod')
400         self.assertEqual(len(lines), 1, "\n".join(lines))
401
402
403 class Os(ProcessBase):
404     def test_waitpid(self):
405         new_mod = """import subprocess
406 import eventlet
407 eventlet.monkey_patch(all=False, os=True)
408 process = subprocess.Popen("sleep 0.1 && false", shell=True)
409 print(process.wait())"""
410         self.write_to_tempfile("newmod", new_mod)
411         output, lines = self.launch_subprocess('newmod')
412         self.assertEqual(len(lines), 2, "\n".join(lines))
413         self.assertEqual('1', lines[0], repr(output))
414
415
416 class GreenThreadWrapper(ProcessBase):
417     prologue = """import eventlet
418 eventlet.monkey_patch()
419 import threading
420 def test():
421     t = threading.currentThread()
422 """
423     epilogue = """
424 t = eventlet.spawn(test)
425 t.wait()
426 """
427
428     def test_join(self):
429         self.write_to_tempfile("newmod", self.prologue + """
430     def test2():
431         global t2
432         t2 = threading.currentThread()
433     eventlet.spawn(test2)
434 """ + self.epilogue + """
435 print(repr(t2))
436 t2.join()
437 """)
438         output, lines = self.launch_subprocess('newmod')
439         self.assertEqual(len(lines), 2, "\n".join(lines))
440         assert lines[0].startswith('<_GreenThread'), lines[0]
441
442     def test_name(self):
443         self.write_to_tempfile("newmod", self.prologue + """
444     print(t.name)
445     print(t.getName())
446     print(t.get_name())
447     t.name = 'foo'
448     print(t.name)
449     print(t.getName())
450     print(t.get_name())
451     t.setName('bar')
452     print(t.name)
453     print(t.getName())
454     print(t.get_name())
455 """ + self.epilogue)
456         output, lines = self.launch_subprocess('newmod')
457         self.assertEqual(len(lines), 10, "\n".join(lines))
458         for i in range(0, 3):
459             self.assertEqual(lines[i], "GreenThread-1", lines[i])
460         for i in range(3, 6):
461             self.assertEqual(lines[i], "foo", lines[i])
462         for i in range(6, 9):
463             self.assertEqual(lines[i], "bar", lines[i])
464
465     def test_ident(self):
466         self.write_to_tempfile("newmod", self.prologue + """
467     print(id(t._g))
468     print(t.ident)
469 """ + self.epilogue)
470         output, lines = self.launch_subprocess('newmod')
471         self.assertEqual(len(lines), 3, "\n".join(lines))
472         self.assertEqual(lines[0], lines[1])
473
474     def test_is_alive(self):
475         self.write_to_tempfile("newmod", self.prologue + """
476     print(t.is_alive())
477     print(t.isAlive())
478 """ + self.epilogue)
479         output, lines = self.launch_subprocess('newmod')
480         self.assertEqual(len(lines), 3, "\n".join(lines))
481         self.assertEqual(lines[0], "True", lines[0])
482         self.assertEqual(lines[1], "True", lines[1])
483
484     def test_is_daemon(self):
485         self.write_to_tempfile("newmod", self.prologue + """
486     print(t.is_daemon())
487     print(t.isDaemon())
488 """ + self.epilogue)
489         output, lines = self.launch_subprocess('newmod')
490         self.assertEqual(len(lines), 3, "\n".join(lines))
491         self.assertEqual(lines[0], "True", lines[0])
492         self.assertEqual(lines[1], "True", lines[1])
493
494
495 def test_importlib_lock():
496     output = run_python('tests/patcher_test_importlib_lock.py')
497     assert output.rstrip() == b'ok'
498
499
500 if __name__ == '__main__':
501     main()