from __future__ import annotations from typing import Any from fastapi.testclient import TestClient from gibby.app import create_app from gibby.manager import AccountManager, NoUsableAccountError class StubManager(AccountManager): def __init__( self, response: dict[str, Any] | None = None, usage_response: dict[str, Any] | None = None, error: Exception | None = None, ): self.response = response self.usage_response = usage_response self.error = error async def issue_token_response(self): if self.error is not None: raise self.error if self.response is not None: return self.response return {} async def get_usage_report(self): if self.usage_response is not None: return self.usage_response return {"accounts": [], "active_account_id": None, "count": 0} def test_health_ok() -> None: client = TestClient(create_app(StubManager(response={}))) response = client.get("/health") assert response.status_code == 200 assert response.text == "ok" def test_token_success_shape() -> None: payload = { "token": "abc", "limit": { "used_percent": 10, "remaining_percent": 90, "exhausted": False, "needs_prepare": False, }, "usage": {"primary_window": None, "secondary_window": None}, } client = TestClient(create_app(StubManager(response=payload))) response = client.get("/token") assert response.status_code == 200 assert response.json() == payload def test_token_error_shape() -> None: client = TestClient( create_app( StubManager(error=NoUsableAccountError("No usable account available")) ) ) response = client.get("/token") assert response.status_code == 503 assert response.json() == {"error": "No usable account available"} def test_usage_success_shape() -> None: payload = { "accounts": [ { "id": "a1", "email": "a1@example.com", "status": "ok", "used_percent": 12, "remaining_percent": 88, "cooldown_until": None, "primary_window": {"used_percent": 12}, "secondary_window": {"used_percent": 1}, } ], "active_account_id": "a1", "count": 1, } client = TestClient(create_app(StubManager(usage_response=payload))) response = client.get("/usage") assert response.status_code == 200 assert response.json() == payload