HR-ATS-Portal/tests/unit/test_config.py

86 lines
3.5 KiB
Python

from __future__ import annotations
import pytest
from pydantic import ValidationError
from app.core.config import Settings, supports_reasoning
from tests.conftest import build_settings
class TestModelFamilyCheck:
@pytest.mark.parametrize(
"model",
["gpt-5.4-mini", "gpt-5.5", "gpt-5", "gpt-5.6-terra", "gpt-4.1", "o3", "o4-mini"],
)
def test_accepts_known_structured_output_families(self, model: str) -> None:
assert build_settings(openai_model=model).openai_model == model
def test_accepts_a_future_point_release(self) -> None:
"""Prefix matching exists so a new gpt-5.x is not rejected on arrival."""
assert build_settings(openai_model="gpt-5.9-turbo").openai_model == "gpt-5.9-turbo"
def test_rejects_chat_latest_variants(self) -> None:
with pytest.raises(ValidationError, match="chat-product variant"):
build_settings(openai_model="gpt-5.4-chat-latest")
def test_rejects_gpt_4o(self) -> None:
"""Pre-2024-08-06 snapshots lack structured outputs and aliases hide which is which."""
with pytest.raises(ValidationError):
build_settings(openai_model="gpt-4o")
def test_rejects_an_unknown_family(self) -> None:
with pytest.raises(ValidationError):
build_settings(openai_model="llama-3-70b")
def test_rejects_empty(self) -> None:
with pytest.raises(ValidationError):
build_settings(openai_model=" ")
class TestReasoningDetection:
@pytest.mark.parametrize("model", ["gpt-5.4-mini", "gpt-5", "o3", "o4-mini"])
def test_reasoning_families(self, model: str) -> None:
assert supports_reasoning(model)
def test_gpt_41_is_not_a_reasoning_model(self) -> None:
"""Allowed as a model, but sending it a reasoning parameter is a 400."""
assert not supports_reasoning("gpt-4.1")
class TestEffort:
@pytest.mark.parametrize("effort", ["none", "minimal", "low", "medium", "high", "xhigh"])
def test_accepts_valid_levels(self, effort: str) -> None:
assert build_settings(openai_effort=effort).openai_effort == effort
def test_normalises_case(self) -> None:
assert build_settings(openai_effort="LOW").openai_effort == "low"
def test_rejects_unknown_level(self) -> None:
with pytest.raises(ValidationError):
build_settings(openai_effort="extreme")
class TestDefaults:
def test_defaults_match_the_documented_baseline(self) -> None:
settings = Settings(_env_file=None)
assert settings.openai_model == "gpt-5.4-mini"
assert settings.openai_max_output_tokens == 4000
assert settings.openai_effort == "low"
assert settings.openai_enable_prompt_cache is True
def test_has_no_sampling_parameters(self) -> None:
"""Their presence would be a 400 waiting to happen on a reasoning model."""
fields = set(Settings.model_fields)
assert not {"openai_temperature", "openai_top_p"} & fields
def test_max_output_tokens_floor_rejects_a_truncating_budget(self) -> None:
"""Reasoning tokens share this budget, so a small cap truncates the JSON."""
with pytest.raises(ValidationError):
build_settings(openai_max_output_tokens=1200)
def test_max_output_tokens_floor_is_the_lowest_safe_budget(self) -> None:
assert build_settings(openai_max_output_tokens=2048).openai_max_output_tokens == 2048
def test_size_limit_converts_to_bytes(self) -> None:
assert build_settings(max_pdf_size_mb=10).max_pdf_size_bytes == 10 * 1024 * 1024