gpt3-dev-api / tests /test_router_error_paths.py
Kyryll Kochkin
AI added tests
88c0e85
"""Router-level error path tests for OpenAI-compatible payloads."""
from __future__ import annotations
import asyncio
import pytest
from fastapi import HTTPException
from app.core.model_registry import ModelSpec
from app.routers import chat, completions, embeddings, responses
from app.schemas.chat import ChatCompletionRequest
from app.schemas.completions import CompletionRequest
from app.schemas.responses import ResponseRequest
def _raise_key_error(_: str) -> None:
raise KeyError("unknown")
def test_completions_unknown_model_returns_404_openai_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("app.routers.completions.get_model_spec", _raise_key_error)
payload = CompletionRequest.model_validate({"model": "missing", "prompt": "Hi"})
with pytest.raises(HTTPException) as exc:
asyncio.run(completions.create_completion(payload))
assert exc.value.status_code == 404
assert exc.value.detail["type"] == "model_not_found"
assert exc.value.detail["param"] == "model"
assert exc.value.detail["code"] == "model_not_found"
def test_chat_unknown_model_returns_404_openai_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("app.routers.chat.get_model_spec", _raise_key_error)
payload = ChatCompletionRequest.model_validate(
{
"model": "missing",
"messages": [{"role": "user", "content": "Hi"}],
}
)
with pytest.raises(HTTPException) as exc:
asyncio.run(chat.create_chat_completion(payload))
assert exc.value.status_code == 404
assert exc.value.detail["type"] == "model_not_found"
assert exc.value.detail["param"] == "model"
assert exc.value.detail["code"] == "model_not_found"
def test_responses_unknown_model_returns_404_openai_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("app.routers.responses.get_model_spec", _raise_key_error)
payload = ResponseRequest.model_validate({"model": "missing", "input": "Hi"})
with pytest.raises(HTTPException) as exc:
asyncio.run(responses.create_response(payload))
assert exc.value.status_code == 404
assert exc.value.detail["type"] == "model_not_found"
assert exc.value.detail["param"] == "model"
assert exc.value.detail["code"] == "model_not_found"
def test_completions_generation_exception_returns_generation_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def boom(*_: object, **__: object) -> None:
raise RuntimeError("boom")
monkeypatch.setattr("app.routers.completions.get_model_spec", lambda _: None)
monkeypatch.setattr("app.routers.completions.engine.generate", boom)
payload = CompletionRequest.model_validate({"model": "GPT3-dev", "prompt": "Hi"})
with pytest.raises(HTTPException) as exc:
asyncio.run(completions.create_completion(payload))
assert exc.value.status_code == 500
assert exc.value.detail["type"] == "server_error"
assert exc.value.detail["code"] == "generation_error"
assert "Generation error:" in exc.value.detail["message"]
def test_chat_generation_exception_returns_generation_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def boom(*_: object, **__: object) -> None:
raise RuntimeError("boom")
monkeypatch.setattr(
"app.routers.chat.get_model_spec",
lambda model: ModelSpec(name=model, hf_repo="dummy/instruct", is_instruct=True),
)
monkeypatch.setattr("app.routers.chat.engine.apply_chat_template", lambda *_: "prompt")
monkeypatch.setattr("app.routers.chat.engine.generate", boom)
payload = ChatCompletionRequest.model_validate(
{
"model": "GPT4-dev-177M-1511-Instruct",
"messages": [{"role": "user", "content": "Hi"}],
}
)
with pytest.raises(HTTPException) as exc:
asyncio.run(chat.create_chat_completion(payload))
assert exc.value.status_code == 500
assert exc.value.detail["type"] == "server_error"
assert exc.value.detail["code"] == "generation_error"
assert "Generation error:" in exc.value.detail["message"]
def test_responses_generation_exception_returns_generation_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def boom(*_: object, **__: object) -> None:
raise RuntimeError("boom")
monkeypatch.setattr(
"app.routers.responses.get_model_spec",
lambda model: ModelSpec(name=model, hf_repo="dummy/base", is_instruct=False),
)
monkeypatch.setattr("app.routers.responses.engine.generate", boom)
payload = ResponseRequest.model_validate({"model": "GPT3-dev", "input": "Hi"})
with pytest.raises(HTTPException) as exc:
asyncio.run(responses.create_response(payload))
assert exc.value.status_code == 500
assert exc.value.detail["type"] == "server_error"
assert exc.value.detail["code"] == "generation_error"
assert "Generation error:" in exc.value.detail["message"]
def test_responses_structured_input_with_non_instruct_model_returns_400(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(
"app.routers.responses.get_model_spec",
lambda model: ModelSpec(name=model, hf_repo="dummy/base", is_instruct=False),
)
payload = ResponseRequest.model_validate(
{
"model": "GPT3-dev",
"input": [{"role": "user", "content": "Hi"}],
}
)
with pytest.raises(HTTPException) as exc:
asyncio.run(responses.create_response(payload))
assert exc.value.status_code == 400
assert exc.value.detail["type"] == "invalid_request_error"
assert exc.value.detail["param"] == "model"
assert "not an instruct model" in exc.value.detail["message"]
def test_embeddings_enabled_backend_returns_pending_code(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class DummySettings:
enable_embeddings_backend = True
monkeypatch.setattr("app.routers.embeddings.get_settings", lambda: DummySettings())
with pytest.raises(HTTPException) as exc:
asyncio.run(embeddings.create_embeddings())
assert exc.value.status_code == 501
assert exc.value.detail["type"] == "not_implemented_error"
assert exc.value.detail["code"] == "embeddings_backend_pending"