From 861e708e9b526e25db36c264298708e7c1d3e2c7 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 19 Sep 2024 13:57:06 +0100 Subject: [PATCH 1/2] test: Make import-related tests stable The integrations not getting enabled when there are missing modules test was relying on certain packages not being installed in the environment and was causing issues when dev requirements was installed. This patch addse a context manager that simulates import errors for certain packages to make the test robust. It also enables the redis-related test by simulating a missing 'redis' package with the same context manager. --- tests/test_basics.py | 49 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/tests/test_basics.py b/tests/test_basics.py index 6f77353c8a..659173de84 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -28,6 +28,7 @@ from sentry_sdk.integrations import ( _AUTO_ENABLING_INTEGRATIONS, _DEFAULT_INTEGRATIONS, + DidNotEnable, Integration, setup_integrations, ) @@ -39,18 +40,6 @@ from sentry_sdk.tracing_utils import has_tracing_enabled -def _redis_installed(): # type: () -> bool - """ - Determines whether Redis is installed. - """ - try: - import redis # noqa: F401 - except ImportError: - return False - - return True - - class NoOpIntegration(Integration): """ A simple no-op integration for testing purposes. @@ -89,20 +78,34 @@ def error_processor(event, exc_info): assert event["exception"]["values"][0]["value"] == "aha! whatever" +class ModuleImportErrorSimulator: + def __init__(self, modules, error_cls=DidNotEnable): + self.modules = modules + self.error_cls = error_cls + for sys_module in list(sys.modules.keys()): + if any(sys_module.startswith(module) for module in modules): + del sys.modules[sys_module] + + def find_spec(self, fullname, _path, _target=None): + if fullname in self.modules: + raise self.error_cls("Test import failure for %s" % fullname) + + def __enter__(self): + sys.meta_path.insert(0, self) + + def __exit__(self, *_args): + sys.meta_path.remove(self) + + def test_auto_enabling_integrations_catches_import_error(sentry_init, caplog): caplog.set_level(logging.DEBUG) - redis_index = _AUTO_ENABLING_INTEGRATIONS.index( - "sentry_sdk.integrations.redis.RedisIntegration" - ) # noqa: N806 - sentry_init(auto_enabling_integrations=True, debug=True) + with ModuleImportErrorSimulator( + [i.rsplit(".", 1)[0] for i in _AUTO_ENABLING_INTEGRATIONS] + ): + sentry_init(auto_enabling_integrations=True, debug=True) for import_string in _AUTO_ENABLING_INTEGRATIONS: - # Ignore redis in the test case, because it does not raise a DidNotEnable - # exception on import; rather, it raises the exception upon enabling. - if _AUTO_ENABLING_INTEGRATIONS[redis_index] == import_string: - continue - assert any( record.message.startswith( "Did not import default integration {}:".format(import_string) @@ -874,9 +877,9 @@ def test_functions_to_trace_with_class(sentry_init, capture_events): assert event["spans"][1]["description"] == "tests.test_basics.WorldGreeter.greet" -@pytest.mark.skipif(_redis_installed(), reason="skipping because redis is installed") def test_redis_disabled_when_not_installed(sentry_init): - sentry_init() + with ModuleImportErrorSimulator(["redis"], ImportError): + sentry_init() assert sentry_sdk.get_client().get_integration(RedisIntegration) is None From 540edc6e164b0be6d67556af58659b342b7cc603 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 19 Sep 2024 14:49:37 +0100 Subject: [PATCH 2/2] add warning for future poor souls --- tests/test_basics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_basics.py b/tests/test_basics.py index 659173de84..e9659da809 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -91,6 +91,7 @@ def find_spec(self, fullname, _path, _target=None): raise self.error_cls("Test import failure for %s" % fullname) def __enter__(self): + # WARNING: We need to be first to avoid pytest messing with local imports sys.meta_path.insert(0, self) def __exit__(self, *_args):