- pyproject.toml: add [tool.ruff] config suppressing E402/W293 globally, F841/E741/E702 in tests, E741 in scripts - inventory.py: split semicolon import (E702) - recipes.py: fix logger -> log (F821 undefined name) - shopping.py: rename l -> lnk in list comprehension (E741) - format_conversion.py: noqa F841 on CUDA flag (used as future hook) - backfill_keywords.py: rename done -> _done (F841) - ingest_purplecarrot.py: drop == True comparison (E712) - Auto-fix: I001 import sorting, F401 unused imports across all files
84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
# tests/api/test_community_endpoints.py
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.main import app
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
def test_get_community_posts_no_db_returns_empty():
|
|
"""When COMMUNITY_DB_URL is not set, GET /community/posts returns empty list (no 500)."""
|
|
with patch("app.api.endpoints.community._community_store", None):
|
|
response = client.get("/api/v1/community/posts")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "posts" in data
|
|
assert isinstance(data["posts"], list)
|
|
|
|
|
|
def test_get_community_post_not_found():
|
|
"""GET /community/posts/{slug} returns 404 when slug doesn't exist."""
|
|
mock_store = MagicMock()
|
|
mock_store.get_post_by_slug.return_value = None
|
|
with patch("app.api.endpoints.community._community_store", mock_store):
|
|
response = client.get("/api/v1/community/posts/nonexistent-slug")
|
|
assert response.status_code == 404
|
|
|
|
|
|
def test_get_community_rss():
|
|
"""GET /community/feed.rss returns XML with content-type application/rss+xml."""
|
|
mock_store = MagicMock()
|
|
mock_store.list_posts.return_value = []
|
|
with patch("app.api.endpoints.community._community_store", mock_store):
|
|
response = client.get("/api/v1/community/feed.rss")
|
|
assert response.status_code == 200
|
|
assert "xml" in response.headers.get("content-type", "")
|
|
|
|
|
|
def test_post_community_requires_auth():
|
|
"""POST /community/posts requires authentication (401/403/422) or community store (503).
|
|
|
|
In local/dev mode get_session bypasses JWT auth and returns a privileged user,
|
|
so the next gate is the community store check (503 when COMMUNITY_DB_URL is not set).
|
|
In cloud mode the endpoint requires a valid session (401/403).
|
|
"""
|
|
response = client.post("/api/v1/community/posts", json={"title": "Test"})
|
|
assert response.status_code in (401, 403, 422, 503)
|
|
|
|
|
|
def test_delete_post_requires_auth():
|
|
"""DELETE /community/posts/{slug} requires authentication (401/403) or community store (503).
|
|
|
|
Same local-mode caveat as test_post_community_requires_auth.
|
|
"""
|
|
response = client.delete("/api/v1/community/posts/some-slug")
|
|
assert response.status_code in (401, 403, 422, 503)
|
|
|
|
|
|
def test_fork_post_route_exists():
|
|
"""POST /community/posts/{slug}/fork route exists (not 404)."""
|
|
response = client.post("/api/v1/community/posts/some-slug/fork")
|
|
assert response.status_code != 404
|
|
|
|
|
|
def test_local_feed_returns_json():
|
|
"""GET /community/local-feed returns JSON list for LAN peers."""
|
|
mock_store = MagicMock()
|
|
mock_store.list_posts.return_value = []
|
|
with patch("app.api.endpoints.community._community_store", mock_store):
|
|
response = client.get("/api/v1/community/local-feed")
|
|
assert response.status_code == 200
|
|
assert isinstance(response.json(), list)
|
|
|
|
|
|
def test_hall_of_chaos_route_exists():
|
|
"""GET /community/hall-of-chaos returns 200 and includes chaos_level key."""
|
|
mock_store = MagicMock()
|
|
mock_store.list_posts.return_value = []
|
|
with patch("app.api.endpoints.community._community_store", mock_store):
|
|
response = client.get("/api/v1/community/hall-of-chaos")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "chaos_level" in data
|