ariadne/tests/test_services.py

1017 lines
35 KiB
Python
Raw Normal View History

2026-01-19 19:01:32 -03:00
from __future__ import annotations
import time
2026-01-19 19:01:32 -03:00
import types
import pytest
from ariadne.services.comms import CommsService
2026-01-19 19:01:32 -03:00
from ariadne.services.firefly import FireflyService
from ariadne.services.mailu import MailuService
2026-01-19 19:01:32 -03:00
from ariadne.services.nextcloud import NextcloudService
from ariadne.services.vault import VaultService
2026-01-19 19:01:32 -03:00
from ariadne.services.wger import WgerService
2026-01-20 00:06:50 -03:00
from ariadne.services.vaultwarden import VaultwardenService
2026-01-19 19:01:32 -03:00
class DummySpawner:
def __init__(self, namespace, cronjob, manifest=None):
2026-01-19 19:01:32 -03:00
self.namespace = namespace
self.cronjob = cronjob
self.calls = []
def trigger_and_wait(self, label_suffix, env_overrides, timeout_sec, job_ttl_seconds=None):
self.calls.append((label_suffix, env_overrides, timeout_sec, job_ttl_seconds))
return {"job": "test", "status": "ok"}
def trigger(self, label_suffix, env_overrides, job_ttl_seconds=None):
self.calls.append((label_suffix, env_overrides, job_ttl_seconds))
return {"job": "test", "status": "queued"}
class DummyClient:
def __init__(self):
self.url = ""
self.payload = None
self.status_code = 200
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
def post(self, url, json=None):
self.url = url
self.payload = json
return types.SimpleNamespace(status_code=self.status_code)
2026-01-20 00:06:50 -03:00
class DummyResponse:
def __init__(self, status_code=200, text=""):
self.status_code = status_code
self.text = text
def raise_for_status(self):
return None
class DummyVaultwardenClient:
def __init__(self):
self.calls = []
self.responses = {}
2026-01-20 00:06:50 -03:00
def post(self, path, json=None, data=None):
self.calls.append((path, json, data))
resp = self.responses.get(path)
if resp is None:
resp = DummyResponse(200, "")
return resp
2026-01-20 00:06:50 -03:00
def close(self):
return None
2026-01-19 19:01:32 -03:00
def test_nextcloud_sync_mail_builds_env(monkeypatch) -> None:
dummy = types.SimpleNamespace(
nextcloud_namespace="nextcloud",
nextcloud_mail_sync_cronjob="nextcloud-mail-sync",
nextcloud_mail_sync_wait_timeout_sec=90.0,
nextcloud_mail_sync_job_ttl_sec=3600,
)
monkeypatch.setattr("ariadne.services.nextcloud.settings", dummy)
monkeypatch.setattr(
"ariadne.services.nextcloud.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
2026-01-19 19:01:32 -03:00
svc = NextcloudService()
result = svc.sync_mail("alice", wait=True)
assert result["status"] == "ok"
spawner = svc._spawner
assert spawner.calls
label, env, timeout, ttl = spawner.calls[0]
assert label == "alice"
assert {item["name"]: item["value"] for item in env}["ONLY_USERNAME"] == "alice"
assert ttl == 3600
def test_wger_sync_user_env(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="health",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
monkeypatch.setattr(
"ariadne.services.wger.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
2026-01-19 19:01:32 -03:00
svc = WgerService()
result = svc.sync_user("alice", "alice@bstein.dev", "pw", wait=True)
assert result["status"] == "ok"
user_spawner = svc._user_spawner
label, env, _, _ = user_spawner.calls[0]
assert label == "alice"
env_map = {item["name"]: item["value"] for item in env}
assert env_map["WGER_USERNAME"] == "alice"
assert env_map["WGER_EMAIL"] == "alice@bstein.dev"
def test_wger_sync_user_queued(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="health",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
monkeypatch.setattr(
"ariadne.services.wger.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = WgerService()
result = svc.sync_user("alice", "alice@bstein.dev", "pw", wait=False)
assert result["status"] == "queued"
2026-01-19 19:01:32 -03:00
def test_firefly_sync_user_env(monkeypatch) -> None:
dummy = types.SimpleNamespace(
firefly_namespace="finance",
firefly_user_sync_cronjob="firefly-user-sync",
firefly_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.firefly.settings", dummy)
monkeypatch.setattr(
"ariadne.services.firefly.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
2026-01-19 19:01:32 -03:00
svc = FireflyService()
result = svc.sync_user("alice@bstein.dev", "pw", wait=True)
assert result["status"] == "ok"
spawner = svc._spawner
label, env, _, _ = spawner.calls[0]
assert label == "alice"
env_map = {item["name"]: item["value"] for item in env}
assert env_map["FIREFLY_USER_EMAIL"] == "alice@bstein.dev"
def test_firefly_sync_user_queued(monkeypatch) -> None:
dummy = types.SimpleNamespace(
firefly_namespace="finance",
firefly_user_sync_cronjob="firefly-user-sync",
firefly_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.firefly.settings", dummy)
monkeypatch.setattr(
"ariadne.services.firefly.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = FireflyService()
result = svc.sync_user("alice@bstein.dev", "pw", wait=False)
assert result["status"] == "queued"
def test_firefly_sync_missing_inputs(monkeypatch) -> None:
dummy = types.SimpleNamespace(
firefly_namespace="finance",
firefly_user_sync_cronjob="firefly-user-sync",
firefly_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.firefly.settings", dummy)
monkeypatch.setattr(
"ariadne.services.firefly.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = FireflyService()
with pytest.raises(RuntimeError):
svc.sync_user("", "pw", wait=True)
with pytest.raises(RuntimeError):
svc.sync_user("alice@bstein.dev", "", wait=True)
def test_firefly_sync_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
firefly_namespace="",
firefly_user_sync_cronjob="",
firefly_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.firefly.settings", dummy)
svc = FireflyService()
with pytest.raises(RuntimeError):
svc.sync_user("alice@bstein.dev", "pw", wait=True)
def test_vault_sync_jobs(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="vault",
vault_k8s_auth_cronjob="vault-k8s-auth-config",
vault_oidc_cronjob="vault-oidc-config",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
monkeypatch.setattr(
"ariadne.services.vault.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = VaultService()
result = svc.sync_k8s_auth(wait=True)
assert result["status"] == "ok"
spawner = svc._k8s_auth_spawner
label, _, timeout, _ = spawner.calls[0]
assert label == "k8s-auth"
assert timeout == 120.0
def test_vault_sync_k8s_auth_queue(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="vault",
vault_k8s_auth_cronjob="vault-k8s-auth-config",
vault_oidc_cronjob="vault-oidc-config",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
monkeypatch.setattr(
"ariadne.services.vault.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = VaultService()
result = svc.sync_k8s_auth(wait=False)
assert result["status"] == "queued"
def test_vault_sync_oidc_queue(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="vault",
vault_k8s_auth_cronjob="vault-k8s-auth-config",
vault_oidc_cronjob="vault-oidc-config",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
monkeypatch.setattr(
"ariadne.services.vault.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = VaultService()
result = svc.sync_oidc(wait=False)
assert result["status"] == "queued"
def test_vault_sync_oidc_wait(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="vault",
vault_k8s_auth_cronjob="vault-k8s-auth-config",
vault_oidc_cronjob="vault-oidc-config",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
monkeypatch.setattr(
"ariadne.services.vault.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = VaultService()
result = svc.sync_oidc(wait=True)
assert result["status"] == "ok"
def test_comms_jobs(monkeypatch) -> None:
dummy = types.SimpleNamespace(
comms_namespace="comms",
comms_guest_name_cronjob="guest-name-randomizer",
comms_pin_invite_cronjob="pin-othrys-invite",
comms_reset_room_cronjob="othrys-room-reset",
comms_seed_room_cronjob="seed-othrys-room",
comms_job_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.comms.settings", dummy)
monkeypatch.setattr(
"ariadne.services.comms.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = CommsService()
result = svc.run_guest_name_randomizer(wait=True)
assert result["status"] == "ok"
spawner = svc._guest_name_spawner
label, _, timeout, _ = spawner.calls[0]
assert label == "guest-name"
assert timeout == 60.0
def test_comms_pin_invite(monkeypatch) -> None:
dummy = types.SimpleNamespace(
comms_namespace="comms",
comms_guest_name_cronjob="guest-name-randomizer",
comms_pin_invite_cronjob="pin-othrys-invite",
comms_reset_room_cronjob="othrys-room-reset",
comms_seed_room_cronjob="seed-othrys-room",
comms_job_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.comms.settings", dummy)
monkeypatch.setattr(
"ariadne.services.comms.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = CommsService()
result = svc.run_pin_invite(wait=False)
assert result["status"] == "queued"
def test_comms_reset_and_seed(monkeypatch) -> None:
dummy = types.SimpleNamespace(
comms_namespace="comms",
comms_guest_name_cronjob="guest-name-randomizer",
comms_pin_invite_cronjob="pin-othrys-invite",
comms_reset_room_cronjob="othrys-room-reset",
comms_seed_room_cronjob="seed-othrys-room",
comms_job_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.comms.settings", dummy)
monkeypatch.setattr(
"ariadne.services.comms.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = CommsService()
assert svc.run_reset_room(wait=False)["status"] == "queued"
assert svc.run_seed_room(wait=True)["status"] == "ok"
def test_mailu_sync_includes_force(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="http://mailu",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
)
client = DummyClient()
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.mailu.httpx.Client", lambda *args, **kwargs: client)
svc = MailuService()
svc.sync("provision", force=True)
assert client.url == "http://mailu"
assert client.payload["wait"] is True
assert client.payload["force"] is True
def test_mailu_sync_skips_without_url(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
mailu_domain="bstein.dev",
)
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
svc = MailuService()
assert svc.sync("provision") is None
def test_mailu_sync_raises_on_error(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="http://mailu",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
)
client = DummyClient()
client.status_code = 500
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.mailu.httpx.Client", lambda *args, **kwargs: client)
svc = MailuService()
with pytest.raises(RuntimeError):
svc.sync("provision")
2026-01-20 00:06:50 -03:00
def test_vaultwarden_invite_uses_admin_session(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
client = DummyVaultwardenClient()
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: client)
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: "127.0.0.1"),
)
svc = VaultwardenService()
result = svc.invite_user("alice@bstein.dev")
assert result.ok is True
assert any(call[0] == "/admin" for call in client.calls)
assert any(call[0] == "/admin/invite" for call in client.calls)
def test_vaultwarden_invite_handles_rate_limit(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
2026-01-19 19:01:32 -03:00
)
client = DummyVaultwardenClient()
client.responses["/admin/invite"] = DummyResponse(429, "rate limited")
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: client)
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: "127.0.0.1"),
)
svc = VaultwardenService()
result = svc.invite_user("alice@bstein.dev")
assert result.status == "rate_limited"
def test_vaultwarden_invite_existing_user(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
client = DummyVaultwardenClient()
client.responses["/admin/invite"] = DummyResponse(409, "user already exists")
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: client)
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: "127.0.0.1"),
)
svc = VaultwardenService()
result = svc.invite_user("alice@bstein.dev")
assert result.status == "already_present"
def test_vaultwarden_invite_rejects_invalid_email() -> None:
svc = VaultwardenService()
result = svc.invite_user("bad-email")
assert result.status == "invalid_email"
def test_vaultwarden_invite_rate_limited_short_circuit() -> None:
svc = VaultwardenService()
svc._rate_limited_until = time.time() + 60
result = svc.invite_user("alice@bstein.dev")
assert result.status == "rate_limited"
def test_vaultwarden_invite_handles_admin_exception(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: (_ for _ in ()).throw(RuntimeError("boom"))),
)
svc = VaultwardenService()
monkeypatch.setattr(
svc,
"_admin_session",
lambda *_args, **_kwargs: (_ for _ in ()).throw(RuntimeError("rate limited")),
)
result = svc.invite_user("alice@bstein.dev")
assert result.status == "rate_limited"
def test_vaultwarden_invite_handles_bad_body(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
class BadTextResponse:
def __init__(self, status_code=500):
self.status_code = status_code
def raise_for_status(self):
return None
@property
def text(self):
raise RuntimeError("boom")
class BadTextClient(DummyVaultwardenClient):
def post(self, path, json=None, data=None):
self.calls.append((path, json, data))
return BadTextResponse(500)
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: BadTextClient())
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: "127.0.0.1"),
)
svc = VaultwardenService()
result = svc.invite_user("alice@bstein.dev")
assert result.status == "error"
def test_vaultwarden_invite_handles_fallback_skip(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr(
"ariadne.services.vaultwarden.VaultwardenService._find_pod_ip",
staticmethod(lambda *args, **kwargs: (_ for _ in ()).throw(RuntimeError("boom"))),
)
svc = VaultwardenService()
monkeypatch.setattr(svc, "_admin_session", lambda *_args, **_kwargs: (_ for _ in ()).throw(RuntimeError("nope")))
result = svc.invite_user("alice@bstein.dev")
assert result.status == "error"
def test_vaultwarden_find_pod_ip(monkeypatch) -> None:
monkeypatch.setattr(
"ariadne.services.vaultwarden.get_json",
lambda *args, **kwargs: {
"items": [
{
"status": {
"phase": "Running",
"podIP": "10.0.0.1",
"conditions": [{"type": "Ready", "status": "True"}],
}
}
]
},
)
assert VaultwardenService._find_pod_ip("ns", "app=vaultwarden") == "10.0.0.1"
def test_vaultwarden_find_pod_ip_skips_missing_ip(monkeypatch) -> None:
monkeypatch.setattr(
"ariadne.services.vaultwarden.get_json",
lambda *args, **kwargs: {
"items": [
{"status": {"phase": "Running", "podIP": ""}},
{"status": {"phase": "Running", "podIP": "10.0.0.2", "conditions": []}},
]
},
)
assert VaultwardenService._find_pod_ip("ns", "app=vaultwarden") == "10.0.0.2"
def test_vaultwarden_find_pod_ip_conditions_default_ready(monkeypatch) -> None:
monkeypatch.setattr(
"ariadne.services.vaultwarden.get_json",
lambda *args, **kwargs: {
"items": [
{"status": {"phase": "Running", "podIP": "10.0.0.3", "conditions": ["bad"]}},
]
},
)
assert VaultwardenService._find_pod_ip("ns", "app=vaultwarden") == "10.0.0.3"
def test_vaultwarden_find_pod_ip_no_pods(monkeypatch) -> None:
monkeypatch.setattr("ariadne.services.vaultwarden.get_json", lambda *args, **kwargs: {"items": []})
with pytest.raises(RuntimeError):
VaultwardenService._find_pod_ip("ns", "app=vaultwarden")
def test_vaultwarden_find_pod_ip_missing_ip(monkeypatch) -> None:
monkeypatch.setattr(
"ariadne.services.vaultwarden.get_json",
lambda *args, **kwargs: {
"items": [
{"status": {"phase": "Pending", "conditions": ["bad"]}},
]
},
)
with pytest.raises(RuntimeError):
VaultwardenService._find_pod_ip("ns", "app=vaultwarden")
def test_vaultwarden_admin_session_rate_limit(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=1,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
client = DummyVaultwardenClient()
client.responses["/admin"] = DummyResponse(429, "")
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: client)
svc = VaultwardenService()
with pytest.raises(RuntimeError):
svc._admin_session("http://vaultwarden")
def test_vaultwarden_admin_session_reuses_client() -> None:
svc = VaultwardenService()
svc._admin_client = DummyVaultwardenClient()
svc._admin_session_expires_at = time.time() + 60
svc._admin_session_base_url = "http://vaultwarden"
client = svc._admin_session("http://vaultwarden")
assert client is svc._admin_client
def test_vaultwarden_admin_session_rate_limited_until() -> None:
svc = VaultwardenService()
svc._rate_limited_until = time.time() + 60
with pytest.raises(RuntimeError):
svc._admin_session("http://vaultwarden")
def test_vaultwarden_admin_session_closes_existing(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
vaultwarden_namespace="vaultwarden",
vaultwarden_admin_secret_name="vaultwarden-admin",
vaultwarden_admin_secret_key="ADMIN_TOKEN",
vaultwarden_admin_rate_limit_backoff_sec=600,
vaultwarden_admin_session_ttl_sec=900,
vaultwarden_service_host="vaultwarden-service.vaultwarden.svc.cluster.local",
vaultwarden_pod_label="app=vaultwarden",
vaultwarden_pod_port=80,
)
class CloseFail:
def close(self):
raise RuntimeError("boom")
monkeypatch.setattr("ariadne.services.vaultwarden.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.vaultwarden.get_secret_value", lambda *args, **kwargs: "token")
monkeypatch.setattr("ariadne.services.vaultwarden.httpx.Client", lambda *args, **kwargs: DummyVaultwardenClient())
svc = VaultwardenService()
svc._admin_client = CloseFail()
svc._admin_session_expires_at = time.time() - 10
svc._admin_session_base_url = "http://old"
assert svc._admin_session("http://vaultwarden") is not None
def test_nextcloud_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
nextcloud_namespace="",
nextcloud_mail_sync_cronjob="",
nextcloud_mail_sync_wait_timeout_sec=90.0,
nextcloud_mail_sync_job_ttl_sec=3600,
)
monkeypatch.setattr("ariadne.services.nextcloud.settings", dummy)
svc = NextcloudService()
with pytest.raises(RuntimeError):
svc.sync_mail("alice")
def test_vault_sync_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="",
vault_k8s_auth_cronjob="",
vault_oidc_cronjob="",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
svc = VaultService()
with pytest.raises(RuntimeError):
svc.sync_k8s_auth(wait=True)
def test_vault_sync_oidc_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
vault_namespace="",
vault_k8s_auth_cronjob="",
vault_oidc_cronjob="",
vault_job_wait_timeout_sec=120.0,
)
monkeypatch.setattr("ariadne.services.vault.settings", dummy)
svc = VaultService()
with pytest.raises(RuntimeError):
svc.sync_oidc(wait=True)
def test_wger_sync_missing_inputs(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="health",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
monkeypatch.setattr(
"ariadne.services.wger.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = WgerService()
with pytest.raises(RuntimeError):
svc.sync_user("", "email", "pw", wait=True)
with pytest.raises(RuntimeError):
svc.sync_user("alice", "email", "", wait=True)
def test_wger_sync_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="",
wger_user_sync_cronjob="",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
svc = WgerService()
with pytest.raises(RuntimeError):
svc.sync_user("alice", "email", "pw", wait=True)
def test_wger_ensure_admin(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="health",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
monkeypatch.setattr(
"ariadne.services.wger.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = WgerService()
result = svc.ensure_admin(wait=True)
assert result["status"] == "ok"
def test_wger_ensure_admin_queue(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="health",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="wger-admin-ensure",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
monkeypatch.setattr(
"ariadne.services.wger.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = WgerService()
result = svc.ensure_admin(wait=False)
assert result["status"] == "queued"
def test_wger_ensure_admin_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
wger_namespace="",
wger_user_sync_cronjob="wger-user-sync",
wger_admin_cronjob="",
wger_user_sync_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.wger.settings", dummy)
svc = WgerService()
with pytest.raises(RuntimeError):
svc.ensure_admin(wait=True)
def test_comms_missing_config(monkeypatch) -> None:
dummy = types.SimpleNamespace(
comms_namespace="",
comms_guest_name_cronjob="guest-name-randomizer",
comms_pin_invite_cronjob="pin-othrys-invite",
comms_reset_room_cronjob="othrys-room-reset",
comms_seed_room_cronjob="seed-othrys-room",
comms_job_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.comms.settings", dummy)
svc = CommsService()
with pytest.raises(RuntimeError):
svc.run_guest_name_randomizer(wait=True)
def test_comms_missing_config_variants(monkeypatch) -> None:
dummy = types.SimpleNamespace(
comms_namespace="",
comms_guest_name_cronjob="guest-name-randomizer",
comms_pin_invite_cronjob="pin-othrys-invite",
comms_reset_room_cronjob="othrys-room-reset",
comms_seed_room_cronjob="seed-othrys-room",
comms_job_wait_timeout_sec=60.0,
)
monkeypatch.setattr("ariadne.services.comms.settings", dummy)
svc = CommsService()
with pytest.raises(RuntimeError):
svc.run_pin_invite(wait=True)
with pytest.raises(RuntimeError):
svc.run_reset_room(wait=True)
with pytest.raises(RuntimeError):
svc.run_seed_room(wait=True)
def test_mailu_mailbox_exists_handles_error(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
mailu_domain="bstein.dev",
)
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
monkeypatch.setattr("ariadne.services.mailu.psycopg.connect", lambda *args, **kwargs: (_ for _ in ()).throw(RuntimeError("boom")))
svc = MailuService()
assert svc.mailbox_exists("alice@bstein.dev") is False
def test_mailu_mailbox_exists_success(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
mailu_domain="bstein.dev",
)
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
class DummyCursor:
def execute(self, *_args, **_kwargs):
return None
def fetchone(self):
return {"id": 1}
def __enter__(self):
return self
def __exit__(self, *_args):
return False
class DummyConn:
def cursor(self):
return DummyCursor()
def __enter__(self):
return self
def __exit__(self, *_args):
return False
monkeypatch.setattr("ariadne.services.mailu.psycopg.connect", lambda *args, **kwargs: DummyConn())
svc = MailuService()
assert svc.mailbox_exists("alice@bstein.dev") is True
def test_mailu_wait_for_mailbox(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
mailu_domain="bstein.dev",
)
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
monkeypatch.setattr(MailuService, "mailbox_exists", lambda self, email: True)
svc = MailuService()
assert svc.wait_for_mailbox("alice@bstein.dev", timeout_sec=1.0) is True
def test_mailu_mailbox_exists_empty_email(monkeypatch) -> None:
dummy_settings = types.SimpleNamespace(
mailu_sync_url="",
mailu_sync_wait_timeout_sec=10.0,
mailu_db_host="localhost",
mailu_db_port=5432,
mailu_db_name="mailu",
mailu_db_user="mailu",
mailu_db_password="secret",
mailu_domain="bstein.dev",
)
monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings)
svc = MailuService()
assert svc.mailbox_exists("") is False
def test_nextcloud_sync_missing_username(monkeypatch) -> None:
dummy = types.SimpleNamespace(
nextcloud_namespace="nextcloud",
nextcloud_mail_sync_cronjob="nextcloud-mail-sync",
nextcloud_mail_sync_wait_timeout_sec=90.0,
nextcloud_mail_sync_job_ttl_sec=3600,
)
monkeypatch.setattr("ariadne.services.nextcloud.settings", dummy)
monkeypatch.setattr(
"ariadne.services.nextcloud.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = NextcloudService()
with pytest.raises(RuntimeError):
svc.sync_mail(" ", wait=True)
def test_nextcloud_sync_queue(monkeypatch) -> None:
dummy = types.SimpleNamespace(
nextcloud_namespace="nextcloud",
nextcloud_mail_sync_cronjob="nextcloud-mail-sync",
nextcloud_mail_sync_wait_timeout_sec=90.0,
nextcloud_mail_sync_job_ttl_sec=3600,
)
monkeypatch.setattr("ariadne.services.nextcloud.settings", dummy)
monkeypatch.setattr(
"ariadne.services.nextcloud.JobSpawner",
lambda ns, cj, manifest=None: DummySpawner(ns, cj, manifest),
)
svc = NextcloudService()
result = svc.sync_mail("alice", wait=False)
assert result["status"] == "queued"