1 # Copyright (c) 2007, Linden Research, Inc.
2 # Copyright (c) 2007, IBM Corp.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 from __future__ import print_function
23 from eventlet import tpool
24 from eventlet.support import six
25 from tests import LimitedTestCase, skipped, skip_with_pyevent, main
38 def raise_exception():
39 raise RuntimeError("hi")
42 class TestTpool(LimitedTestCase):
44 super(TestTpool, self).setUp()
48 super(TestTpool, self).tearDown()
51 def test_wrap_tuple(self):
53 prox = tpool.Proxy(my_tuple)
54 self.assertEqual(prox[0], 1)
55 self.assertEqual(prox[1], 2)
56 self.assertEqual(len(my_tuple), 2)
59 def test_wrap_string(self):
60 my_object = "whatever"
61 prox = tpool.Proxy(my_object)
62 self.assertEqual(str(my_object), str(prox))
63 self.assertEqual(len(my_object), len(prox))
64 self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b']))
67 def test_wrap_uniterable(self):
68 prox = tpool.Proxy([])
76 self.assertRaises(IndexError, index)
77 self.assertRaises(TypeError, key)
80 def test_wrap_dict(self):
82 prox = tpool.Proxy(my_object)
83 self.assertEqual('a', list(prox.keys())[0])
84 self.assertEqual(1, prox['a'])
85 self.assertEqual(str(my_object), str(prox))
86 self.assertEqual(repr(my_object), repr(prox))
89 def test_wrap_module_class(self):
90 prox = tpool.Proxy(re)
91 self.assertEqual(tpool.Proxy, type(prox))
92 exp = prox.compile('(.)(.)(.)')
93 self.assertEqual(exp.groups, 3)
94 assert repr(prox.compile)
97 def test_wrap_eq(self):
98 prox = tpool.Proxy(re)
99 exp1 = prox.compile('.')
100 exp2 = prox.compile(exp1.pattern)
101 self.assertEqual(exp1, exp2)
102 exp3 = prox.compile('/')
106 def test_wrap_ints(self):
111 def test_wrap_hash(self):
112 prox1 = tpool.Proxy('' + 'A')
113 prox2 = tpool.Proxy('A' + '')
116 # assert prox1 == prox2 FIXME - could __eq__ unwrap rhs if it is other proxy?
117 self.assertEqual(hash(prox1), hash(prox2))
118 proxList = tpool.Proxy([])
119 self.assertRaises(TypeError, hash, proxList)
122 def test_wrap_nonzero(self):
123 prox = tpool.Proxy(re)
124 exp1 = prox.compile('.')
126 prox2 = tpool.Proxy([1, 2, 3])
130 def test_multiple_wraps(self):
131 prox1 = tpool.Proxy(re)
132 prox2 = tpool.Proxy(re)
134 x2 = prox1.compile('.')
139 def test_wrap_getitem(self):
140 prox = tpool.Proxy([0, 1, 2])
141 self.assertEqual(prox[0], 0)
144 def test_wrap_setitem(self):
145 prox = tpool.Proxy([0, 1, 2])
147 self.assertEqual(prox[1], 2)
150 def test_wrap_iterator(self):
151 self.reset_timeout(2)
152 prox = tpool.Proxy(range(10))
156 self.assertEqual(list(range(10)), result)
159 def test_wrap_iterator2(self):
160 self.reset_timeout(5) # might take a while due to imprecise sleeping
171 for i in six.moves.range(20000):
173 if counter[0] % 20 == 0:
174 eventlet.sleep(0.0001)
178 gt = eventlet.spawn(tick)
180 for item in tpool.Proxy(foo()):
181 assert item >= previtem
182 # make sure the tick happened at least a few times so that we know
183 # that our iterations in foo() were actually tpooled
184 assert counter[0] > 10, counter[0]
188 def test_raising_exceptions(self):
189 prox = tpool.Proxy(re)
192 prox.never_name_a_function_like_this()
193 self.assertRaises(AttributeError, nofunc)
195 from tests import tpool_test
196 prox = tpool.Proxy(tpool_test)
197 self.assertRaises(RuntimeError, prox.raise_exception)
200 def test_variable_and_keyword_arguments_with_function_calls(self):
202 parser = tpool.Proxy(optparse.OptionParser())
203 parser.add_option('-n', action='store', type='string', dest='n')
204 opts, args = parser.parse_args(["-nfoo"])
205 self.assertEqual(opts.n, 'foo')
208 def test_contention(self):
209 from tests import tpool_test
210 prox = tpool.Proxy(tpool_test)
212 pile = eventlet.GreenPile(4)
213 pile.spawn(lambda: self.assertEqual(prox.one, 1))
214 pile.spawn(lambda: self.assertEqual(prox.two, 2))
215 pile.spawn(lambda: self.assertEqual(prox.three, 3))
217 self.assertEqual(len(results), 3)
220 def test_timeout(self):
222 eventlet.Timeout(0.1, eventlet.TimeoutError())
223 self.assertRaises(eventlet.TimeoutError,
224 tpool.execute, time.sleep, 0.3)
227 def test_killall(self):
232 def test_autowrap(self):
233 x = tpool.Proxy({'a': 1, 'b': 2}, autowrap=(int,))
234 assert isinstance(x.get('a'), tpool.Proxy)
235 assert not isinstance(x.items(), tpool.Proxy)
236 # attributes as well as callables
237 from tests import tpool_test
238 x = tpool.Proxy(tpool_test, autowrap=(int,))
239 assert isinstance(x.one, tpool.Proxy)
240 assert not isinstance(x.none, tpool.Proxy)
243 def test_autowrap_names(self):
244 x = tpool.Proxy({'a': 1, 'b': 2}, autowrap_names=('get',))
245 assert isinstance(x.get('a'), tpool.Proxy)
246 assert not isinstance(x.items(), tpool.Proxy)
247 from tests import tpool_test
248 x = tpool.Proxy(tpool_test, autowrap_names=('one',))
249 assert isinstance(x.one, tpool.Proxy)
250 assert not isinstance(x.two, tpool.Proxy)
253 def test_autowrap_both(self):
254 from tests import tpool_test
255 x = tpool.Proxy(tpool_test, autowrap=(int,), autowrap_names=('one',))
256 assert isinstance(x.one, tpool.Proxy)
257 # violating the abstraction to check that we didn't double-wrap
258 assert not isinstance(x._obj, tpool.Proxy)
261 def test_callable(self):
264 x = tpool.Proxy(wrapped)
265 self.assertEqual(4, x(4))
266 # verify that it wraps return values if specified
267 x = tpool.Proxy(wrapped, autowrap_names=('__call__',))
268 assert isinstance(x(4), tpool.Proxy)
269 self.assertEqual("4", str(x(4)))
272 def test_callable_iterator(self):
278 x = tpool.Proxy(wrapped, autowrap_names=('__call__',))
280 self.assertEqual(3, r)
283 def test_eventlet_timeout(self):
285 raise eventlet.Timeout()
286 self.assertRaises(eventlet.Timeout, tpool.execute, raise_timeout)
289 def test_tpool_set_num_threads(self):
290 tpool.set_num_threads(5)
291 self.assertEqual(5, tpool._nthreads)
294 class TpoolLongTests(LimitedTestCase):
298 def test_a_buncha_stuff(self):
299 assert_ = self.assert_
302 def foo(self, when, token=None):
303 assert_(token is not None)
304 time.sleep(random.random() / 200.0)
307 def sender_loop(loopnum):
308 obj = tpool.Proxy(Dummy())
310 for n in six.moves.range(count):
311 eventlet.sleep(random.random() / 200.0)
313 token = loopnum * count + n
314 rv = obj.foo(now, token=token)
315 self.assertEqual(token, rv)
316 eventlet.sleep(random.random() / 200.0)
319 pile = eventlet.GreenPile(cnt)
320 for i in six.moves.range(cnt):
321 pile.spawn(sender_loop, i)
323 self.assertEqual(len(results), cnt)
327 def test_benchmark(self):
328 """ Benchmark computing the amount of overhead tpool adds to function calls."""
332 from tests.tpool_test import noop
333 from eventlet.tpool import execute
335 t = timeit.Timer("noop()", imports)
336 results = t.repeat(repeat=3, number=iterations)
337 best_normal = min(results)
339 t = timeit.Timer("execute(noop)", imports)
340 results = t.repeat(repeat=3, number=iterations)
341 best_tpool = min(results)
343 tpool_overhead = (best_tpool - best_normal) / iterations
344 print("%s iterations\nTpool overhead is %s seconds per call. Normal: %s; Tpool: %s" % (
345 iterations, tpool_overhead, best_normal, best_tpool))
349 def test_leakage_from_tracebacks(self):
350 tpool.execute(noop) # get it started
352 initial_objs = len(gc.get_objects())
354 self.assertRaises(RuntimeError, tpool.execute, raise_exception)
356 middle_objs = len(gc.get_objects())
357 # some objects will inevitably be created by the previous loop
358 # now we test to ensure that running the loop an order of
359 # magnitude more doesn't generate additional objects
360 for i in six.moves.range(100):
361 self.assertRaises(RuntimeError, tpool.execute, raise_exception)
362 first_created = middle_objs - initial_objs
364 second_created = len(gc.get_objects()) - middle_objs
365 self.assert_(second_created - first_created < 10,
366 "first loop: %s, second loop: %s" % (first_created,
371 if __name__ == '__main__':