"""Videos API tests. List / retrieve / error shapes are free and always run; creation is gated by RUN_VIDEO_TESTS. Videos API + Sora 2 models are scheduled for removal on 2026-09-24 — a 404/410 after that date is expected.""" from __future__ import annotations import time import pytest TERMINAL = {"completed", "failed"} STATES = {"queued", "in_progress"} | TERMINAL def test_list_videos(openai): st, body, _ = openai("GET", "/v1/videos?limit=2", note="test_video list (free)") if st in (404, 410): pytest.skip(f"Videos API answered {st} (scheduled shutdown 2026-09-24)") assert st == 200, body assert body["object"] == "list" and isinstance(body["data"], list) and "has_more" in body for v in body["data"]: assert v["object"] == "video" and v["status"] in STATES and v["id"].startswith("video") def test_retrieve_unknown_video_404(openai): st, body, _ = openai("GET", "/v1/videos/video_atlas_does_not_exist", note="test_video 404 shape (free)") if st == 410: pytest.skip("Videos API gone") assert st == 404, body assert body["error"]["type"] == "invalid_request_error" and "not found" in body["error"]["message"] def test_characters_has_no_list_operation(openai): st, body, _ = openai("GET", "/v1/videos/characters?limit=1", note="test_video characters list probe (free)") if st in (404, 410): pytest.skip("Videos API gone") assert st == 400 and body["error"]["param"] == "video_id" @pytest.mark.run_video_tests def test_create_poll_video(openai): """~$0.40: 4 s sora-2 720p clip. Polls up to 15 min, then downloads the thumbnail.""" st, job, _ = openai("POST", "/v1/videos", {"model": "sora-2", "prompt": "A simple blue geometric cube rotating on a white background.", "size": "720x1280", "seconds": "4"}, est_cost_usd=0.40, note="test_video create (RUN_VIDEO_TESTS)") assert st == 200, job assert job["object"] == "video" and job["status"] in STATES deadline = time.time() + 900 while job["status"] not in TERMINAL and time.time() < deadline: time.sleep(15) st, job, _ = openai("GET", f"/v1/videos/{job['id']}", note="poll") assert st == 200, job assert job["status"] == "completed", job.get("error") st, content, hdrs = openai("GET", f"/v1/videos/{job['id']}/content?variant=thumbnail", note="download thumbnail") assert st == 200 and isinstance(content, bytes) and hdrs.get("Content-Type", "").startswith("image/")