diff --git a/setup.py b/setup.py index 881bf2c61..4c8491505 100755 --- a/setup.py +++ b/setup.py @@ -122,9 +122,9 @@ class test(Command): suite = unittest.defaultTestLoader.loadTestsFromName( self.test_suite) if self.xunit_output: - from xmlrunner import XMLTestRunner - runner = XMLTestRunner(verbosity=2, failfast=self.failfast, - output=self.xunit_output) + from test import PymongoXMLTestRunner + runner = PymongoXMLTestRunner(verbosity=2, failfast=self.failfast, + output=self.xunit_output) else: runner = PymongoTestRunner(verbosity=2, failfast=self.failfast) result = runner.run(suite) diff --git a/test/__init__.py b/test/__init__.py index 6f585f27e..5943d968f 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -15,6 +15,7 @@ """Test suite for pymongo, bson, and gridfs. """ +import gc import os import socket import sys @@ -23,6 +24,12 @@ import time import unittest import warnings +try: + from xmlrunner import XMLTestRunner + HAVE_XML = True +except ImportError: + HAVE_XML = False + try: import ipaddress HAVE_IPADDRESS = True @@ -53,6 +60,13 @@ try: except ImportError: pass +# Enable debug output for uncollectable objects. PyPy does not have set_debug. +if hasattr(gc, 'set_debug'): + gc.set_debug( + gc.DEBUG_UNCOLLECTABLE | + getattr(gc, 'DEBUG_OBJECTS', 0) | + getattr(gc, 'DEBUG_INSTANCES', 0)) + # The host and port of a single mongod or mongos, or the seed host # for a replica set. host = os.environ.get("DB_IP", 'localhost') @@ -779,22 +793,38 @@ def setup(): def teardown(): + garbage = [] + for g in gc.garbage: + garbage.append('GARBAGE: %r' % (g,)) + garbage.append(' gc.get_referents: %r' % (gc.get_referents(g),)) + garbage.append(' gc.get_referrers: %r' % (gc.get_referrers(g),)) + if garbage: + assert False, '\n'.join(garbage) c = client_context.client - c.drop_database("pymongo-pooling-tests") - c.drop_database("pymongo_test") - c.drop_database("pymongo_test1") - c.drop_database("pymongo_test2") - c.drop_database("pymongo_test_mike") - c.drop_database("pymongo_test_bernie") + if c: + c.drop_database("pymongo-pooling-tests") + c.drop_database("pymongo_test") + c.drop_database("pymongo_test1") + c.drop_database("pymongo_test2") + c.drop_database("pymongo_test_mike") + c.drop_database("pymongo_test_bernie") + c.close() class PymongoTestRunner(unittest.TextTestRunner): def run(self, test): setup() result = super(PymongoTestRunner, self).run(test) - try: + teardown() + return result + + +if HAVE_XML: + class PymongoXMLTestRunner(XMLTestRunner): + def run(self, test): + setup() + result = super(PymongoXMLTestRunner, self).run(test) teardown() - finally: return result diff --git a/test/test_change_stream.py b/test/test_change_stream.py index a4421f265..669c774a3 100644 --- a/test/test_change_stream.py +++ b/test/test_change_stream.py @@ -575,12 +575,13 @@ class ProseSpecTestsMixin(object): change_stream._cursor.close() raise OperationFailure('Mock server error', code=code) - original_try_next = change_stream._cursor._try_next + original_cursor = change_stream._cursor change_stream._cursor._try_next = mock_try_next try: yield finally: - change_stream._cursor._try_next = original_try_next + # Un patch the instance. + del original_cursor._try_next for code in TEST_ERROR_CODES: with self.change_stream() as change_stream: diff --git a/test/test_client.py b/test/test_client.py index 05e94b3d9..c547c98cb 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -1514,6 +1514,8 @@ class TestClient(IntegrationTest): return original_connect(*args, **kwargs) pool.connect = stall_connect + # Un-patch Pool.connect to break the cyclic reference. + self.addCleanup(delattr, pool, 'connect') # Wait for the background thread to start creating connections wait_until(lambda: len(pool.sockets) > 1, 'start creating connections') diff --git a/test/test_cmap.py b/test/test_cmap.py index 9a021f6b4..28de56633 100644 --- a/test/test_cmap.py +++ b/test/test_cmap.py @@ -376,6 +376,8 @@ class TestCMAP(IntegrationTest): sock_info.check_auth = functools.partial(mock_check_auth, sock_info) return sock_info pool.connect = mock_connect + # Un-patch Pool.connect to break the cyclic reference. + self.addCleanup(delattr, pool, 'connect') # Attempt to create a new connection. with self.assertRaisesRegex(ConnectionFailure, 'auth failed'):