From 0c34e786e354a2dc4388b22279dae91d74f93c43 Mon Sep 17 00:00:00 2001 From: drew2a Date: Thu, 13 Jul 2023 13:51:54 +0200 Subject: [PATCH] Add `ensure_gc` for each test call --- src/tribler/core/conftest.py | 24 ++++++++++++++++++++++++ src/tribler/gui/tests/conftest.py | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/tribler/core/conftest.py b/src/tribler/core/conftest.py index 1e19858a79c..266b3cfe5be 100644 --- a/src/tribler/core/conftest.py +++ b/src/tribler/core/conftest.py @@ -1,4 +1,5 @@ import asyncio +import gc import logging import platform import sys @@ -64,6 +65,29 @@ def pytest_runtest_protocol(item: Function, log=True, nextitem=None): yield + +@pytest.fixture(autouse=True) +def ensure_gc(): + """ Ensure that the garbage collector runs after each test. + This is critical for test stability as we use Libtorrent and need to ensure all its destructors are called. """ + # For this fixture, it is necessary for it to be called as late as possible within the current test's scope. + # Therefore it should be placed at the first place in the "function" scope. + # If there are two or more autouse fixtures within this scope, the order should be explicitly set through using + # this fixture as a dependency. + # See the discussion in https://github.com/Tribler/tribler/pull/7542 for more information. + + yield + # Without "yield" the fixture triggers the garbage collection at the beginning of the (next) test. + # For that reason, the errors triggered during the garbage collection phase will take place not in the erroneous + # test but in the randomly scheduled next test. Usually, these errors are silently suppressed, as any exception in + # __del__ methods is silently suppressed, but they still can somehow affect the test. + # + # By adding the yield we move the garbage collection phase to the end of the current test, to not affect the next + # test. + + gc.collect() + + @pytest.fixture def free_port(): return default_network_utils.get_random_free_port(start=1024, stop=50000) diff --git a/src/tribler/gui/tests/conftest.py b/src/tribler/gui/tests/conftest.py index f1519fe4d4d..30841a47ede 100644 --- a/src/tribler/gui/tests/conftest.py +++ b/src/tribler/gui/tests/conftest.py @@ -1,3 +1,4 @@ +import gc import logging import time @@ -61,3 +62,25 @@ def pytest_runtest_protocol(item, log=True, nextitem=None): total = time.time() - pytest_start_time if enable_extended_logging: print(f' in {duration:.3f}s ({total:.1f}s in total)', end='') + + +@pytest.fixture(autouse=True) +def ensure_gc(): + """ Ensure that the garbage collector runs after each test. + This is critical for test stability as we use Libtorrent and need to ensure all its destructors are called. """ + # For this fixture, it is necessary for it to be called as late as possible within the current test's scope. + # Therefore it should be placed at the first place in the "function" scope. + # If there are two or more autouse fixtures within this scope, the order should be explicitly set through using + # this fixture as a dependency. + # See the discussion in https://github.com/Tribler/tribler/pull/7542 for more information. + + yield + # Without "yield" the fixture triggers the garbage collection at the beginning of the (next) test. + # For that reason, the errors triggered during the garbage collection phase will take place not in the erroneous + # test but in the randomly scheduled next test. Usually, these errors are silently suppressed, as any exception in + # __del__ methods is silently suppressed, but they still can somehow affect the test. + # + # By adding the yield we move the garbage collection phase to the end of the current test, to not affect the next + # test. + + gc.collect()