Download test/test_upload_form_limits.py from ethonmax/picpocket: direct link, hf CLI and curl.
- Browser
- Download file 5.29 kB
-
https://huggingface.co/spaces/ethonmax/picpocket/resolve/main/test/test_upload_form_limits.py
- Command line
-
hf download hf://spaces/ethonmax/picpocket/test/test_upload_form_limits.py
-
curl -L -o test_upload_form_limits.py https://huggingface.co/spaces/ethonmax/picpocket/resolve/main/test/test_upload_form_limits.py
5.29 kB
| """使用内存 TestClient 验证表单解析,不启动服务器、不导入模型/数据库。""" | |
| import json | |
| import unittest | |
| from unittest.mock import patch | |
| from fastapi import APIRouter, FastAPI, File, Form, HTTPException, Query, UploadFile | |
| from fastapi.testclient import TestClient | |
| from upload_routes import FaceAnalysisFormRoute | |
| class UploadFormLimitsTest(unittest.TestCase): | |
| def setUp(self) -> None: | |
| self.received_files = [] | |
| app = FastAPI() | |
| router = APIRouter(prefix="/facescore", route_class=FaceAnalysisFormRoute) | |
| async def analyze( | |
| images: str = Form(None), nickname: str = Form(None), | |
| file: UploadFile = File(None), files: list[UploadFile] = File(None), | |
| model: str = Query("hybrid"), fail: bool = Query(False), | |
| ) -> dict: | |
| uploads = ([file] if file is not None else []) + (files or []) | |
| self.received_files.extend(uploads) | |
| if fail: | |
| raise HTTPException(status_code=400, detail="business error") | |
| return { | |
| "images": images, "nickname": nickname, "model": model, | |
| "uploads": [{"name": item.filename, "size": len(await item.read())} for item in uploads], | |
| } | |
| async def other(images: str = Form(...)) -> dict: | |
| return {"size": len(images)} | |
| app.include_router(router) | |
| self.client = TestClient(app) | |
| self.large_images = json.dumps(["A" * (2 * 1024 * 1024)]) | |
| def test_two_analysis_routes_accept_large_multipart_base64(self) -> None: | |
| for path in ("/facescore/analyze", "/facescore/app/analyze"): | |
| with self.subTest(path=path): | |
| response = self.client.post(path, params={"model": "deepface"}, files={ | |
| "images": (None, self.large_images), "nickname": (None, "测试昵称"), | |
| }) | |
| self.assertEqual(200, response.status_code, response.text) | |
| self.assertEqual(self.large_images, response.json()["images"]) | |
| self.assertEqual("测试昵称", response.json()["nickname"]) | |
| self.assertEqual("deepface", response.json()["model"]) | |
| def test_urlencoded_base64_is_preserved(self) -> None: | |
| response = self.client.post("/facescore/analyze", data={"images": self.large_images}) | |
| self.assertEqual(200, response.status_code, response.text) | |
| self.assertEqual(self.large_images, response.json()["images"]) | |
| def test_other_routes_retain_default_limit(self) -> None: | |
| response = self.client.post("/facescore/other", files={"images": (None, self.large_images)}) | |
| self.assertEqual(400, response.status_code) | |
| self.assertIn("maximum size", response.json()["detail"]) | |
| def test_configured_limit_rejects_larger_fields_with_413(self) -> None: | |
| with patch("upload_routes.FACE_SCORE_MAX_FORM_FIELD_MB", 1): | |
| for multipart in (True, False): | |
| with self.subTest(multipart=multipart): | |
| kwargs = {"files": {"images": (None, self.large_images)}} if multipart else { | |
| "data": {"images": self.large_images}} | |
| response = self.client.post("/facescore/analyze", **kwargs) | |
| self.assertEqual(413, response.status_code, response.text) | |
| self.assertIn("1MB", response.json()["detail"]) | |
| def test_field_at_limit_is_accepted(self) -> None: | |
| with patch("upload_routes.FACE_SCORE_MAX_FORM_FIELD_MB", 1): | |
| response = self.client.post("/facescore/analyze", files={"images": (None, "A" * (1024 * 1024))}) | |
| self.assertEqual(200, response.status_code, response.text) | |
| def test_file_uploads_still_work_and_are_closed(self) -> None: | |
| for field, count in (("file", 1), ("files", 2)): | |
| with self.subTest(field=field), patch("upload_routes.FACE_SCORE_MAX_FORM_FIELD_MB", 1): | |
| response = self.client.post("/facescore/analyze", files=[ | |
| (field, (f"photo{i}.jpg", b"x" * (2 * 1024 * 1024), "image/jpeg")) for i in range(count) | |
| ]) | |
| self.assertEqual(200, response.status_code, response.text) | |
| self.assertEqual(count, len(response.json()["uploads"])) | |
| self.assertTrue(all(item["size"] == 2 * 1024 * 1024 for item in response.json()["uploads"])) | |
| self.assertTrue(all(item.file.closed for item in self.received_files)) | |
| def test_business_error_is_preserved_and_upload_closed(self) -> None: | |
| response = self.client.post("/facescore/analyze?fail=true", files={"file": ("photo.jpg", b"image")}) | |
| self.assertEqual(400, response.status_code) | |
| self.assertEqual("business error", response.json()["detail"]) | |
| self.assertTrue(self.received_files[0].file.closed) | |
| def test_invalid_multipart_is_still_rejected(self) -> None: | |
| response = self.client.post("/facescore/analyze", content=b"invalid", headers={"content-type": "multipart/form-data"}) | |
| self.assertEqual(400, response.status_code) | |
| self.assertIn("boundary", response.json()["detail"]) | |
| if __name__ == "__main__": | |
| unittest.main() | |