diff --git a/server/tests/test_tcp_transport.py b/server/tests/test_tcp_transport.py new file mode 100644 index 0000000..ae82bc5 --- /dev/null +++ b/server/tests/test_tcp_transport.py @@ -0,0 +1,50 @@ +import socket + +import pytest + +from packet_codec import MAX_MESSAGE_BYTES, encode_packet +from tcp_transport import LineMessageBuffer, TcpFramingError, frame_message, send_message + + +def test_tcp_framing_adds_delimiter_only_at_transport_boundary(): + encoded = encode_packet({"type": "playerState", "characterName": "Nomad"}) + assert not encoded.payload.endswith(b"\n") + framed = frame_message(encoded.payload) + assert framed == encoded.payload + b"\n" + + +def test_line_buffer_preserves_fragmented_and_coalesced_messages(): + buffer = LineMessageBuffer() + assert buffer.feed(b'{"type":"first"') == [] + messages = buffer.feed(b'}\n{"type":"second"}\n{"type":"third"') + assert messages == [b'{"type":"first"}', b'{"type":"second"}'] + assert buffer.buffered_bytes > 0 + assert buffer.feed(b'}\r\n') == [b'{"type":"third"}'] + assert buffer.buffered_bytes == 0 + + +def test_line_buffer_rejects_oversize_unterminated_and_terminated_messages(): + with pytest.raises(TcpFramingError): + LineMessageBuffer().feed(b"x" * (MAX_MESSAGE_BYTES + 1)) + with pytest.raises(TcpFramingError): + LineMessageBuffer().feed((b"x" * (MAX_MESSAGE_BYTES + 1)) + b"\n") + + +def test_frame_rejects_raw_delimiters_and_oversize_payloads(): + with pytest.raises(TcpFramingError): + frame_message(b"bad\nmessage") + with pytest.raises(TcpFramingError): + frame_message(b"bad\rmessage") + with pytest.raises(TcpFramingError): + frame_message(b"x" * (MAX_MESSAGE_BYTES + 1)) + + +def test_send_message_preserves_existing_tcp_wire_format(): + reader, writer = socket.socketpair() + try: + payload = encode_packet({"type": "keepAlive"}).payload + send_message(writer, payload) + assert reader.recv(4096) == payload + b"\n" + finally: + reader.close() + writer.close()