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()