2626from pymongo .errors import ProtocolError
2727from pymongo .network_layer import PyMongoProtocol , _async_socket_receive
2828from test .asynchronous import AsyncUnitTest , unittest
29- from test .utils_shared import make_msg_header
29+ from test .utils_shared import pack_msg_header
3030
3131
3232def _make_protocol (timeout = None ):
@@ -43,7 +43,7 @@ async def asyncSetUp(self):
4343
4444 def test_op_msg_returns_body_len_and_op_code (self ):
4545 self .protocol ._header = memoryview (
46- bytearray (make_msg_header (length = 32 , request_id = 1 , response_to = 99 , op_code = 2013 ))
46+ bytearray (pack_msg_header (length = 32 , request_id = 1 , response_to = 99 , op_code = 2013 ))
4747 )
4848 body_len , op_code , response_to , expecting_compression = self .protocol .process_header ()
4949 self .assertEqual (body_len , 16 )
@@ -56,7 +56,7 @@ def test_op_compressed_sets_expecting_compression(self):
5656 # (op code + uncompressed size + compressor id), then the 16-byte standard header.
5757 # length=35 → after compression sub-header: 26 → body: 10
5858 self .protocol ._header = memoryview (
59- bytearray (make_msg_header (length = 35 , request_id = 1 , response_to = 0 , op_code = 2012 ))
59+ bytearray (pack_msg_header (length = 35 , request_id = 1 , response_to = 0 , op_code = 2012 ))
6060 )
6161 body_len , op_code , _response_to , expecting_compression = self .protocol .process_header ()
6262 self .assertEqual (body_len , 10 )
@@ -65,22 +65,22 @@ def test_op_compressed_sets_expecting_compression(self):
6565
6666 def test_op_compressed_length_too_small_raises (self ):
6767 self .protocol ._header = memoryview (
68- bytearray (make_msg_header (length = 25 , request_id = 1 , response_to = 0 , op_code = 2012 ))
68+ bytearray (pack_msg_header (length = 25 , request_id = 1 , response_to = 0 , op_code = 2012 ))
6969 )
7070 with self .assertRaisesRegex (ProtocolError , "not longer than standard OP_COMPRESSED" ):
7171 self .protocol .process_header ()
7272
7373 def test_non_compressed_length_too_small_raises (self ):
7474 self .protocol ._header = memoryview (
75- bytearray (make_msg_header (length = 16 , request_id = 1 , response_to = 0 , op_code = 2013 ))
75+ bytearray (pack_msg_header (length = 16 , request_id = 1 , response_to = 0 , op_code = 2013 ))
7676 )
7777 with self .assertRaisesRegex (ProtocolError , "not longer than standard message header size" ):
7878 self .protocol .process_header ()
7979
8080 def test_length_exceeds_max_raises (self ):
8181 self .protocol ._header = memoryview (
8282 bytearray (
83- make_msg_header (
83+ pack_msg_header (
8484 length = MAX_MESSAGE_SIZE + 1 , request_id = 1 , response_to = 0 , op_code = 2013
8585 )
8686 )
@@ -111,15 +111,31 @@ class TestBufferUpdated(AsyncUnitTest):
111111 async def asyncSetUp (self ):
112112 self .protocol = _make_protocol ()
113113
114- def test_zero_bytes_closes_connection (self ):
114+ async def test_zero_bytes_closes_connection (self ):
115+ # A zero-byte buffer_updated (connection closed mid-read) must surface to
116+ # a waiting reader as OSError("connection closed"), not just abort the transport.
117+ read_task = asyncio .create_task (
118+ self .protocol .read (request_id = None , max_message_size = MAX_MESSAGE_SIZE )
119+ )
120+ await asyncio .sleep (0 )
115121 self .protocol .buffer_updated (0 )
116122 self .assertTrue (self .protocol .transport .abort .called )
123+ with self .assertRaisesRegex (OSError , "connection closed" ):
124+ await read_task
117125
118- def test_protocol_error_closes_connection (self ):
126+ async def test_protocol_error_closes_connection (self ):
127+ # A malformed header must surface to a waiting reader as a ProtocolError,
128+ # not just abort the transport.
129+ read_task = asyncio .create_task (
130+ self .protocol .read (request_id = None , max_message_size = MAX_MESSAGE_SIZE )
131+ )
132+ await asyncio .sleep (0 )
119133 buf = self .protocol .get_buffer (16 )
120- buf [:16 ] = make_msg_header (length = 16 , request_id = 1 , response_to = 0 , op_code = 2013 )
134+ buf [:16 ] = pack_msg_header (length = 16 , request_id = 1 , response_to = 0 , op_code = 2013 )
121135 self .protocol .buffer_updated (16 )
122136 self .assertTrue (self .protocol .transport .abort .called )
137+ with self .assertRaisesRegex (ProtocolError , "not longer than standard message header" ):
138+ await read_task
123139
124140 async def test_resolves_pending_read (self ):
125141 read_task = asyncio .create_task (
@@ -128,7 +144,7 @@ async def test_resolves_pending_read(self):
128144 await asyncio .sleep (0 )
129145
130146 # Feed a valid 32-byte OP_MSG header (16-byte header + 16-byte body).
131- header = make_msg_header (length = 32 , request_id = 1 , response_to = 99 , op_code = 2013 )
147+ header = pack_msg_header (length = 32 , request_id = 1 , response_to = 99 , op_code = 2013 )
132148 buf = self .protocol .get_buffer (16 )
133149 buf [:16 ] = header
134150 self .protocol .buffer_updated (16 )
0 commit comments