import pytest from fastapi.testclient import TestClient from main import app, get_db import aiosqlite from unittest.mock import patch @pytest.fixture def client(test_db): # Override get_db dependency to use the isolated test database async def override_get_db(): yield test_db app.dependency_overrides[get_db] = override_get_db yield TestClient(app) app.dependency_overrides.clear() def test_health(client): response = client.get("/api/health") assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.asyncio async def test_get_videos(client, test_db): # Insert mock videos with different statuses await test_db.execute(""" INSERT INTO videos (video_id, title, url, status) VALUES ('v1', 'Pending Video', 'https://youtube.com/v1', 'pending'), ('v2', 'Read Video', 'https://youtube.com/v2', 'read'), ('v3', 'Skipped Video', 'https://youtube.com/v3', 'skipped') """) await test_db.commit() # Test pending filter resp = client.get("/api/videos?status=pending") assert resp.status_code == 200 data = resp.json() assert len(data) == 1 assert data[0]["video_id"] == "v1" # Test read filter resp = client.get("/api/videos?status=read") assert resp.status_code == 200 data = resp.json() assert len(data) == 1 assert data[0]["video_id"] == "v2" def test_update_status_success(client, test_db): # Insert pending video test_db.execute_insert = lambda *args: None # Helper since we execute raw async def insert(): await test_db.execute(""" INSERT INTO videos (video_id, title, url, status) VALUES ('status_vid', 'Title', 'https://youtube.com/watch?v=status_vid', 'pending') """) await test_db.commit() import asyncio asyncio.run(insert()) # Send status update resp = client.post("/api/videos/status_vid/status", json={"status": "read"}) assert resp.status_code == 200 assert resp.json() == {"message": "Video status_vid status updated to read."} # Verify db was updated async def verify(): cursor = await test_db.execute("SELECT status FROM videos WHERE video_id = 'status_vid'") row = await cursor.fetchone() return row["status"] status = asyncio.run(verify()) assert status == "read" def test_update_status_invalid_value(client): resp = client.post("/api/videos/status_vid/status", json={"status": "archived"}) assert resp.status_code == 400 assert "Invalid status value" in resp.json()["detail"] def test_update_status_not_found(client): resp = client.post("/api/videos/missing_vid/status", json={"status": "read"}) assert resp.status_code == 404 assert "Video not found" in resp.json()["detail"] def test_trigger_fetch(client): with patch("main.bg_fetch_and_summarize") as mock_task: resp = client.post("/api/videos/fetch") assert resp.status_code == 200 assert "sync and summarization running in background" in resp.json()["message"] @pytest.mark.asyncio async def test_trigger_summarize(client, test_db): # Insert video await test_db.execute(""" INSERT INTO videos (video_id, title, url, status) VALUES ('sum_vid', 'Title', 'https://youtube.com/watch?v=sum_vid', 'pending') """) await test_db.commit() with patch("main.summarize_video") as mock_sum: resp = client.post("/api/videos/sum_vid/summarize") assert resp.status_code == 200 assert "summarization for video sum_vid queued" in resp.json()["message"].lower() def test_trigger_summarize_not_found(client): resp = client.post("/api/videos/missing_sum/summarize") assert resp.status_code == 404 assert "Video not found" in resp.json()["detail"]