test: update video generation tests for queued jobs and gallery redirects

This commit is contained in:
zwitschi committed 2026-09-03 17:04:02 +02:00
1 parent a4b874598d
commit b5dda5ed97
3 files changed
+201 -88

No files matched your search

+157 -80
View File
@@ -7,6 +7,7 @@ from httpx import AsyncClient, ASGITransport
from app.main import app
from app import db as db_module
from app.services import video_worker
os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only")
os.environ.setdefault("OPENROUTER_API_KEY", "test-key")
@@ -357,20 +358,30 @@ async def test_generate_image_stored_in_db(client):
# ---------------------------------------------------------------------------
async def test_generate_video(client):
"""POST /generate/video queues a text-to-video job for the background worker."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video", new_callable=AsyncMock, return_value=FAKE_VIDEO):
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video",
"prompt": "Ocean waves at sunset"},
headers={"Authorization": f"Bearer {token}"},
)
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video",
"prompt": "Ocean waves at sunset"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
data = resp.json()
assert data["id"] == "gen-vid-1"
assert data["status"] == "queued"
assert data["polling_url"] == "https://openrouter.ai/api/v1/videos/gen-vid-1"
assert data["model"] == "stability/stable-video"
# Provider job_id / polling_url are assigned later by the worker, not at queue time
assert data["id"] == ""
assert data["polling_url"] is None
assert data["video_url"] is None
assert data["db_id"] is not None
row = db_module.get_conn().execute(
"SELECT generation_type, status, model_id, prompt FROM generated_videos WHERE id = ?",
[data["db_id"]],
).fetchone()
assert row == ("text_to_video", "queued", "stability/stable-video",
"Ocean waves at sunset")
async def test_generate_video_unauthenticated(client):
@@ -379,14 +390,26 @@ async def test_generate_video_unauthenticated(client):
async def test_generate_video_upstream_error(client):
"""A queued text job is marked 'failed' when the worker's OpenRouter call raises."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video", new_callable=AsyncMock, side_effect=Exception("503")):
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Hi"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 502
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Hi"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
db_id = resp.json()["db_id"]
with patch("app.services.video_worker.openrouter.generate_video",
new_callable=AsyncMock, side_effect=Exception("503")):
processed = await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
assert processed == 0
row = db_module.get_conn().execute(
"SELECT status, error FROM generated_videos WHERE id = ?", [db_id]).fetchone()
assert row[0] == "failed"
assert "503" in row[1]
# ---------------------------------------------------------------------------
@@ -394,22 +417,27 @@ async def test_generate_video_upstream_error(client):
# ---------------------------------------------------------------------------
async def test_generate_video_from_image(client):
"""POST /generate/video/from-image queues an image-to-video job for the worker."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video_from_image", new_callable=AsyncMock, return_value=FAKE_VIDEO_DONE):
resp = await client.post(
"/generate/video/from-image",
json={
"model": "runway/gen-3",
"image_url": "https://example.com/cat.jpg",
"prompt": "Cat runs across the room",
},
headers={"Authorization": f"Bearer {token}"},
)
resp = await client.post(
"/generate/video/from-image",
json={
"model": "runway/gen-3",
"image_url": "https://example.com/cat.jpg",
"prompt": "Cat runs across the room",
},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "completed"
assert data["video_url"] == "https://example.com/video.mp4"
assert data["video_urls"] == ["https://example.com/video.mp4"]
assert data["status"] == "queued"
assert data["model"] == "runway/gen-3"
assert data["db_id"] is not None
row = db_module.get_conn().execute(
"SELECT generation_type, status, model_id FROM generated_videos WHERE id = ?",
[data["db_id"]]).fetchone()
assert row == ("image_to_video", "queued", "runway/gen-3")
async def test_poll_video_status(client):
@@ -463,61 +491,93 @@ async def test_generate_video_from_image_unauthenticated(client):
# ---------------------------------------------------------------------------
async def test_generate_video_stored_in_db(client):
"""Submitting a video job inserts a row into generated_videos."""
"""Submitting a video job inserts a row; the worker assigns the provider job_id."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video", new_callable=AsyncMock, return_value=FAKE_VIDEO):
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Ocean waves"},
headers={"Authorization": f"Bearer {token}"},
)
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Ocean waves"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
db_id = resp.json()["db_id"]
# Row is queued with no provider job_id until the worker submits it
row = db_module.get_conn().execute(
"SELECT job_id, model_id, prompt, status FROM generated_videos WHERE job_id = ?",
["gen-vid-1"],
"SELECT job_id, model_id, prompt, status, generation_type FROM generated_videos WHERE id = ?",
[db_id],
).fetchone()
assert row is not None
assert row[0] == "gen-vid-1"
assert row[0] == ""
assert row[1] == "stability/stable-video"
assert row[2] == "Ocean waves"
assert row[3] == "queued"
assert row[4] == "text_to_video"
# Worker submits and persists provider job_id / polling_url / status
with patch("app.services.video_worker.openrouter.generate_video",
new_callable=AsyncMock, return_value=FAKE_VIDEO):
await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
row = db_module.get_conn().execute(
"SELECT job_id, polling_url, status FROM generated_videos WHERE id = ?",
[db_id]).fetchone()
assert row[0] == "gen-vid-1"
assert row[1] == "https://openrouter.ai/api/v1/videos/gen-vid-1"
assert row[2] == "queued"
async def test_generate_video_from_image_stored_in_db(client):
"""Submitting a from-image job inserts a row into generated_videos."""
"""Submitting a from-image job inserts a row; worker assigns provider job_id."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video_from_image", new_callable=AsyncMock, return_value=FAKE_VIDEO_DONE):
resp = await client.post(
"/generate/video/from-image",
json={
"model": "runway/gen-3",
"image_url": "https://example.com/cat.jpg",
"prompt": "Cat runs",
},
headers={"Authorization": f"Bearer {token}"},
)
resp = await client.post(
"/generate/video/from-image",
json={
"model": "runway/gen-3",
"image_url": "https://example.com/cat.jpg",
"prompt": "Cat runs",
},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
db_id = resp.json()["db_id"]
row = db_module.get_conn().execute(
"SELECT job_id, model_id, prompt, status FROM generated_videos WHERE job_id = ?",
["gen-vid-2"],
).fetchone()
assert row is not None
assert row[1] == "runway/gen-3"
assert row[2] == "Cat runs"
"SELECT generation_type, status, model_id, prompt FROM generated_videos WHERE id = ?",
[db_id]).fetchone()
assert row == ("image_to_video", "queued", "runway/gen-3", "Cat runs")
# FAKE_VIDEO_DONE is immediately completed with URLs
with patch("app.services.video_worker.openrouter.generate_video_from_image",
new_callable=AsyncMock, return_value=FAKE_VIDEO_DONE):
await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
row = db_module.get_conn().execute(
"SELECT job_id, status, video_url FROM generated_videos WHERE id = ?",
[db_id]).fetchone()
assert row[0] == "gen-vid-2"
assert row[1] == "completed"
assert row[2] == "https://example.com/video.mp4"
async def test_poll_video_updates_db_on_completion(client):
"""Polling a completed job updates the row status and video_url."""
"""Polling a completed job updates the matching row's status and video_url."""
token = await _user_token(client)
# First submit a job
with patch("app.routers.generate.openrouter.generate_video", new_callable=AsyncMock, return_value=FAKE_VIDEO):
await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Test"},
headers={"Authorization": f"Bearer {token}"},
)
# First submit a job and let the worker assign provider job_id + polling_url
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Test"},
headers={"Authorization": f"Bearer {token}"},
)
db_id = resp.json()["db_id"]
with patch("app.services.video_worker.openrouter.generate_video",
new_callable=AsyncMock,
return_value={"id": "gen-vid-1",
"polling_url": "https://openrouter.ai/api/v1/videos/gen-vid-1",
"status": "processing"}):
await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
# Now poll and get completed status
mock_result = {
@@ -533,8 +593,8 @@ async def test_poll_video_updates_db_on_completion(client):
)
row = db_module.get_conn().execute(
"SELECT status, video_url FROM generated_videos WHERE job_id = ?",
["gen-vid-1"],
"SELECT status, video_url FROM generated_videos WHERE id = ?",
[db_id],
).fetchone()
assert row is not None
assert row[0] == "completed"
@@ -555,12 +615,16 @@ async def test_list_generated_videos_empty(client):
async def test_list_generated_videos_returns_own_jobs(client):
"""GET /generate/videos returns the current user's jobs only."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video", new_callable=AsyncMock, return_value=FAKE_VIDEO):
await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Waves"},
headers={"Authorization": f"Bearer {token}"},
)
resp = await client.post(
"/generate/video",
json={"model": "stability/stable-video", "prompt": "Waves"},
headers={"Authorization": f"Bearer {token}"},
)
db_id = resp.json()["db_id"]
with patch("app.services.video_worker.openrouter.generate_video",
new_callable=AsyncMock, return_value=FAKE_VIDEO):
await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
resp = await client.get(
"/generate/videos",
@@ -569,7 +633,9 @@ async def test_list_generated_videos_returns_own_jobs(client):
assert resp.status_code == 200
data = resp.json()
assert len(data) == 1
assert data[0]["id"] == db_id
assert data[0]["job_id"] == "gen-vid-1"
assert data[0]["model_id"] == "stability/stable-video"
assert data[0]["prompt"] == "Waves"
assert data[0]["status"] == "queued"
@@ -580,12 +646,23 @@ async def test_list_generated_videos_unauthenticated(client):
async def test_generate_video_from_image_upstream_error(client):
"""A queued image-to-video job is marked 'failed' on worker OpenRouter error."""
token = await _user_token(client)
with patch("app.routers.generate.openrouter.generate_video_from_image", new_callable=AsyncMock, side_effect=Exception("error")):
resp = await client.post(
"/generate/video/from-image",
json={"model": "runway/gen-3",
"image_url": "https://example.com/img.jpg", "prompt": "p"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 502
resp = await client.post(
"/generate/video/from-image",
json={"model": "runway/gen-3",
"image_url": "https://example.com/img.jpg", "prompt": "p"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 200
db_id = resp.json()["db_id"]
with patch("app.services.video_worker.openrouter.generate_video_from_image",
new_callable=AsyncMock, side_effect=Exception("error")):
processed = await video_worker.process_queued_jobs(
db_module.get_conn(), db_module.get_write_lock())
assert processed == 0
row = db_module.get_conn().execute(
"SELECT status FROM generated_videos WHERE id = ?", [db_id]).fetchone()
assert row[0] == "failed"