135 lines
4.5 KiB
Python
135 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
import httpx
|
|
|
|
from ariadne.services.mailu import MailuService
|
|
from ariadne.utils.errors import safe_error_detail
|
|
from ariadne.utils.http import extract_bearer_token
|
|
from ariadne.utils.name_generator import NameGenerator
|
|
from ariadne.utils.passwords import random_password
|
|
|
|
|
|
class DummyRequest:
|
|
def __init__(self, headers):
|
|
self.headers = headers
|
|
|
|
|
|
def test_random_password_length() -> None:
|
|
password = random_password(24)
|
|
assert len(password) == 24
|
|
assert re.match(r"^[A-Za-z0-9]+$", password)
|
|
|
|
|
|
def test_mailu_resolve_email_attribute() -> None:
|
|
attrs = {"mailu_email": ["custom@bstein.dev"]}
|
|
assert MailuService.resolve_mailu_email("alice", attrs) == "custom@bstein.dev"
|
|
|
|
|
|
def test_mailu_resolve_email_string() -> None:
|
|
attrs = {"mailu_email": "custom@bstein.dev"}
|
|
assert MailuService.resolve_mailu_email("alice", attrs) == "custom@bstein.dev"
|
|
|
|
|
|
def test_mailu_resolve_email_default() -> None:
|
|
assert MailuService.resolve_mailu_email("alice", {}) == "alice@bstein.dev"
|
|
|
|
|
|
def test_mailu_resolve_email_fallback() -> None:
|
|
assert (
|
|
MailuService.resolve_mailu_email("alice", {}, "alice@bstein.dev")
|
|
== "alice@bstein.dev"
|
|
)
|
|
|
|
|
|
def test_safe_error_detail_runtime() -> None:
|
|
assert safe_error_detail(RuntimeError("boom"), "fallback") == "boom"
|
|
|
|
|
|
def test_safe_error_detail_http_status_json() -> None:
|
|
request = httpx.Request("GET", "https://example.com")
|
|
response = httpx.Response(400, json={"errorMessage": "bad things"}, request=request)
|
|
exc = httpx.HTTPStatusError("bad", request=request, response=response)
|
|
|
|
detail = safe_error_detail(exc, "fallback")
|
|
assert "http 400" in detail
|
|
assert "bad things" in detail
|
|
|
|
|
|
def test_safe_error_detail_http_status_text() -> None:
|
|
request = httpx.Request("GET", "https://example.com")
|
|
response = httpx.Response(500, text="bad error", request=request)
|
|
exc = httpx.HTTPStatusError("bad", request=request, response=response)
|
|
|
|
detail = safe_error_detail(exc, "fallback")
|
|
assert "http 500" in detail
|
|
assert "bad error" in detail
|
|
|
|
|
|
def test_safe_error_detail_http_status_string() -> None:
|
|
request = httpx.Request("GET", "https://example.com")
|
|
response = httpx.Response(400, json="bad string", request=request)
|
|
exc = httpx.HTTPStatusError("bad", request=request, response=response)
|
|
|
|
detail = safe_error_detail(exc, "fallback")
|
|
assert "http 400" in detail
|
|
assert "bad string" in detail
|
|
|
|
|
|
def test_safe_error_detail_timeout() -> None:
|
|
exc = httpx.TimeoutException("timeout")
|
|
assert safe_error_detail(exc, "fallback") == "timeout"
|
|
|
|
|
|
def test_safe_error_detail_runtime_blank_uses_fallback() -> None:
|
|
assert safe_error_detail(RuntimeError(" "), "fallback") == "fallback"
|
|
|
|
|
|
def test_safe_error_detail_http_status_without_body() -> None:
|
|
request = httpx.Request("GET", "https://example.com")
|
|
response = httpx.Response(403, request=request)
|
|
exc = httpx.HTTPStatusError("bad", request=request, response=response)
|
|
|
|
assert safe_error_detail(exc, "fallback") == "http 403"
|
|
|
|
|
|
def test_safe_error_detail_unknown_exception_uses_fallback() -> None:
|
|
assert safe_error_detail(ValueError("boom"), "fallback") == "fallback"
|
|
|
|
|
|
def test_extract_bearer_token() -> None:
|
|
request = DummyRequest({"Authorization": "Bearer token123"})
|
|
assert extract_bearer_token(request) == "token123"
|
|
|
|
|
|
def test_extract_bearer_token_invalid() -> None:
|
|
request = DummyRequest({"Authorization": "Basic abc"})
|
|
assert extract_bearer_token(request) is None
|
|
|
|
|
|
def test_extract_bearer_token_missing_parts() -> None:
|
|
request = DummyRequest({"Authorization": "Bearer"})
|
|
assert extract_bearer_token(request) is None
|
|
|
|
|
|
def test_name_generator_unique_adds_candidate(monkeypatch) -> None:
|
|
generator = NameGenerator(max_attempts=2)
|
|
monkeypatch.setattr(NameGenerator, "generate", lambda self: "atlas-guest")
|
|
existing = {"taken"}
|
|
|
|
assert generator.unique(existing) == "atlas-guest"
|
|
assert "atlas-guest" in existing
|
|
|
|
|
|
def test_name_generator_unique_returns_none_after_retries(monkeypatch) -> None:
|
|
generator = NameGenerator(max_attempts=2)
|
|
monkeypatch.setattr(NameGenerator, "generate", lambda self: "taken")
|
|
assert generator.unique({"taken"}) is None
|
|
|
|
|
|
def test_name_generator_generate_normalizes_words(monkeypatch) -> None:
|
|
monkeypatch.setattr("ariadne.utils.name_generator.coolname.generate", lambda words: [" Atlas ", "", "Guest"])
|
|
generator = NameGenerator(words=3)
|
|
assert generator.generate() == "atlas-guest"
|