"""Tests for Crown Commend endpoints.""" from __future__ import annotations from fastapi.testclient import TestClient def test_commend_health(client: TestClient) -> None: """Commend health endpoint should return status information.""" response = client.get("/api/commend/health") assert response.status_code == 200 data = response.json() assert "status" in data assert "geminiConfigured" in data assert "youtubeConfigured" in data def test_commend_styles(client: TestClient) -> None: """Styles endpoint should return available comment styles.""" response = client.get("/api/commend/styles") assert response.status_code == 200 data = response.json() assert "styles" in data assert len(data["styles"]) > 0 def test_commend_generate_rejects_invalid_url(client: TestClient) -> None: """Generate endpoint should reject a non-YouTube URL.""" response = client.post( "/api/commend/generate", json={ "videoUrl": "https://example.com", "language": "English", "commentStyle": "supportive", }, ) # 400 (invalid url), 401 (auth), 422 (validation), 503 (auth not configured) assert response.status_code in (400, 401, 422, 429, 503) def test_commend_generate_rejects_empty_url(client: TestClient) -> None: """Generate endpoint should reject empty URL.""" response = client.post( "/api/commend/generate", json={ "videoUrl": "", "language": "English", "commentStyle": "supportive", }, ) # 422 (Pydantic min_length), 401 (auth), 503 (auth not configured) assert response.status_code in (401, 422, 429, 503) def test_commend_post_disabled_by_default(client: TestClient) -> None: """Post endpoint should be disabled by default (feature flag).""" response = client.post( "/api/commend/post", json={ "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "commentText": "Test comment", }, ) # 401 (auth), 403 (feature flag disabled), 503 (auth not configured) assert response.status_code in (401, 403, 429, 503) def test_commend_post_error_envelope_format(client: TestClient) -> None: """Error responses should use {code, message} envelope format.""" response = client.post( "/api/commend/post", json={ "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "commentText": "Test comment", }, ) if response.status_code in (401, 403, 503): data = response.json() detail = data.get("detail", {}) if isinstance(detail, dict): assert "code" in detail assert "message" in detail def test_commend_auth_fail_closed_without_key(client: TestClient) -> None: """Without COMMEND_API_KEY set, protected endpoints should reject (fail-closed).""" response = client.post( "/api/commend/generate", json={ "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "language": "English", "commentStyle": "supportive", }, ) # With COMMEND_REQUIRE_AUTH=true (default) and no key, expect 429 or 503 assert response.status_code in (429, 503) def test_commend_rate_limit_independent_of_auth(client: TestClient) -> None: """Rate limiting should apply regardless of auth configuration.""" # Send multiple rapid requests — rate limit should apply even without auth key statuses = [] for _ in range(15): response = client.post( "/api/commend/generate", json={ "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "language": "English", "commentStyle": "supportive", }, ) statuses.append(response.status_code) # Should see at least one 429 in the batch (rate limit is 10/min) assert 429 in statuses, f"Expected 429 in statuses but got: {set(statuses)}"