Files
computer-playbook/tests/unit/python/plugins/lookup/test_sso_proxy_consumers.py
T
kevinveenbirkenbachandClaude Opus 5.5 0292751a27 test(lookup): restore sys.modules after loading the sso plugins fresh
test_sso.py, test_sso_oidc_plugin.py and test_sso_proxy_consumers.py evict utils.cache.applications, utils.cache and the roles packages from sys.modules to import their plugin against fresh modules, and never put the originals back. A later test module in the same worker then held two copies of utils.cache.applications: plugins.lookup.applications, imported earlier, kept calling the old one, while test_email patched and reset the new one, so its carrier tests counted 0 renders and failed depending only on which modules xdist placed in one worker.

_load_module now runs inside mock.patch.dict(sys.modules): the plugin keeps the fresh modules it was built against, and sys.modules returns to its prior state afterwards. `pytest test_sso.py test_email.py` failed test_worker_reads_the_provider_view_from_the_provider_carrier and test_worker_renders_when_the_provider_carrier_key_differs before; the three SSO modules followed by test_email.py now pass 66/66. Same patch-id as feature/store-i18n ec0fde6561.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-29 15:41:20 +01:00

134 lines
4.5 KiB
Python

"""Unit tests for the ``sso_proxy_consumers`` lookup plugin.
The plugin enumerates roles whose merged config satisfies
``services.sso.flavor == 'oauth2'`` AND ``services.sso.enabled``
potentially-truthy. The shape test (no terms) and the predicate test
(only oauth2-flavored, enabled consumers appear) are pinned here so
future contract changes are caught.
"""
import importlib
import importlib.util
import sys
import unittest
import unittest.mock as mock
from ansible.errors import AnsibleError
from . import PROJECT_ROOT
def _load_module(rel_path: str, name: str):
with mock.patch.dict(sys.modules):
for key in (
"utils.roles.applications.config",
"utils.roles.applications",
"utils",
"utils.cache.applications",
"utils.cache",
"utils.roles.applications.services.sso",
"utils.roles.applications.services",
):
sys.modules.pop(key, None)
importlib.import_module("utils.roles.applications.config")
importlib.import_module("utils.cache.applications")
importlib.import_module("utils.roles.applications.services.sso")
path = PROJECT_ROOT / rel_path
spec = importlib.util.spec_from_file_location(name, str(path))
mod = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(mod)
return mod
def _role(*, enabled=True, flavor="oauth2"):
sso: dict = {"enabled": enabled, "flavor": flavor}
return {"services": {"sso": sso}}
class SsoProxyConsumersLookupTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.mod = _load_module(
"plugins/lookup/sso_proxy_consumers.py", "sso_proxy_consumers"
)
def setUp(self):
self._original_loader = self.mod.lookup_loader
self._stub_payload = None
loader_mock = mock.MagicMock()
loader_mock.get.return_value = mock.MagicMock(
run=lambda *_a, **_k: [self._stub_payload]
)
self.mod.lookup_loader = loader_mock
def tearDown(self):
self.mod.lookup_loader = self._original_loader
def _run(self, applications, terms=None):
self._stub_payload = applications
lk = self.mod.LookupModule()
lk._loader = mock.MagicMock()
return lk.run(terms or [], variables={"applications": applications})
def test_positional_terms_raise(self):
with self.assertRaises(AnsibleError):
self._run({}, ["extra-arg"])
def test_empty_applications_returns_empty_list(self):
result = self._run({})
self.assertEqual(result, [[]])
def test_oauth2_enabled_consumer_is_included(self):
apps = {"web-app-a": _role(enabled=True, flavor="oauth2")}
result = self._run(apps)
self.assertEqual(result, [["web-app-a"]])
def test_oidc_consumer_is_excluded(self):
apps = {"web-app-a": _role(enabled=True, flavor="oidc")}
self.assertEqual(self._run(apps), [[]])
def test_disabled_oauth2_consumer_is_excluded(self):
apps = {"web-app-a": _role(enabled=False, flavor="oauth2")}
self.assertEqual(self._run(apps), [[]])
def test_mixed_apps_only_oauth2_enabled_returned(self):
apps = {
"web-app-a": _role(enabled=True, flavor="oauth2"),
"web-app-b": _role(enabled=True, flavor="oidc"),
"web-app-c": _role(enabled=False, flavor="oauth2"),
"web-app-d": _role(enabled=True, flavor="oauth2"),
"web-app-e": {"services": {}},
}
result = self._run(apps)
self.assertEqual(result, [["web-app-a", "web-app-d"]])
def test_result_is_alphabetically_sorted(self):
apps = {
"web-app-zeta": _role(enabled=True, flavor="oauth2"),
"web-app-alpha": _role(enabled=True, flavor="oauth2"),
"web-app-mu": _role(enabled=True, flavor="oauth2"),
}
result = self._run(apps)
self.assertEqual(result, [["web-app-alpha", "web-app-mu", "web-app-zeta"]])
def test_jinja_enabled_string_is_treated_as_potentially_truthy(self):
apps = {
"web-app-a": {
"services": {
"sso": {
"enabled": "{{ 'web-app-keycloak' in group_names }}",
"flavor": "oauth2",
}
}
}
}
result = self._run(apps)
self.assertEqual(result, [["web-app-a"]])
if __name__ == "__main__":
unittest.main()