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