"""Files API: resumable upload protocol, get/list/delete, fileData usage, 403 semantics. Verified 2026-09-18 (free).""" from __future__ import annotations from tests.gemini._core_helpers import call, gc def test_resumable_upload_lifecycle(gemini, models): data = b"The secret word in this Atlas test file is PELICAN.\n" st, body, hdrs = call(gemini, "POST", "/upload/v1beta/files", {"file": {"displayName": "atlas-test.txt"}}, extra_headers={"X-Goog-Upload-Protocol": "resumable", "X-Goog-Upload-Command": "start", "X-Goog-Upload-Header-Content-Length": str(len(data)), "X-Goog-Upload-Header-Content-Type": "text/plain"}, note="test_files start") assert st == 200, body lower = {k.lower(): v for k, v in hdrs.items()} assert lower.get("x-goog-upload-status") == "active" and lower.get("x-goog-upload-url") and lower.get("x-goog-upload-chunk-granularity") path = lower["x-goog-upload-url"].split("generativelanguage.googleapis.com", 1)[1] st, fb, fh = call(gemini, "POST", path, None, data=data, content_type="text/plain", extra_headers={"X-Goog-Upload-Offset": "0", "X-Goog-Upload-Command": "upload, finalize", "Content-Length": str(len(data))}, note="test_files finalize") assert st == 200, fb f = fb["file"] assert f["name"].startswith("files/") and f["state"] == "ACTIVE" and f["source"] == "UPLOADED" and f["mimeType"] == "text/plain" assert f["sizeBytes"] == str(len(data)) and f["expirationTime"] and f["sha256Hash"] and f["uri"].endswith(f["name"]) assert {k.lower(): v for k, v in fh.items()}.get("x-goog-upload-status") == "final" try: st, g, _ = call(gemini, "GET", f"/v1beta/{f['name']}", None, note="test_files get") assert st == 200 and g["name"] == f["name"] st, lst, _ = call(gemini, "GET", "/v1beta/files?pageSize=50", None, note="test_files list") assert st == 200 and any(x["name"] == f["name"] for x in lst.get("files", [])) st, r, _ = call(gemini, "POST", gc(models["gemini"]), {"contents": [{"role": "user", "parts": [{"text": "What is the secret word? One word."}, {"fileData": {"fileUri": f["uri"], "mimeType": "text/plain"}}]}], "generationConfig": {"maxOutputTokens": 8}}, note="test_files use") assert st == 200 and "PELICAN" in r["candidates"][0]["content"]["parts"][0]["text"].upper() finally: st, _, _ = call(gemini, "DELETE", f"/v1beta/{f['name']}", None, note="test_files delete") assert st == 200 st, r, _ = call(gemini, "GET", f"/v1beta/{f['name']}", None, note="test_files get after delete") assert st == 403 and r["error"]["status"] == "PERMISSION_DENIED" and "may not exist" in r["error"]["message"] def test_unknown_file_is_403_not_404(gemini): st, r, _ = call(gemini, "GET", "/v1beta/files/does-not-exist-atlas", None, note="test_files unknown") assert st == 403 and r["error"]["status"] == "PERMISSION_DENIED" def test_generated_files_list(gemini): st, r, _ = call(gemini, "GET", "/v1beta/generatedFiles?pageSize=3", None, note="test_files generatedFiles") assert st == 200 and isinstance(r, dict)