refactor: centralize ndjson streaming transport
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import unittest
|
||||
|
||||
from backend.http.handler import HttpTransportMixin
|
||||
|
||||
|
||||
class StreamError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class TransportStub(HttpTransportMixin):
|
||||
def __init__(self) -> None:
|
||||
self.statuses: list[int] = []
|
||||
self.response_headers: list[tuple[str, str]] = []
|
||||
self.wfile = io.BytesIO()
|
||||
self.close_connection = False
|
||||
|
||||
def send_response(self, status: int) -> None:
|
||||
self.statuses.append(int(status))
|
||||
|
||||
def send_header(self, name: str, value: str) -> None:
|
||||
self.response_headers.append((name, value))
|
||||
|
||||
def end_headers(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class HttpStreamingTests(unittest.TestCase):
|
||||
def test_stream_transport_preserves_headers_events_and_completion(self) -> None:
|
||||
handler = TransportStub()
|
||||
handler.send_ndjson_stream(
|
||||
({"type": "delta", "content": value} for value in ("甲", "乙")),
|
||||
(StreamError,),
|
||||
)
|
||||
|
||||
self.assertEqual(handler.statuses, [200])
|
||||
self.assertEqual(
|
||||
dict(handler.response_headers),
|
||||
{
|
||||
"Content-Type": "application/x-ndjson; charset=utf-8",
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
"X-Accel-Buffering": "no",
|
||||
"Connection": "close",
|
||||
},
|
||||
)
|
||||
events = [
|
||||
json.loads(line)
|
||||
for line in handler.wfile.getvalue().decode("utf-8").splitlines()
|
||||
]
|
||||
self.assertEqual(
|
||||
events,
|
||||
[
|
||||
{"type": "delta", "content": "甲"},
|
||||
{"type": "delta", "content": "乙"},
|
||||
{"type": "done"},
|
||||
],
|
||||
)
|
||||
self.assertTrue(handler.close_connection)
|
||||
|
||||
def test_stream_transport_preserves_feature_error_event(self) -> None:
|
||||
def events():
|
||||
yield {"type": "delta", "content": "partial"}
|
||||
raise StreamError("stream failed")
|
||||
|
||||
handler = TransportStub()
|
||||
handler.send_ndjson_stream(events(), (StreamError,))
|
||||
payloads = [
|
||||
json.loads(line)
|
||||
for line in handler.wfile.getvalue().decode("utf-8").splitlines()
|
||||
]
|
||||
self.assertEqual(
|
||||
payloads,
|
||||
[
|
||||
{"type": "delta", "content": "partial"},
|
||||
{"type": "error", "error": "stream failed"},
|
||||
],
|
||||
)
|
||||
self.assertTrue(handler.close_connection)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -40,6 +40,8 @@ class AccountSliceStructureTests(unittest.TestCase):
|
||||
"require_access",
|
||||
"serve_static",
|
||||
"send_json",
|
||||
"_write_stream_event",
|
||||
"send_ndjson_stream",
|
||||
):
|
||||
self.assertNotIn(method, RequestHandler.__dict__)
|
||||
self.assertIn(method, HttpTransportMixin.__dict__)
|
||||
|
||||
Reference in New Issue
Block a user