diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-01-14 18:07:14 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-01-15 00:29:12 -0500 |
| commit | 44034f19ac27ccd4a0e57dfa3d2d6b494dc9b133 (patch) | |
| tree | 9837f4818d8e345fc36fe99cd888825832a6b98e /lib/sqlalchemy/testing | |
| parent | 41ca37734aa4f293ac5fb63c239d78185c8ec983 (diff) | |
| download | sqlalchemy-44034f19ac27ccd4a0e57dfa3d2d6b494dc9b133.tar.gz | |
Create explicit GC ordering between ConnectionFairy/ConnectionRecord
Fixed issue where connection pool would not return connections to the pool
or otherwise be finalized upon garbage collection under pypy if the checked
out connection fell out of scope without being closed. This is a long
standing issue due to pypy's difference in GC behavior that does not call
weakref finalizers if they are relative to another object that is also
being garbage collected. A strong reference to the related record is now
maintained so that the weakref has a strong-referenced "base" to trigger
off of.
Fixes: #5842
Change-Id: Id5448fdacb6cceaac1ea40b2fbc851f052ed8e86
Diffstat (limited to 'lib/sqlalchemy/testing')
| -rw-r--r-- | lib/sqlalchemy/testing/assertions.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/testing/engines.py | 14 | ||||
| -rw-r--r-- | lib/sqlalchemy/testing/plugin/plugin_base.py | 1 |
3 files changed, 19 insertions, 8 deletions
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py index 40549f54c..f2ed91b79 100644 --- a/lib/sqlalchemy/testing/assertions.py +++ b/lib/sqlalchemy/testing/assertions.py @@ -228,6 +228,10 @@ def is_none(a, msg=None): is_(a, None, msg=msg) +def is_not_none(a, msg=None): + is_not(a, None, msg=msg) + + def is_true(a, msg=None): is_(bool(a), True, msg=msg) @@ -236,14 +240,6 @@ def is_false(a, msg=None): is_(bool(a), False, msg=msg) -def is_none(a, msg=None): - is_(a, None, msg=msg) - - -def is_not_none(a, msg=None): - is_not(a, None, msg=msg) - - def is_(a, b, msg=None): """Assert a is b, with repr messaging on failure.""" assert a is b, msg or "%r is not %r" % (a, b) diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py index 8b334fde2..a313c298a 100644 --- a/lib/sqlalchemy/testing/engines.py +++ b/lib/sqlalchemy/testing/engines.py @@ -14,6 +14,7 @@ import weakref from . import config from .util import decorator +from .util import gc_collect from .. import event from .. import pool @@ -124,6 +125,19 @@ class ConnectionKiller(object): self._drop_testing_engines("function") self._drop_testing_engines("class") + def stop_test_class_outside_fixtures(self): + # ensure no refs to checked out connections at all. + + if pool.base._strong_ref_connection_records: + gc_collect() + + if pool.base._strong_ref_connection_records: + ln = len(pool.base._strong_ref_connection_records) + pool.base._strong_ref_connection_records.clear() + assert ( + False + ), "%d connection recs not cleared after test suite" % (ln) + def final_cleanup(self): self.checkin_all() for scope in self.testing_engines: diff --git a/lib/sqlalchemy/testing/plugin/plugin_base.py b/lib/sqlalchemy/testing/plugin/plugin_base.py index 7851fbb3e..858814f91 100644 --- a/lib/sqlalchemy/testing/plugin/plugin_base.py +++ b/lib/sqlalchemy/testing/plugin/plugin_base.py @@ -586,6 +586,7 @@ def stop_test_class(cls): def stop_test_class_outside_fixtures(cls): + engines.testing_reaper.stop_test_class_outside_fixtures() provision.stop_test_class_outside_fixtures(config, config.db, cls) try: if not options.low_connections: |
