summaryrefslogtreecommitdiff
path: root/test/engine/test_pool.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-07-22 17:59:34 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-07-22 18:03:36 -0400
commit4096ad0f0980f6940be57aaee85791df8f975cd7 (patch)
tree3cbba9826c3d8be0dfa4da2fa0241e5847d83d42 /test/engine/test_pool.py
parenta6e83b204ffc13817fd0ef5bd7483ec811704992 (diff)
downloadsqlalchemy-4096ad0f0980f6940be57aaee85791df8f975cd7.tar.gz
- Fixed critical issue whereby the pool "checkout" event handler
may be called against a stale connection without the "connect" event handler having been called, in the case where the pool attempted to reconnect after being invalidated and failed; the stale connection would remain present and would be used on a subsequent attempt. This issue has a greater impact in the 1.0 series subsequent to 1.0.2, as it also delivers a blanked-out ``.info`` dictionary to the event handler; prior to 1.0.2 the ``.info`` dictionary is still the previous one. fixes #3497
Diffstat (limited to 'test/engine/test_pool.py')
-rw-r--r--test/engine/test_pool.py95
1 files changed, 94 insertions, 1 deletions
diff --git a/test/engine/test_pool.py b/test/engine/test_pool.py
index 451cb8b0e..8551e1fcb 100644
--- a/test/engine/test_pool.py
+++ b/test/engine/test_pool.py
@@ -8,8 +8,9 @@ from sqlalchemy.testing import eq_, assert_raises, is_not_, is_
from sqlalchemy.testing.engines import testing_engine
from sqlalchemy.testing import fixtures
import random
-from sqlalchemy.testing.mock import Mock, call, patch
+from sqlalchemy.testing.mock import Mock, call, patch, ANY
import weakref
+import collections
join_timeout = 10
@@ -1480,6 +1481,98 @@ class QueuePoolTest(PoolTestBase):
time.sleep(1.5)
self._assert_cleanup_on_pooled_reconnect(dbapi, p)
+ def test_connect_handler_not_called_for_recycled(self):
+ """test [ticket:3497]"""
+
+ dbapi, p = self._queuepool_dbapi_fixture(
+ pool_size=2, max_overflow=2)
+
+ canary = Mock()
+
+ c1 = p.connect()
+ c2 = p.connect()
+
+ c1.close()
+ c2.close()
+
+ dbapi.shutdown(True)
+
+ bad = p.connect()
+ p._invalidate(bad)
+ bad.close()
+ assert p._invalidate_time
+
+ event.listen(p, "connect", canary.connect)
+ event.listen(p, "checkout", canary.checkout)
+
+ assert_raises(
+ Exception,
+ p.connect
+ )
+
+ p._pool.queue = collections.deque(
+ [
+ c for c in p._pool.queue
+ if c.connection is not None
+ ]
+ )
+
+ dbapi.shutdown(False)
+ c = p.connect()
+ c.close()
+
+ eq_(
+ canary.mock_calls,
+ [
+ call.connect(ANY, ANY),
+ call.checkout(ANY, ANY, ANY)
+ ]
+ )
+
+ def test_connect_checkout_handler_always_gets_info(self):
+ """test [ticket:3497]"""
+
+ dbapi, p = self._queuepool_dbapi_fixture(
+ pool_size=2, max_overflow=2)
+
+ c1 = p.connect()
+ c2 = p.connect()
+
+ c1.close()
+ c2.close()
+
+ dbapi.shutdown(True)
+
+ bad = p.connect()
+ p._invalidate(bad)
+ bad.close()
+ assert p._invalidate_time
+
+ @event.listens_for(p, "connect")
+ def connect(conn, conn_rec):
+ conn_rec.info['x'] = True
+
+ @event.listens_for(p, "checkout")
+ def checkout(conn, conn_rec, conn_f):
+ assert 'x' in conn_rec.info
+
+ assert_raises(
+ Exception,
+ p.connect
+ )
+
+ p._pool.queue = collections.deque(
+ [
+ c for c in p._pool.queue
+ if c.connection is not None
+ ]
+ )
+
+ dbapi.shutdown(False)
+ c = p.connect()
+ c.close()
+
+
def test_error_on_pooled_reconnect_cleanup_wcheckout_event(self):
dbapi, p = self._queuepool_dbapi_fixture(pool_size=1,
max_overflow=2)