fix(core): preserve data integrity and bound shared UI and response work
Module Package Release / publish-packages (push) Successful in 13s

Release v0.1.46. Coordinated integrity review: GovOPlaN/govoplan-core#298.
This commit is contained in:
2026-09-08 12:30:38 +02:00
parent dc1f244f17
commit 6591aaa3fd
33 changed files with 1889 additions and 114 deletions
+71 -1
View File
@@ -1,15 +1,85 @@
from __future__ import annotations
import unittest
from unittest.mock import patch
from fastapi import APIRouter, Response
from fastapi import APIRouter, Request, Response
from fastapi.responses import PlainTextResponse
from fastapi.testclient import TestClient
from starlette.background import BackgroundTask
from starlette.responses import StreamingResponse
from govoplan_core.auth import get_api_principal
from govoplan_core.core.registry import PlatformRegistry
from govoplan_core.server.fastapi import create_govoplan_app
from govoplan_core.server.platform import create_platform_router
from govoplan_core.server.conditional_requests import conditional_json_get_middleware
class ConditionalBufferTests(unittest.IsolatedAsyncioTestCase):
async def test_unknown_length_overflow_replays_exact_bytes_without_eager_drain(self) -> None:
chunks = [b'{"value":"', b'', b'a' * 32, b'b' * 32, b'c' * 32, b'"}']
consumed = []
async def body():
for chunk in chunks:
consumed.append(chunk)
yield chunk
background = BackgroundTask(lambda: None)
response = StreamingResponse(body(), media_type="application/json", background=background)
async def route(request):
return response
request = Request({"type": "http", "method": "GET", "headers": [(b'if-none-match', b'*')]})
with patch("govoplan_core.server.conditional_requests.MAX_CONDITIONAL_JSON_BYTES", 64, create=True):
result = await conditional_json_get_middleware(request, route)
self.assertIs(result, response)
self.assertEqual(4, len(consumed))
self.assertEqual(200, result.status_code)
self.assertNotIn("etag", result.headers)
self.assertIn("private", result.headers["cache-control"])
self.assertIn("Authorization", result.headers["vary"])
self.assertIs(background, result.background)
self.assertEqual(b"".join(chunks), b"".join([chunk async for chunk in result.body_iterator]))
self.assertEqual(chunks, consumed)
async def test_known_large_body_is_not_consumed(self) -> None:
consumed = []
async def body():
consumed.append(True)
yield b"x" * 65
response = StreamingResponse(body(), media_type="application/json", headers={"Content-Length": "65"})
async def route(request):
return response
request = Request({"type": "http", "method": "GET", "headers": []})
with patch("govoplan_core.server.conditional_requests.MAX_CONDITIONAL_JSON_BYTES", 64, create=True):
result = await conditional_json_get_middleware(request, route)
self.assertIs(result, response)
self.assertEqual([], consumed)
self.assertEqual("65", result.headers["content-length"])
self.assertEqual(b"x" * 65, b"".join([chunk async for chunk in result.body_iterator]))
async def test_matching_small_response_still_runs_current_route_authorization(self) -> None:
calls = []
async def route(request):
calls.append(True)
if len(calls) > 1:
return Response(status_code=403)
return StreamingResponse(iter([b'{"ok":true}']), media_type="application/json")
request = Request({"type": "http", "method": "GET", "headers": []})
first = await conditional_json_get_middleware(request, route)
conditional = Request({"type": "http", "method": "GET", "headers": [(b'if-none-match', first.headers['etag'].encode())]})
second = await conditional_json_get_middleware(conditional, route)
self.assertEqual(403, second.status_code)
self.assertEqual(2, len(calls))
class ConditionalRequestTests(unittest.TestCase):