mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 02:05:22 -04:00
refactor(tests): centralize fake endpoint resolver cleanup
Test-only refactor continuing #2523. Centralizes the final repeated fake src.endpoint_resolver cleanup pattern into a focused import-state helper.
This commit is contained in:
committed by
GitHub
parent
301d1109b5
commit
452a94fb1b
@@ -6,6 +6,7 @@ import pytest
|
||||
|
||||
from tests.helpers.import_state import (
|
||||
clear_fake_database_modules,
|
||||
clear_fake_endpoint_resolver_modules,
|
||||
clear_module,
|
||||
preserve_import_state,
|
||||
)
|
||||
@@ -16,6 +17,16 @@ _SENTINEL = "tests._import_state_test_sentinel"
|
||||
# tests never leak into the real core/src packages.
|
||||
_DB_NAMES = ("core", "core.database", "src", "src.database")
|
||||
|
||||
# Names touched by clear_fake_endpoint_resolver_modules — snapshot/restore these
|
||||
# so the tests never leak into the real src/routes packages.
|
||||
_RESOLVER_NAMES = (
|
||||
"src",
|
||||
"src.endpoint_resolver",
|
||||
"routes",
|
||||
"routes.model_routes",
|
||||
"routes.chat_routes",
|
||||
)
|
||||
|
||||
|
||||
def test_absent_module_is_removed_after_block():
|
||||
assert _SENTINEL not in sys.modules
|
||||
@@ -250,3 +261,166 @@ def test_clear_fake_database_noop_when_nothing_cached():
|
||||
clear_fake_database_modules() # must not raise
|
||||
|
||||
assert "core.database" not in sys.modules
|
||||
|
||||
|
||||
def test_clear_fake_resolver_removes_stub_endpoint_resolver():
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
fake_resolver = types.ModuleType("src.endpoint_resolver") # no __file__ => stub
|
||||
fake_src.endpoint_resolver = fake_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = fake_resolver
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert "src.endpoint_resolver" not in sys.modules
|
||||
assert not hasattr(fake_src, "endpoint_resolver")
|
||||
|
||||
|
||||
def test_clear_fake_resolver_preserves_real_endpoint_resolver():
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
real_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
real_resolver.__file__ = "/somewhere/src/endpoint_resolver.py" # looks on-disk
|
||||
fake_src.endpoint_resolver = real_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = real_resolver
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert sys.modules["src.endpoint_resolver"] is real_resolver
|
||||
assert fake_src.endpoint_resolver is real_resolver
|
||||
|
||||
|
||||
def test_clear_fake_resolver_evicts_empty_file_resolver():
|
||||
"""A resolver with __file__ = "" is a stub under the old truthiness guard, so
|
||||
it (and its dependents) must be evicted, not preserved."""
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
empty_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
empty_resolver.__file__ = "" # falsy => stub
|
||||
fake_src.endpoint_resolver = empty_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = empty_resolver
|
||||
model_routes = types.ModuleType("routes.model_routes")
|
||||
sys.modules["routes.model_routes"] = model_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert "src.endpoint_resolver" not in sys.modules
|
||||
assert not hasattr(fake_src, "endpoint_resolver")
|
||||
assert "routes.model_routes" not in sys.modules
|
||||
|
||||
|
||||
def test_clear_fake_resolver_removes_model_routes_when_resolver_fake():
|
||||
"""model_routes is dropped, and its parent `routes` attr is cleared too —
|
||||
the behavior delta over the old bare sys.modules.pop() guards."""
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
fake_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
fake_src.endpoint_resolver = fake_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = fake_resolver
|
||||
|
||||
fake_routes = types.ModuleType("routes")
|
||||
model_routes = types.ModuleType("routes.model_routes")
|
||||
fake_routes.model_routes = model_routes
|
||||
sys.modules["routes"] = fake_routes
|
||||
sys.modules["routes.model_routes"] = model_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert "routes.model_routes" not in sys.modules
|
||||
assert not hasattr(fake_routes, "model_routes")
|
||||
|
||||
|
||||
def test_clear_fake_resolver_removes_extra_modules_when_resolver_fake():
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
fake_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
fake_src.endpoint_resolver = fake_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = fake_resolver
|
||||
|
||||
fake_routes = types.ModuleType("routes")
|
||||
chat_routes = types.ModuleType("routes.chat_routes")
|
||||
fake_routes.chat_routes = chat_routes
|
||||
sys.modules["routes"] = fake_routes
|
||||
sys.modules["routes.chat_routes"] = chat_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules("routes.chat_routes")
|
||||
|
||||
assert "routes.chat_routes" not in sys.modules
|
||||
assert not hasattr(fake_routes, "chat_routes")
|
||||
|
||||
|
||||
def test_clear_fake_resolver_keeps_dependents_when_resolver_real():
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
real_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
real_resolver.__file__ = "/somewhere/src/endpoint_resolver.py"
|
||||
fake_src.endpoint_resolver = real_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = real_resolver
|
||||
|
||||
model_routes = types.ModuleType("routes.model_routes")
|
||||
chat_routes = types.ModuleType("routes.chat_routes")
|
||||
sys.modules["routes.model_routes"] = model_routes
|
||||
sys.modules["routes.chat_routes"] = chat_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules("routes.chat_routes")
|
||||
|
||||
assert sys.modules["routes.model_routes"] is model_routes
|
||||
assert sys.modules["routes.chat_routes"] is chat_routes
|
||||
|
||||
|
||||
def test_clear_fake_resolver_noop_when_nothing_cached():
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
sys.modules.pop("src.endpoint_resolver", None)
|
||||
fake_src = types.ModuleType("src") # no endpoint_resolver attr
|
||||
sys.modules["src"] = fake_src
|
||||
model_routes = types.ModuleType("routes.model_routes")
|
||||
sys.modules["routes.model_routes"] = model_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules() # must not raise
|
||||
|
||||
assert "src.endpoint_resolver" not in sys.modules
|
||||
# dependents are left alone when the resolver was never cached
|
||||
assert sys.modules["routes.model_routes"] is model_routes
|
||||
|
||||
|
||||
def test_clear_fake_resolver_keeps_parent_attr_pointing_elsewhere():
|
||||
"""When the cached src.endpoint_resolver is a stub but the `endpoint_resolver`
|
||||
attr on the src package points at a *different* object, the attr is left
|
||||
intact — only the same fake object is unlinked."""
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
fake_src = types.ModuleType("src")
|
||||
cached_fake = types.ModuleType("src.endpoint_resolver") # the stub in sys.modules
|
||||
other = types.ModuleType("src.endpoint_resolver") # parent attr points here
|
||||
fake_src.endpoint_resolver = other
|
||||
sys.modules["src"] = fake_src
|
||||
sys.modules["src.endpoint_resolver"] = cached_fake
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert "src.endpoint_resolver" not in sys.modules
|
||||
assert fake_src.endpoint_resolver is other
|
||||
|
||||
|
||||
def test_clear_fake_resolver_uses_parent_attr_when_not_in_sys_modules():
|
||||
"""A stub reachable only via the src package's `endpoint_resolver` attribute
|
||||
(not in sys.modules) is still detected, unlinked, and triggers dependent
|
||||
eviction."""
|
||||
with preserve_import_state(*_RESOLVER_NAMES):
|
||||
sys.modules.pop("src.endpoint_resolver", None)
|
||||
fake_src = types.ModuleType("src")
|
||||
fake_resolver = types.ModuleType("src.endpoint_resolver")
|
||||
fake_src.endpoint_resolver = fake_resolver
|
||||
sys.modules["src"] = fake_src
|
||||
model_routes = types.ModuleType("routes.model_routes")
|
||||
sys.modules["routes.model_routes"] = model_routes
|
||||
|
||||
clear_fake_endpoint_resolver_modules()
|
||||
|
||||
assert not hasattr(fake_src, "endpoint_resolver")
|
||||
assert "routes.model_routes" not in sys.modules
|
||||
|
||||
Reference in New Issue
Block a user