From 472fe1cab8a4aeac9924e78839bc7124909854b8 Mon Sep 17 00:00:00 2001 From: zwitschi Date: Wed, 29 Apr 2026 15:25:41 +0200 Subject: [PATCH] test: add video job storage and retrieval tests in generate endpoints Co-authored-by: Copilot --- backend/tests/test_generate.py | 121 ++++++++++++++++++++++++++++++++ frontend/tests/test_frontend.py | 12 ++-- 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/backend/tests/test_generate.py b/backend/tests/test_generate.py index 366f089..275d078 100644 --- a/backend/tests/test_generate.py +++ b/backend/tests/test_generate.py @@ -458,6 +458,127 @@ async def test_generate_video_from_image_unauthenticated(client): assert resp.status_code == 401 +# --------------------------------------------------------------------------- +# Video job DB storage +# --------------------------------------------------------------------------- + +async def test_generate_video_stored_in_db(client): + """Submitting a video job inserts a row into generated_videos.""" + 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}"}, + ) + assert resp.status_code == 200 + + row = db_module.get_conn().execute( + "SELECT job_id, model_id, prompt, status FROM generated_videos WHERE job_id = ?", + ["gen-vid-1"], + ).fetchone() + assert row is not None + assert row[0] == "gen-vid-1" + assert row[1] == "stability/stable-video" + assert row[2] == "Ocean waves" + assert row[3] == "queued" + + +async def test_generate_video_from_image_stored_in_db(client): + """Submitting a from-image job inserts a row into generated_videos.""" + 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}"}, + ) + assert resp.status_code == 200 + + 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" + + +async def test_poll_video_updates_db_on_completion(client): + """Polling a completed job updates the row 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}"}, + ) + + # Now poll and get completed status + mock_result = { + "id": "gen-vid-1", + "status": "completed", + "unsigned_urls": ["https://example.com/video.mp4"], + } + with patch("app.routers.generate.openrouter.poll_video_status", new_callable=AsyncMock, return_value=mock_result): + await client.get( + "/generate/video/status", + params={"polling_url": "https://openrouter.ai/api/v1/videos/gen-vid-1"}, + headers={"Authorization": f"Bearer {token}"}, + ) + + row = db_module.get_conn().execute( + "SELECT status, video_url FROM generated_videos WHERE job_id = ?", + ["gen-vid-1"], + ).fetchone() + assert row is not None + assert row[0] == "completed" + assert row[1] == "https://example.com/video.mp4" + + +async def test_list_generated_videos_empty(client): + """GET /generate/videos returns empty list initially.""" + token = await _user_token(client) + resp = await client.get( + "/generate/videos", + headers={"Authorization": f"Bearer {token}"}, + ) + assert resp.status_code == 200 + assert resp.json() == [] + + +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.get( + "/generate/videos", + headers={"Authorization": f"Bearer {token}"}, + ) + assert resp.status_code == 200 + data = resp.json() + assert len(data) == 1 + assert data[0]["job_id"] == "gen-vid-1" + assert data[0]["prompt"] == "Waves" + assert data[0]["status"] == "queued" + + +async def test_list_generated_videos_unauthenticated(client): + resp = await client.get("/generate/videos") + assert resp.status_code == 401 + + async def test_generate_video_from_image_upstream_error(client): token = await _user_token(client) with patch("app.routers.generate.openrouter.generate_video_from_image", new_callable=AsyncMock, side_effect=Exception("error")): diff --git a/frontend/tests/test_frontend.py b/frontend/tests/test_frontend.py index 02edb31..4a44140 100644 --- a/frontend/tests/test_frontend.py +++ b/frontend/tests/test_frontend.py @@ -152,7 +152,8 @@ def test_dashboard_renders_user_info(client): 200, {"id": "1", "email": "u@example.com", "role": "user"}) images_mock = _mock_response(200, []) gen_images_mock = _mock_response(200, []) - with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock]): + gen_videos_mock = _mock_response(200, []) + with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock, gen_videos_mock]): resp = client.get("/dashboard") assert resp.status_code == 200 assert b"u@example.com" in resp.data @@ -533,7 +534,8 @@ def test_dashboard_shows_uploaded_images(client): "size_bytes": 1024, "created_at": "2026-04-29T10:00:00"}, ]) gen_images_mock = _mock_response(200, []) - with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock]): + gen_videos_mock = _mock_response(200, []) + with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock, gen_videos_mock]): resp = client.get("/dashboard") assert resp.status_code == 200 assert b"cat.png" in resp.data @@ -554,7 +556,8 @@ def test_dashboard_shows_generated_images(client): "created_at": "2026-04-29T10:00:00", } ]) - with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock]): + gen_videos_mock = _mock_response(200, []) + with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock, gen_videos_mock]): resp = client.get("/dashboard") assert resp.status_code == 200 assert b"Generated images" in resp.data @@ -568,7 +571,8 @@ def test_dashboard_no_images_section_when_empty(client): 200, {"id": "1", "email": "u@example.com", "role": "user"}) images_mock = _mock_response(200, []) gen_images_mock = _mock_response(200, []) - with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock]): + gen_videos_mock = _mock_response(200, []) + with patch("frontend.app.main.httpx.request", side_effect=[me_mock, images_mock, gen_images_mock, gen_videos_mock]): resp = client.get("/dashboard") assert resp.status_code == 200 assert b"Uploaded reference images" not in resp.data