Spaces:
Running
Running
| """Integration tests for the /estimate and /health endpoints.""" | |
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| from unittest.mock import patch | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| # -- helpers to build fake ecologits responses (same as unit tests) -- | |
| class _RangeValue: | |
| min: float | |
| max: float | |
| class _Metric: | |
| value: _RangeValue | |
| class _FakeImpactsOutput: | |
| gwp: _Metric | None = None | |
| energy: _Metric | None = None | |
| warnings: list | None = None | |
| errors: list | None = None | |
| def _make_impact(gwp_min: float = 0.001, gwp_max: float = 0.003): | |
| return _FakeImpactsOutput( | |
| gwp=_Metric(value=_RangeValue(min=gwp_min, max=gwp_max)), | |
| energy=_Metric(value=_RangeValue(min=0.01, max=0.02)), | |
| warnings=[], | |
| errors=[], | |
| ) | |
| # -- tests -- | |
| def test_health(client: TestClient): | |
| resp = client.get("/health") | |
| assert resp.status_code == 200 | |
| assert resp.json() == {"status": "ok"} | |
| def test_estimate_success(mock_llm_impacts, client: TestClient): | |
| mock_llm_impacts.return_value = _make_impact() | |
| resp = client.post("/estimate", json={ | |
| "provider": "openai", | |
| "model": "gpt-4o", | |
| "output_tokens": 500, | |
| "request_latency": 1.2, | |
| }) | |
| assert resp.status_code == 200 | |
| body = resp.json() | |
| assert body["status"] == "ok" | |
| assert body["data"] is not None | |
| assert body["data"]["gwp_avg_kgco2eq"] == pytest.approx(0.002) | |
| assert body["data"]["gwp_gco2eq"] == pytest.approx(2.0) | |
| assert body["data"]["equivalences"]["car_km"] > 0 | |
| assert body["data"]["equivalences"]["tgv_km"] > 0 | |
| def test_estimate_unknown_model(mock_llm_impacts, client: TestClient): | |
| """Unknown provider/model returns an error status, not HTTP 500.""" | |
| mock_llm_impacts.return_value = _FakeImpactsOutput( | |
| gwp=None, energy=None, warnings=[], errors=["Model not found"], | |
| ) | |
| resp = client.post("/estimate", json={ | |
| "provider": "unknown", | |
| "model": "no-model", | |
| "output_tokens": 100, | |
| "request_latency": 0.5, | |
| }) | |
| assert resp.status_code == 200 | |
| body = resp.json() | |
| assert body["status"] == "error" | |
| assert body["data"] is None | |
| assert len(body["errors"]) > 0 | |
| def test_estimate_missing_fields(client: TestClient): | |
| """Missing required fields should return 422.""" | |
| resp = client.post("/estimate", json={"provider": "openai"}) | |
| assert resp.status_code == 422 | |
| def test_estimate_invalid_token_count(client: TestClient): | |
| """output_tokens must be > 0.""" | |
| resp = client.post("/estimate", json={ | |
| "provider": "openai", | |
| "model": "gpt-4o", | |
| "output_tokens": 0, | |
| "request_latency": 1.0, | |
| }) | |
| assert resp.status_code == 422 | |
| def test_estimate_ecologits_crash(mock_llm_impacts, client: TestClient): | |
| """If ecologits raises, the API should return HTTP 500.""" | |
| mock_llm_impacts.side_effect = RuntimeError("unexpected") | |
| resp = client.post("/estimate", json={ | |
| "provider": "openai", | |
| "model": "gpt-4o", | |
| "output_tokens": 500, | |
| "request_latency": 1.0, | |
| }) | |
| assert resp.status_code == 500 | |