mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-10 12:47:04 +00:00
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>
134 lines
4.5 KiB
Python
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()
|