tts-voice-creator-clone-and.../tests/test_security.py

54 lines
1.8 KiB
Python

"""Fast, dependency-light regression tests for P0 request protections."""
from __future__ import annotations
import asyncio
import os
import tempfile
import unittest
os.environ.setdefault("CONFIG_DIR", tempfile.mkdtemp(prefix="ttvc-test-config-"))
from fastapi import HTTPException
from core.validation import _validate_character_record, _validate_http_url
from server import RequestSizeLimitMiddleware
class SecurityValidationTests(unittest.TestCase):
def test_character_record_rejects_missing_id_and_bad_sheet(self):
for record in (
{"name": "Missing id", "sheet": {}},
{"id": "c1", "name": "Bad sheet", "sheet": []},
):
with self.assertRaises(HTTPException):
_validate_character_record(record)
def test_character_record_accepts_minimal_record(self):
record = {"id": "c1", "book": "Book", "name": "Name", "tags": "", "sheet": {}}
self.assertIs(_validate_character_record(record), record)
def test_private_url_is_rejected_when_downloads_are_public_only(self):
with self.assertRaises(HTTPException):
_validate_http_url("http://127.0.0.1:8188/image", allow_private=False)
def test_request_size_middleware_rejects_oversized_json(self):
sent = []
async def downstream(scope, receive, send):
sent.append({"type": "downstream"})
async def send(message):
sent.append(message)
scope = {
"type": "http", "method": "POST", "path": "/api/test",
"headers": [(b"content-type", b"application/json"), (b"content-length", b"40000000")],
}
asyncio.run(RequestSizeLimitMiddleware(downstream)(scope, None, send))
self.assertEqual(sent[0]["status"], 413)
self.assertNotIn({"type": "downstream"}, sent)
if __name__ == "__main__":
unittest.main()