Skip to content

Commit eaeeac9

Browse files
author
A. Jesse Jiryu Davis
committed
Refactoring and increased reliability in Python 2.4 and PyPy for test_pooling. Skip tests known to fail in Jython.
1 parent 14a0c7b commit eaeeac9

File tree

1 file changed

+41
-11
lines changed

1 file changed

+41
-11
lines changed

test/test_pooling.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Test built in connection-pooling."""
1616

17+
import gc
1718
import os
1819
import random
1920
import sys
@@ -236,6 +237,35 @@ def test_max_pool_size_validation(self):
236237
c = Connection(host=host, port=port, max_pool_size=100)
237238
self.assertEqual(c.max_pool_size, 100)
238239

240+
def force_reclaim_sockets(self, cx_pool, n_expected):
241+
# When a thread dies without ending its request, the SocketInfo it was
242+
# using is deleted, and in its __del__ it returns the socket to the
243+
# pool. However, when exactly that happens is unpredictable. Try
244+
# various ways of forcing the issue.
245+
246+
if sys.platform.startswith('java'):
247+
raise SkipTest("Jython can't reclaim sockets")
248+
249+
# Bizarre behavior in CPython 2.4, and possibly other CPython versions
250+
# less than 2.7: the last dead thread's locals aren't cleaned up until
251+
# the local attribute with the same name is accessed from a different
252+
# thread. This assert checks that the thread-local is indeed local, and
253+
# also triggers the cleanup so the socket is reclaimed.
254+
self.assertEqual(None, cx_pool.local.sock_info)
255+
256+
# In PyPy, we need to try for a while to make garbage-collection call
257+
# SocketInfo.__del__
258+
start = time.time()
259+
while len(cx_pool.sockets) < n_expected and time.time() - start < 5:
260+
import gc
261+
try:
262+
gc.collect(2)
263+
except TypeError:
264+
# collect() didn't support 'generation' arg until 2.5
265+
gc.collect()
266+
267+
time.sleep(0.5)
268+
239269
def test_no_disconnect(self):
240270
run_cases(self, [NoRequest, NonUnique, Unique, SaveAndFind])
241271

@@ -500,7 +530,7 @@ def run_in_request():
500530

501531
def test_socket_reclamation(self):
502532
# Check that if a thread starts a request and dies without ending
503-
# the request, that the socket is reclaimed
533+
# the request, that the socket is reclaimed into the pool.
504534
cx_pool = Pool(
505535
pair=(host,port),
506536
max_size=10,
@@ -517,21 +547,24 @@ def test_socket_reclamation(self):
517547
the_sock = [None]
518548

519549
def leak_request():
550+
self.assertEqual(NO_REQUEST, cx_pool.local.sock_info)
520551
cx_pool.start_request()
552+
self.assertEqual(NO_SOCKET_YET, cx_pool.local.sock_info)
521553
sock_info = cx_pool.get_socket()
522-
lock.release()
523-
cx_pool._reset()
554+
self.assertEqual(sock_info, cx_pool.local.sock_info)
524555
the_sock[0] = id(sock_info.sock)
556+
lock.release()
525557

526558
# Start a thread WITHOUT a threading.Thread - important to test that
527559
# Pool can deal with primitive threads.
528560
thread.start_new_thread(leak_request, ())
529561

530562
# Join thread
531-
time.sleep(0.5)
532-
acquired = lock.acquire(0)
563+
acquired = lock.acquire(1)
533564
self.assertTrue(acquired, "Thread is hung")
534565

566+
self.force_reclaim_sockets(cx_pool, 1)
567+
535568
# Pool reclaimed the socket
536569
self.assertEqual(1, len(cx_pool.sockets))
537570
self.assertEqual(the_sock[0], id((iter(cx_pool.sockets).next()).sock))
@@ -550,17 +583,14 @@ def _test_max_pool_size(self, c, start_request, end_request):
550583
self.assert_(t.passed)
551584

552585
# Critical: release refs to threads, so SocketInfo.__del__() executes
553-
import sys; print >> sys.stderr, "Deleting threads"
554586
del threads
555587
t = None
556-
import sys; print >> sys.stderr, "Deleted"
557588

558-
# Let all the SocketInfo destructors execute and return sockets to
559-
# the pool
560-
time.sleep(1)
589+
cx_pool = c._Connection__pool
590+
self.force_reclaim_sockets(cx_pool, 4)
561591

562592
# There's a race condition, so be lenient
563-
nsock = len(c._Connection__pool.sockets)
593+
nsock = len(cx_pool.sockets)
564594
self.assert_(
565595
abs(4 - nsock) < 4,
566596
"Expected about 4 sockets in the pool, got %d" % nsock

0 commit comments

Comments
 (0)