]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
test: mark flaky ref count tests
authornialov <nikolasovaskainen@gmail.com>
Mon, 4 Dec 2023 17:33:46 +0000 (19:33 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 6 Dec 2023 16:46:25 +0000 (17:46 +0100)
All tests that have the 'gc' fixture are now marked with the refcount mark. The
reasoning is that they demonstrate flaky behaviour and disabling them in
certain CI is necessary to ensure reliable testing. See #692

tests/conftest.py
tests/fix_gc.py [new file with mode: 0644]

index f5d1623571fc263d948fb91cfc8b16fba44cdb3d..6647cfd9eab765669c3cbcb1ee02d71d9d199edf 100644 (file)
@@ -1,8 +1,7 @@
-import gc
-import sys
 import asyncio
 import selectors
-from typing import Any, Dict, List, Tuple
+import sys
+from typing import Any, Dict, List
 
 import pytest
 
@@ -14,6 +13,7 @@ pytest_plugins = (
     "tests.fix_proxy",
     "tests.fix_psycopg",
     "tests.fix_crdb",
+    "tests.fix_gc",
     "tests.pool.fix_pool",
 )
 
@@ -98,70 +98,3 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config):
         terminalreporter.section("failed tests ignored")
         for msg in allow_fail_messages:
             terminalreporter.line(msg)
-
-
-NO_COUNT_TYPES: Tuple[type, ...] = ()
-
-if sys.version_info[:2] == (3, 10):
-    # On my laptop there are occasional creations of a single one of these objects
-    # with empty content, which might be some Decimal caching.
-    # Keeping the guard as strict as possible, to be extended if other types
-    # or versions are necessary.
-    try:
-        from _contextvars import Context  # type: ignore
-    except ImportError:
-        pass
-    else:
-        NO_COUNT_TYPES += (Context,)
-
-
-class GCFixture:
-    __slots__ = ()
-
-    @staticmethod
-    def collect() -> None:
-        """
-        gc.collect(), but more insisting.
-        """
-        for i in range(3):
-            gc.collect()
-
-    @staticmethod
-    def count() -> int:
-        """
-        len(gc.get_objects()), with subtleties.
-        """
-
-        if not NO_COUNT_TYPES:
-            return len(gc.get_objects())
-
-        # Note: not using a list comprehension because it pollutes the objects list.
-        rv = 0
-        for obj in gc.get_objects():
-            if isinstance(obj, NO_COUNT_TYPES):
-                continue
-            rv += 1
-
-        return rv
-
-
-@pytest.fixture(name="gc")
-def fixture_gc():
-    """
-    Provides a consistent way to run garbage collection and count references.
-
-    **Note:** This will skip tests on PyPy.
-    """
-    if sys.implementation.name == "pypy":
-        pytest.skip(reason="depends on refcount semantics")
-    return GCFixture()
-
-
-@pytest.fixture
-def gc_collect():
-    """
-    Provides a consistent way to run garbage collection.
-
-    **Note:** This will *not* skip tests on PyPy.
-    """
-    return GCFixture.collect
diff --git a/tests/fix_gc.py b/tests/fix_gc.py
new file mode 100644 (file)
index 0000000..ead6c6b
--- /dev/null
@@ -0,0 +1,85 @@
+import gc
+import sys
+from typing import Tuple
+
+import pytest
+
+
+def pytest_collection_modifyitems(items):
+    for item in items:
+        if "gc" in item.fixturenames:
+            item.add_marker(pytest.mark.refcount)
+
+
+def pytest_configure(config):
+    config.addinivalue_line(
+        "markers",
+        "refcount: the test checks ref counts which is sometimes flaky",
+    )
+
+
+NO_COUNT_TYPES: Tuple[type, ...] = ()
+
+if sys.version_info[:2] == (3, 10):
+    # On my laptop there are occasional creations of a single one of these objects
+    # with empty content, which might be some Decimal caching.
+    # Keeping the guard as strict as possible, to be extended if other types
+    # or versions are necessary.
+    try:
+        from _contextvars import Context  # type: ignore
+    except ImportError:
+        pass
+    else:
+        NO_COUNT_TYPES += (Context,)
+
+
+class GCFixture:
+    __slots__ = ()
+
+    @staticmethod
+    def collect() -> None:
+        """
+        gc.collect(), but more insisting.
+        """
+        for i in range(3):
+            gc.collect()
+
+    @staticmethod
+    def count() -> int:
+        """
+        len(gc.get_objects()), with subtleties.
+        """
+
+        if not NO_COUNT_TYPES:
+            return len(gc.get_objects())
+
+        # Note: not using a list comprehension because it pollutes the objects list.
+        rv = 0
+        for obj in gc.get_objects():
+            if isinstance(obj, NO_COUNT_TYPES):
+                continue
+            rv += 1
+
+        return rv
+
+
+@pytest.fixture(name="gc")
+def fixture_gc():
+    """
+    Provides a consistent way to run garbage collection and count references.
+
+    **Note:** This will skip tests on PyPy.
+    """
+    if sys.implementation.name == "pypy":
+        pytest.skip(reason="depends on refcount semantics")
+    return GCFixture()
+
+
+@pytest.fixture
+def gc_collect():
+    """
+    Provides a consistent way to run garbage collection.
+
+    **Note:** This will *not* skip tests on PyPy.
+    """
+    return GCFixture.collect