"""Tests for KeyringCredentialStore (mocked keyring backend).""" from __future__ import annotations import sys import types from typing import Any import pytest from ci_orchestrator.credentials import KeyringCredentialStore def _install_fake_keyring(monkeypatch: pytest.MonkeyPatch, **behaviour: Any) -> None: fake = types.ModuleType("keyring") def get_credential(target: str, _username: str | None) -> Any: return behaviour.get("credential_map", {}).get(target) def get_password(service: str, target: str) -> str | None: return behaviour.get("password_map", {}).get((service, target)) fake.get_credential = get_credential # type: ignore[attr-defined] fake.get_password = get_password # type: ignore[attr-defined] monkeypatch.setitem(sys.modules, "keyring", fake) class _FakeCred: def __init__(self, username: str, password: str) -> None: self.username = username self.password = password def test_get_returns_credential(monkeypatch: pytest.MonkeyPatch) -> None: _install_fake_keyring( monkeypatch, credential_map={"BuildVMGuest": _FakeCred("Administrator", "s3cret")}, ) cred = KeyringCredentialStore().get("BuildVMGuest") assert cred.username == "Administrator" assert cred.password == "s3cret" def test_get_falls_back_to_password(monkeypatch: pytest.MonkeyPatch) -> None: _install_fake_keyring( monkeypatch, credential_map={}, password_map={("ci", "GiteaPAT"): "tokentoken"}, ) cred = KeyringCredentialStore().get("GiteaPAT") assert cred.username == "GiteaPAT" assert cred.password == "tokentoken" def test_get_raises_when_missing(monkeypatch: pytest.MonkeyPatch) -> None: _install_fake_keyring(monkeypatch, credential_map={}, password_map={}) with pytest.raises(KeyError): KeyringCredentialStore().get("Unknown")