Python 88.3%
TypeScript 7.6%
Shell 4.1%
1"""Smoke test for Gemini File Search stores (API Atlas) — cheap (indexing ≈ 50 tokens ≈ $0.00001), always runs, cleans up.23Lifecycle: create store → resumable uploadToFileSearchStore → poll operation → list/get documents → generateContent with the fileSearch4tool → delete document (force) → delete store (force). Also asserts the documented 400 FAILED_PRECONDITION when deleting a5non-empty document without ?force=true. Reference run: 2026-09-18 (tmp-live/gemini-tools/g*.json).6"""7from __future__ import annotations89import time1011from scripts.live import GEMINI_BASE1213MODEL = "gemini-3.5-flash-lite"14TEXT = b"The Atlas test document. The secret fruit is kumquat. The secret number is 4711."151617def test_file_search_lifecycle(gemini):18 st, store, _ = gemini("POST", "/v1beta/fileSearchStores", {"displayName": "atlas-pytest"}, note="test_file_search create store")19 assert st == 200 and store["name"].startswith("fileSearchStores/") and store["embeddingModel"]20 name = store["name"]21 try:22 st, _, h = gemini("POST", f"/upload/v1beta/{name}:uploadToFileSearchStore", {"displayName": "probe.txt", "customMetadata": [{"key": "kind", "stringValue": "probe"}]},23 extra_headers={"X-Goog-Upload-Protocol": "resumable", "X-Goog-Upload-Command": "start",24 "X-Goog-Upload-Header-Content-Length": str(len(TEXT)), "X-Goog-Upload-Header-Content-Type": "text/plain"},25 note="test_file_search upload start")26 assert st == 20027 upload_url = next(v for k, v in h.items() if k.lower() == "x-goog-upload-url")28 st, op, _ = gemini("POST", upload_url.replace(GEMINI_BASE, ""), data=TEXT, content_type="text/plain",29 extra_headers={"X-Goog-Upload-Offset": "0", "X-Goog-Upload-Command": "upload, finalize"}, note="test_file_search upload finalize")30 assert st == 200 and "/upload/operations/" in op["name"]31 for _ in range(20):32 if op.get("done"):33 break34 time.sleep(2)35 st, op, _ = gemini("GET", f"/v1beta/{op['name']}", note="test_file_search poll")36 assert op.get("done") is True and op["response"]["documentName"].startswith(name + "/documents/")37 doc = op["response"]["documentName"]38 st, docs, _ = gemini("GET", f"/v1beta/{name}/documents", note="test_file_search list documents")39 assert st == 200 and docs["documents"][0]["state"] == "STATE_ACTIVE" and docs["documents"][0]["customMetadata"][0]["key"] == "kind"40 st, r, _ = gemini("POST", f"/v1beta/models/{MODEL}:generateContent",41 {"contents": [{"parts": [{"text": "What is the secret fruit? 3 words."}]}],42 "tools": [{"fileSearch": {"fileSearchStoreNames": [name], "metadataFilter": "kind=probe"}}], "generationConfig": {"maxOutputTokens": 32}},43 note="test_file_search query")44 assert st == 20045 text = "".join(p.get("text", "") for p in r["candidates"][0]["content"]["parts"]).lower()46 assert "kumquat" in text and r["usageMetadata"].get("toolUsePromptTokenCount", 0) > 047 gm = r["candidates"][0].get("groundingMetadata") # present in most runs; absent once on 2026-09-18 (recorded)48 if gm:49 assert gm["groundingChunks"][0]["retrievedContext"]["fileSearchStore"] == name50 st, err, _ = gemini("DELETE", f"/v1beta/{doc}", note="test_file_search delete document no force")51 assert st == 400 and err["error"]["status"] == "FAILED_PRECONDITION"52 st, _, _ = gemini("DELETE", f"/v1beta/{doc}?force=true", note="test_file_search delete document force")53 assert st == 20054 finally:55 st, _, _ = gemini("DELETE", f"/v1beta/{name}?force=true", note="test_file_search delete store")56 assert st == 20057