File size: 3,099 Bytes
020b38e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a1da8b
 
 
 
 
 
 
020b38e
 
 
 
 
4a1da8b
 
 
 
 
020b38e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a1da8b
020b38e
4a1da8b
020b38e
 
 
 
 
4a1da8b
020b38e
 
 
 
 
4a1da8b
020b38e
 
 
 
 
 
 
 
4a1da8b
 
 
 
 
 
 
 
 
 
 
 
020b38e
 
 
 
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import pytest
from fastapi.testclient import TestClient

from api import main


@pytest.fixture
def client():
    return TestClient(main.app)


def test_health_check_reports_readiness(client):
    response = client.get("/")

    assert response.status_code == 200
    body = response.json()
    assert body["status"] == "ok"
    assert body["model_ready"] is False


def test_predict_returns_the_documented_schema(client, monkeypatch):
    monkeypatch.setattr(
        main,
        "analyze_text",
        lambda text: {
            "label": "POSITIVE",
            "score": 0.99,
            "irony": {"detected": True, "score": 0.87},
        },
    )

    response = client.post("/predict", json={"text": "wonderful"})

    assert response.status_code == 200
    assert response.json() == {
        "label": "POSITIVE",
        "score": 0.99,
        "irony": {"detected": True, "score": 0.87},
    }


def test_predict_rejects_empty_text(client):
    response = client.post("/predict", json={"text": ""})

    assert response.status_code == 422


def test_predict_rejects_a_missing_field(client):
    response = client.post("/predict", json={})

    assert response.status_code == 422


def test_predict_does_not_leak_internal_errors(client, monkeypatch):
    def explode(text):
        raise RuntimeError("secret internal detail")

    monkeypatch.setattr(main, "analyze_text", explode)

    response = client.post("/predict", json={"text": "anything"})

    assert response.status_code == 500
    assert "secret internal detail" not in response.text


def test_lifespan_marks_the_model_ready(monkeypatch, fake_pipeline, fake_irony):
    monkeypatch.setattr(main, "get_model", lambda: fake_pipeline)
    monkeypatch.setattr(main, "get_irony_model", lambda: fake_irony)

    with TestClient(main.app) as client:
        assert client.get("/").json()["model_ready"] is True


def test_lifespan_survives_a_failed_load(monkeypatch, fake_irony):
    """A missing checkpoint must degrade the service, not crash-loop it."""
    def explode():
        raise OSError("no checkpoint")

    monkeypatch.setattr(main, "get_model", explode)
    monkeypatch.setattr(main, "get_irony_model", lambda: fake_irony)

    with TestClient(main.app) as client:
        response = client.get("/")

    assert response.status_code == 200
    assert response.json()["model_ready"] is False


def test_readiness_covers_the_irony_head(monkeypatch, fake_pipeline):
    """Every response carries an irony verdict, so one head loaded is not ready."""
    def explode():
        raise OSError("no graph")

    monkeypatch.setattr(main, "get_model", lambda: fake_pipeline)
    monkeypatch.setattr(main, "get_irony_model", explode)

    with TestClient(main.app) as client:
        assert client.get("/").json()["model_ready"] is False


def test_the_example_reaches_the_openapi_document(client):
    schema = client.get("/openapi.json").json()

    assert "example" in schema["components"]["schemas"]["SentimentRequest"]