import importlib.util import pathlib import pytest def load_sync_module(monkeypatch): # Minimal env required by module import env = { "KEYCLOAK_BASE_URL": "http://keycloak", "KEYCLOAK_REALM": "atlas", "KEYCLOAK_CLIENT_ID": "mailu-sync", "KEYCLOAK_CLIENT_SECRET": "secret", "MAILU_DOMAIN": "example.com", "MAILU_DB_HOST": "localhost", "MAILU_DB_PORT": "5432", "MAILU_DB_NAME": "mailu", "MAILU_DB_USER": "mailu", "MAILU_DB_PASSWORD": "pw", } for k, v in env.items(): monkeypatch.setenv(k, v) module_path = pathlib.Path(__file__).resolve().parents[1] / "mailu_sync.py" spec = importlib.util.spec_from_file_location("mailu_sync_testmod", module_path) module = importlib.util.module_from_spec(spec) assert spec.loader is not None spec.loader.exec_module(module) return module def test_random_password_length_and_charset(monkeypatch): sync = load_sync_module(monkeypatch) pw = sync.random_password() assert len(pw) == 24 assert all(ch.isalnum() for ch in pw) class _FakeResponse: def __init__(self, json_data=None, status=200): self._json_data = json_data or {} self.status_code = status def raise_for_status(self): if self.status_code >= 400: raise AssertionError(f"status {self.status_code}") def json(self): return self._json_data class _FakeSession: def __init__(self, put_resp, get_resp): self.put_resp = put_resp self.get_resp = get_resp self.put_called = False self.get_called = False def post(self, *args, **kwargs): return _FakeResponse({"access_token": "dummy"}) def put(self, *args, **kwargs): self.put_called = True return self.put_resp def get(self, *args, **kwargs): self.get_called = True return self.get_resp def test_kc_update_attributes_succeeds(monkeypatch): sync = load_sync_module(monkeypatch) ok_resp = _FakeResponse({"attributes": {"mailu_app_password": ["abc"]}}) sync.SESSION = _FakeSession(_FakeResponse({}), ok_resp) sync.kc_update_attributes("token", {"id": "u1", "username": "u1"}, {"mailu_app_password": "abc"}) assert sync.SESSION.put_called and sync.SESSION.get_called def test_kc_update_attributes_raises_without_attribute(monkeypatch): sync = load_sync_module(monkeypatch) missing_attr_resp = _FakeResponse({"attributes": {}}, status=200) sync.SESSION = _FakeSession(_FakeResponse({}), missing_attr_resp) with pytest.raises(Exception): sync.kc_update_attributes("token", {"id": "u1", "username": "u1"}, {"mailu_app_password": "abc"})