from __future__ import annotations from fastapi.testclient import TestClient from backend.app.api.routes import strategy from backend.app.core.config import settings from backend.app.core.rate_limiter import clear_rate_limit_state from backend.app.main import app from backend.app.services.campaign_vectorizer import FEATURE_KEYS def _stub_vectorized(text: str) -> dict: return { "normalized_features": {key: 0.5 for key in FEATURE_KEYS}, "embedding": [0.0] * 12, "embedding_model": "test", "model": "test-vectorizer", } def test_strategy_vectorize_rate_limit_returns_429(monkeypatch) -> None: clear_rate_limit_state() monkeypatch.setattr(settings, "rate_limit_enabled", True) monkeypatch.setattr(settings, "rate_limit_strategy_vectorize_per_minute", 1) monkeypatch.setattr(strategy, "extract_campaign_features", _stub_vectorized) client = TestClient(app) first = client.post("/api/strategy/vectorize", json={"text": "oncology evidence brief"}) second = client.post("/api/strategy/vectorize", json={"text": "oncology evidence brief"}) assert first.status_code == 200 assert second.status_code == 429 assert second.json()["error"] == "rate_limited" assert second.json()["retry_after_seconds"] > 0 clear_rate_limit_state() def test_healthz_is_not_rate_limited(monkeypatch) -> None: clear_rate_limit_state() monkeypatch.setattr(settings, "rate_limit_enabled", True) monkeypatch.setattr(settings, "rate_limit_strategy_vectorize_per_minute", 1) client = TestClient(app) for _ in range(5): response = client.get("/healthz") assert response.status_code == 200 clear_rate_limit_state()