File size: 2,601 Bytes
88c0e85
 
 
 
 
2673d1c
 
88c0e85
 
 
 
2673d1c
 
 
 
88c0e85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""Behavioral tests for app.main helpers and handlers."""
from __future__ import annotations

import asyncio
import json
import sys
from pathlib import Path

from fastapi import HTTPException
from starlette.requests import Request

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

from app import main


def _dummy_request() -> Request:
    scope = {
        "type": "http",
        "http_version": "1.1",
        "method": "GET",
        "path": "/",
        "headers": [],
        "query_string": b"",
    }
    return Request(scope)


def test_root_returns_ok_when_no_failures(monkeypatch) -> None:
    monkeypatch.setattr(main, "_endpoint_status", {"failures": {}, "last_checked": None})
    payload = asyncio.run(main.root())
    assert payload == {"status": "ok", "message": "GPT3dev API is running"}


def test_root_returns_degraded_with_sorted_issues_and_last_checked(monkeypatch) -> None:
    monkeypatch.setattr(
        main,
        "_endpoint_status",
        {
            "failures": {
                "/v1/zeta": {"status_code": 503},
                "/v1/alpha": {"status_code": 500, "detail": "boom"},
            },
            "last_checked": "2026-02-05T12:00:00+00:00",
        },
    )
    payload = asyncio.run(main.root())

    assert payload["status"] == "degraded"
    assert payload["message"] == "GPT3dev API is running"
    assert payload["issues"][0]["endpoint"] == "/v1/alpha"
    assert payload["issues"][1]["endpoint"] == "/v1/zeta"
    assert payload["last_checked"] == "2026-02-05T12:00:00+00:00"


def test_openai_exception_handler_wraps_error_payload() -> None:
    exc = HTTPException(
        status_code=400,
        detail={
            "message": "bad request",
            "type": "invalid_request_error",
            "param": "model",
            "code": "bad_model",
        },
    )
    response = asyncio.run(main.openai_http_exception_handler(_dummy_request(), exc))

    assert response.status_code == 400
    assert json.loads(response.body.decode("utf-8")) == {
        "error": {
            "message": "bad request",
            "type": "invalid_request_error",
            "param": "model",
            "code": "bad_model",
        }
    }


def test_openai_exception_handler_preserves_generic_detail() -> None:
    exc = HTTPException(status_code=422, detail="unprocessable")
    response = asyncio.run(main.openai_http_exception_handler(_dummy_request(), exc))

    assert response.status_code == 422
    assert json.loads(response.body.decode("utf-8")) == {"detail": "unprocessable"}