From 938d9da08ce98a8b3633a1cf9cf308e41c2c12d7 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 23 Apr 2026 17:58:04 -0400 Subject: [PATCH 1/7] PYTHON-5781 Increase coverage for network_layer.py Add test/test_network_layer.py with 56 unit tests covering: - PyMongoProtocol: process_header (including ProtocolError paths), process_compression_header, get_buffer (all state branches), buffer_updated (state machine), close/connection_lost lifecycle - NetworkingInterfaceBase: abstract method NotImplementedError raises - NetworkingInterface: socket delegation methods - AsyncNetworkingInterface: transport/protocol delegation - sendall: trivial delegation - _async_socket_receive: success and connection-closed paths --- test/test_network_layer.py | 650 +++++++++++++++++++++++++++++++++++++ 1 file changed, 650 insertions(+) create mode 100644 test/test_network_layer.py diff --git a/test/test_network_layer.py b/test/test_network_layer.py new file mode 100644 index 0000000000..99148c82e7 --- /dev/null +++ b/test/test_network_layer.py @@ -0,0 +1,650 @@ +# Copyright 2026-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unit tests for network_layer.py. + +Tests cover pure-function and state-machine logic that does not require +a live socket or MongoDB server. Live-endpoint paths are exercised by +integration tests in test_client.py / test_ssl.py. +""" + +from __future__ import annotations + +import asyncio +import struct +import sys +import unittest +from unittest.mock import AsyncMock, MagicMock, patch + +sys.path[0:0] = [""] + +from pymongo.common import MAX_MESSAGE_SIZE +from pymongo.errors import ProtocolError +from pymongo.network_layer import ( + AsyncNetworkingInterface, + NetworkingInterface, + NetworkingInterfaceBase, + PyMongoProtocol, + _async_socket_receive, + sendall, +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _run(coro): + """Run a coroutine synchronously for testing.""" + return asyncio.run(coro) + + +async def _make_protocol(timeout=None): + """Create a PyMongoProtocol with a stubbed transport.""" + proto = PyMongoProtocol(timeout=timeout) + mock_transport = MagicMock() + mock_transport.is_closing.return_value = False + proto.transport = mock_transport + return proto + + +def _make_header(length, request_id, response_to, op_code): + """Pack a 16-byte MongoDB wire-protocol header.""" + return struct.pack(" 16) triggers ProtocolError + hdr = _make_header(16, 1, 0, 2013) + proto._header = memoryview(bytearray(hdr)) + proto._header_index = 0 + proto.buffer_updated(16) + return proto._connection_lost + + self.assertTrue(_run(_test())) + + def test_compression_header_processing(self): + async def _test(): + proto = await _make_protocol() + proto._expecting_header = False + proto._expecting_compression = True + comp_hdr = struct.pack(" Date: Thu, 23 Apr 2026 18:09:38 -0400 Subject: [PATCH 2/7] PYTHON-5781 Nit fixes - Fix mypy type error in test_network_layer.py - Use 'from test import unittest', remove self-evident docstrings from helpers - Fix inaccurate comment: second field in compression header is uncompressed_size --- test/test_network_layer.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/test_network_layer.py b/test/test_network_layer.py index 99148c82e7..daf0dff185 100644 --- a/test/test_network_layer.py +++ b/test/test_network_layer.py @@ -24,11 +24,12 @@ import asyncio import struct import sys -import unittest from unittest.mock import AsyncMock, MagicMock, patch sys.path[0:0] = [""] +from test import unittest + from pymongo.common import MAX_MESSAGE_SIZE from pymongo.errors import ProtocolError from pymongo.network_layer import ( @@ -45,13 +46,11 @@ # --------------------------------------------------------------------------- -def _run(coro): - """Run a coroutine synchronously for testing.""" - return asyncio.run(coro) +def _run(coroutine): + return asyncio.run(coroutine) async def _make_protocol(timeout=None): - """Create a PyMongoProtocol with a stubbed transport.""" proto = PyMongoProtocol(timeout=timeout) mock_transport = MagicMock() mock_transport.is_closing.return_value = False @@ -60,7 +59,6 @@ async def _make_protocol(timeout=None): def _make_header(length, request_id, response_to, op_code): - """Pack a 16-byte MongoDB wire-protocol header.""" return struct.pack(" Date: Fri, 1 May 2026 17:53:05 -0400 Subject: [PATCH 3/7] PYTHON-5781 Async split for test_network_layer.py - Add test/asynchronous/test_network_layer.py as the async source of truth with AsyncUnitTest and _IS_SYNC = False - Regenerate test/test_network_layer.py via synchro from the async source - Register test_network_layer.py in synchro converted_tests (alpha order) - Add "AsyncMock": "MagicMock" replacement after AsyncMockPool to avoid substring collision in translate_docstrings --- test/asynchronous/test_network_layer.py | 500 ++++++++++++++++++++ test/test_network_layer.py | 579 +++++++++--------------- tools/synchro.py | 2 + 3 files changed, 717 insertions(+), 364 deletions(-) create mode 100644 test/asynchronous/test_network_layer.py diff --git a/test/asynchronous/test_network_layer.py b/test/asynchronous/test_network_layer.py new file mode 100644 index 0000000000..fa207be49f --- /dev/null +++ b/test/asynchronous/test_network_layer.py @@ -0,0 +1,500 @@ +# Copyright 2026-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unit tests for network_layer.py.""" + +from __future__ import annotations + +import asyncio +import struct +import sys +from unittest.mock import AsyncMock, MagicMock, patch + +sys.path[0:0] = [""] + +from test.asynchronous import AsyncUnitTest, unittest + +from pymongo.common import MAX_MESSAGE_SIZE +from pymongo.errors import ProtocolError +from pymongo.network_layer import ( + AsyncNetworkingInterface, + NetworkingInterface, + NetworkingInterfaceBase, + PyMongoProtocol, + _async_socket_receive, + sendall, +) + +_IS_SYNC = False + + +async def _make_protocol(timeout=None): + proto = PyMongoProtocol(timeout=timeout) + mock_transport = MagicMock() + mock_transport.is_closing.return_value = False + proto.transport = mock_transport + return proto + + +def _make_header(length, request_id, response_to, op_code): + return struct.pack(" 16) triggers ProtocolError + hdr = _make_header(16, 1, 0, 2013) + proto._header = memoryview(bytearray(hdr)) + proto._header_index = 0 + proto.buffer_updated(16) + self.assertTrue(proto._connection_lost) + + async def test_compression_header_processing(self): + proto = await _make_protocol() + proto._expecting_header = False + proto._expecting_compression = True + comp_hdr = struct.pack(" 16) triggers ProtocolError hdr = _make_header(16, 1, 0, 2013) proto._header = memoryview(bytearray(hdr)) proto._header_index = 0 proto.buffer_updated(16) - return proto._connection_lost + self.assertTrue(proto._connection_lost) - self.assertTrue(_run(_test())) - - def test_compression_header_processing(self): - async def _test(): - proto = await _make_protocol() + def test_compression_header_processing(self): + proto = _make_protocol() proto._expecting_header = False proto._expecting_compression = True comp_hdr = struct.pack(" bool: "test_monitor.py", "test_monitoring.py", "test_mongos_load_balancing.py", + "test_network_layer.py", "test_on_demand_csfle.py", "test_pooling.py", "test_raw_bson.py", From 9d4bf46ea846e5f1262708f01fb06ce3e2397cc0 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Tue, 5 May 2026 18:24:21 -0400 Subject: [PATCH 4/7] Address Noah review by proxy Applying feedback from PYTHON-5784 to all open codecov PRs --- test/asynchronous/test_network_layer.py | 221 +++--------------------- test/test_network_layer.py | 221 +++--------------------- 2 files changed, 56 insertions(+), 386 deletions(-) diff --git a/test/asynchronous/test_network_layer.py b/test/asynchronous/test_network_layer.py index fa207be49f..8bfea71cff 100644 --- a/test/asynchronous/test_network_layer.py +++ b/test/asynchronous/test_network_layer.py @@ -125,42 +125,47 @@ def test_get_conn_returns_socket(self): def test_sock_returns_socket(self): self.assertIs(self.iface.sock, self.mock_sock) - if not _IS_SYNC: - def _make_async_iface(self): +if not _IS_SYNC: + + class TestAsyncNetworkingInterface(AsyncUnitTest): + def _make_iface(self): mock_transport = MagicMock() mock_protocol = MagicMock() mock_protocol.gettimeout = 10.0 return AsyncNetworkingInterface((mock_transport, mock_protocol)) - def test_async_gettimeout_returns_protocol_timeout(self): - iface = self._make_async_iface() + def test_gettimeout_returns_protocol_timeout(self): + iface = self._make_iface() self.assertEqual(iface.gettimeout, 10.0) - def test_async_settimeout_delegates_to_protocol(self): - iface = self._make_async_iface() + def test_settimeout_delegates_to_protocol(self): + iface = self._make_iface() iface.settimeout(7.0) iface.conn[1].settimeout.assert_called_once_with(7.0) - def test_async_is_closing_delegates_to_transport(self): - iface = self._make_async_iface() + def test_is_closing_delegates_to_transport(self): + iface = self._make_iface() iface.conn[0].is_closing.return_value = False self.assertFalse(iface.is_closing()) - def test_async_get_conn_returns_protocol(self): - iface = self._make_async_iface() + def test_get_conn_returns_protocol(self): + iface = self._make_iface() self.assertIs(iface.get_conn, iface.conn[1]) - def test_async_sock_returns_transport_socket(self): - iface = self._make_async_iface() + def test_sock_returns_transport_socket(self): + iface = self._make_iface() sentinel = object() iface.conn[0].get_extra_info.return_value = sentinel self.assertIs(iface.sock, sentinel) iface.conn[0].get_extra_info.assert_called_once_with("socket") - -class TestPyMongoProtocolTimeout(AsyncUnitTest): - if not _IS_SYNC: + class TestPyMongoProtocol(AsyncUnitTest): + async def _make_proto_with_header(self, header_bytes, max_size=MAX_MESSAGE_SIZE): + proto = await _make_protocol() + proto._max_message_size = max_size + proto._header = memoryview(bytearray(header_bytes)) + return proto async def test_initial_timeout_from_constructor(self): proto = await _make_protocol(timeout=3.0) @@ -175,16 +180,6 @@ async def test_default_timeout_is_none(self): proto = await _make_protocol() self.assertIsNone(proto.gettimeout) - -class TestPyMongoProtocolProcessHeader(AsyncUnitTest): - if not _IS_SYNC: - - async def _make_proto_with_header(self, header_bytes, max_size=MAX_MESSAGE_SIZE): - proto = await _make_protocol() - proto._max_message_size = max_size - proto._header = memoryview(bytearray(header_bytes)) - return proto - async def test_normal_op_msg(self): hdr = _make_header(32, 1, 99, 2013) proto = await self._make_proto_with_header(hdr) @@ -229,11 +224,7 @@ async def test_op_reply_op_code(self): self.assertEqual(op_code, 1) self.assertFalse(expecting_compression) - -class TestPyMongoProtocolProcessCompressionHeader(AsyncUnitTest): - if not _IS_SYNC: - - async def test_returns_op_code_and_compressor_id(self): + async def test_compression_header_returns_op_code_and_compressor_id(self): proto = await _make_protocol() # op_code=2013, uncompressed_size=0, compressor_id=1 (snappy) data = struct.pack(" 16) triggers ProtocolError - hdr = _make_header(16, 1, 0, 2013) - proto._header = memoryview(bytearray(hdr)) - proto._header_index = 0 - proto.buffer_updated(16) - self.assertTrue(proto._connection_lost) - - async def test_compression_header_processing(self): - proto = await _make_protocol() - proto._expecting_header = False - proto._expecting_compression = True - comp_hdr = struct.pack(" 16) triggers ProtocolError - hdr = _make_header(16, 1, 0, 2013) - proto._header = memoryview(bytearray(hdr)) - proto._header_index = 0 - proto.buffer_updated(16) - self.assertTrue(proto._connection_lost) - - def test_compression_header_processing(self): - proto = _make_protocol() - proto._expecting_header = False - proto._expecting_compression = True - comp_hdr = struct.pack(" Date: Tue, 5 May 2026 20:31:57 -0400 Subject: [PATCH 5/7] Rename vars --- test/asynchronous/test_network_layer.py | 212 ++++++++++++------------ test/test_network_layer.py | 212 ++++++++++++------------ 2 files changed, 212 insertions(+), 212 deletions(-) diff --git a/test/asynchronous/test_network_layer.py b/test/asynchronous/test_network_layer.py index 8bfea71cff..88e1d56a6e 100644 --- a/test/asynchronous/test_network_layer.py +++ b/test/asynchronous/test_network_layer.py @@ -40,11 +40,11 @@ async def _make_protocol(timeout=None): - proto = PyMongoProtocol(timeout=timeout) + protocol = PyMongoProtocol(timeout=timeout) mock_transport = MagicMock() mock_transport.is_closing.return_value = False - proto.transport = mock_transport - return proto + protocol.transport = mock_transport + return protocol def _make_header(length, request_id, response_to, op_code): @@ -53,9 +53,9 @@ def _make_header(length, request_id, response_to, op_code): class TestSendall(AsyncUnitTest): def test_delegates_to_sock_sendall(self): - mock_sock = MagicMock() - sendall(mock_sock, b"hello") - mock_sock.sendall.assert_called_once_with(b"hello") + mock_socket = MagicMock() + sendall(mock_socket, b"hello") + mock_socket.sendall.assert_called_once_with(b"hello") class TestNetworkingInterfaceBase(AsyncUnitTest): @@ -89,101 +89,101 @@ def test_sock_raises(self): class TestNetworkingInterface(AsyncUnitTest): def setUp(self): - self.mock_sock = MagicMock() - self.iface = NetworkingInterface(self.mock_sock) + self.mock_socket = MagicMock() + self.network_interface = NetworkingInterface(self.mock_socket) def test_gettimeout_delegates(self): - self.mock_sock.gettimeout.return_value = 5.0 - self.assertEqual(self.iface.gettimeout(), 5.0) + self.mock_socket.gettimeout.return_value = 5.0 + self.assertEqual(self.network_interface.gettimeout(), 5.0) def test_settimeout_delegates(self): - self.iface.settimeout(3.0) - self.mock_sock.settimeout.assert_called_once_with(3.0) + self.network_interface.settimeout(3.0) + self.mock_socket.settimeout.assert_called_once_with(3.0) def test_close_delegates(self): - self.iface.close() - self.mock_sock.close.assert_called_once() + self.network_interface.close() + self.mock_socket.close.assert_called_once() def test_is_closing_delegates(self): - self.mock_sock.is_closing.return_value = True - self.assertTrue(self.iface.is_closing()) + self.mock_socket.is_closing.return_value = True + self.assertTrue(self.network_interface.is_closing()) def test_fileno_delegates(self): - self.mock_sock.fileno.return_value = 42 - self.assertEqual(self.iface.fileno(), 42) + self.mock_socket.fileno.return_value = 42 + self.assertEqual(self.network_interface.fileno(), 42) def test_recv_into_delegates(self): buf = memoryview(bytearray(10)) - self.mock_sock.recv_into.return_value = 7 - result = self.iface.recv_into(buf) + self.mock_socket.recv_into.return_value = 7 + result = self.network_interface.recv_into(buf) self.assertEqual(result, 7) - self.mock_sock.recv_into.assert_called_once_with(buf) + self.mock_socket.recv_into.assert_called_once_with(buf) def test_get_conn_returns_socket(self): - self.assertIs(self.iface.get_conn, self.mock_sock) + self.assertIs(self.network_interface.get_conn, self.mock_socket) def test_sock_returns_socket(self): - self.assertIs(self.iface.sock, self.mock_sock) + self.assertIs(self.network_interface.sock, self.mock_socket) if not _IS_SYNC: class TestAsyncNetworkingInterface(AsyncUnitTest): - def _make_iface(self): + def _make_network_interface(self): mock_transport = MagicMock() mock_protocol = MagicMock() mock_protocol.gettimeout = 10.0 return AsyncNetworkingInterface((mock_transport, mock_protocol)) def test_gettimeout_returns_protocol_timeout(self): - iface = self._make_iface() - self.assertEqual(iface.gettimeout, 10.0) + network_interface = self._make_network_interface() + self.assertEqual(network_interface.gettimeout, 10.0) def test_settimeout_delegates_to_protocol(self): - iface = self._make_iface() - iface.settimeout(7.0) - iface.conn[1].settimeout.assert_called_once_with(7.0) + network_interface = self._make_network_interface() + network_interface.settimeout(7.0) + network_interface.conn[1].settimeout.assert_called_once_with(7.0) def test_is_closing_delegates_to_transport(self): - iface = self._make_iface() - iface.conn[0].is_closing.return_value = False - self.assertFalse(iface.is_closing()) + network_interface = self._make_network_interface() + network_interface.conn[0].is_closing.return_value = False + self.assertFalse(network_interface.is_closing()) def test_get_conn_returns_protocol(self): - iface = self._make_iface() - self.assertIs(iface.get_conn, iface.conn[1]) + network_interface = self._make_network_interface() + self.assertIs(network_interface.get_conn, network_interface.conn[1]) def test_sock_returns_transport_socket(self): - iface = self._make_iface() + network_interface = self._make_network_interface() sentinel = object() - iface.conn[0].get_extra_info.return_value = sentinel - self.assertIs(iface.sock, sentinel) - iface.conn[0].get_extra_info.assert_called_once_with("socket") + network_interface.conn[0].get_extra_info.return_value = sentinel + self.assertIs(network_interface.sock, sentinel) + network_interface.conn[0].get_extra_info.assert_called_once_with("socket") class TestPyMongoProtocol(AsyncUnitTest): async def _make_proto_with_header(self, header_bytes, max_size=MAX_MESSAGE_SIZE): - proto = await _make_protocol() - proto._max_message_size = max_size - proto._header = memoryview(bytearray(header_bytes)) - return proto + protocol = await _make_protocol() + protocol._max_message_size = max_size + protocol._header = memoryview(bytearray(header_bytes)) + return protocol async def test_initial_timeout_from_constructor(self): - proto = await _make_protocol(timeout=3.0) - self.assertEqual(proto.gettimeout, 3.0) + protocol = await _make_protocol(timeout=3.0) + self.assertEqual(protocol.gettimeout, 3.0) async def test_settimeout_updates_value(self): - proto = await _make_protocol() - proto.settimeout(7.5) - self.assertEqual(proto.gettimeout, 7.5) + protocol = await _make_protocol() + protocol.settimeout(7.5) + self.assertEqual(protocol.gettimeout, 7.5) async def test_default_timeout_is_none(self): - proto = await _make_protocol() - self.assertIsNone(proto.gettimeout) + protocol = await _make_protocol() + self.assertIsNone(protocol.gettimeout) async def test_normal_op_msg(self): - hdr = _make_header(32, 1, 99, 2013) - proto = await self._make_proto_with_header(hdr) - body_len, op_code, response_to, expecting_compression = proto.process_header() + header = _make_header(32, 1, 99, 2013) + protocol = await self._make_proto_with_header(header) + body_len, op_code, response_to, expecting_compression = protocol.process_header() self.assertEqual(body_len, 16) self.assertEqual(op_code, 2013) self.assertEqual(response_to, 99) @@ -191,101 +191,101 @@ async def test_normal_op_msg(self): async def test_op_compressed(self): # OP_COMPRESSED=2012, length=35 → adjusted=35-9=26 → body=26-16=10 - hdr = _make_header(35, 1, 0, 2012) - proto = await self._make_proto_with_header(hdr) - body_len, op_code, _response_to, expecting_compression = proto.process_header() + header = _make_header(35, 1, 0, 2012) + protocol = await self._make_proto_with_header(header) + body_len, op_code, _response_to, expecting_compression = protocol.process_header() self.assertEqual(body_len, 10) self.assertEqual(op_code, 2012) self.assertTrue(expecting_compression) async def test_op_compressed_length_too_small_raises(self): - hdr = _make_header(25, 1, 0, 2012) - proto = await self._make_proto_with_header(hdr) + header = _make_header(25, 1, 0, 2012) + protocol = await self._make_proto_with_header(header) with self.assertRaises(ProtocolError): - proto.process_header() + protocol.process_header() async def test_non_compressed_length_too_small_raises(self): - hdr = _make_header(16, 1, 0, 2013) - proto = await self._make_proto_with_header(hdr) + header = _make_header(16, 1, 0, 2013) + protocol = await self._make_proto_with_header(header) with self.assertRaises(ProtocolError): - proto.process_header() + protocol.process_header() async def test_length_exceeds_max_raises(self): - hdr = _make_header(MAX_MESSAGE_SIZE + 1, 1, 0, 2013) - proto = await self._make_proto_with_header(hdr) + header = _make_header(MAX_MESSAGE_SIZE + 1, 1, 0, 2013) + protocol = await self._make_proto_with_header(header) with self.assertRaises(ProtocolError): - proto.process_header() + protocol.process_header() async def test_op_reply_op_code(self): - hdr = _make_header(20, 0, 0, 1) - proto = await self._make_proto_with_header(hdr) - body_len, op_code, _response_to, expecting_compression = proto.process_header() + header = _make_header(20, 0, 0, 1) + protocol = await self._make_proto_with_header(header) + body_len, op_code, _response_to, expecting_compression = protocol.process_header() self.assertEqual(body_len, 4) self.assertEqual(op_code, 1) self.assertFalse(expecting_compression) async def test_compression_header_returns_op_code_and_compressor_id(self): - proto = await _make_protocol() + protocol = await _make_protocol() # op_code=2013, uncompressed_size=0, compressor_id=1 (snappy) data = struct.pack(" Date: Tue, 5 May 2026 20:50:49 -0400 Subject: [PATCH 6/7] Update OP_COMPRESSED comment --- test/asynchronous/test_network_layer.py | 2 +- test/test_network_layer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asynchronous/test_network_layer.py b/test/asynchronous/test_network_layer.py index 88e1d56a6e..8e806ba763 100644 --- a/test/asynchronous/test_network_layer.py +++ b/test/asynchronous/test_network_layer.py @@ -226,7 +226,7 @@ async def test_op_reply_op_code(self): async def test_compression_header_returns_op_code_and_compressor_id(self): protocol = await _make_protocol() - # op_code=2013, uncompressed_size=0, compressor_id=1 (snappy) + # Date: Wed, 6 May 2026 17:22:56 -0400 Subject: [PATCH 7/7] Noah + Copilot review --- test/asynchronous/test_async_network_layer.py | 211 +++++++++++++ test/asynchronous/test_network_layer.py | 285 +----------------- test/test_network_layer.py | 282 +---------------- tools/synchro.py | 1 + 4 files changed, 225 insertions(+), 554 deletions(-) create mode 100644 test/asynchronous/test_async_network_layer.py diff --git a/test/asynchronous/test_async_network_layer.py b/test/asynchronous/test_async_network_layer.py new file mode 100644 index 0000000000..2480bbf61c --- /dev/null +++ b/test/asynchronous/test_async_network_layer.py @@ -0,0 +1,211 @@ +# Copyright 2026-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Async-only unit tests for network_layer.py.""" + +from __future__ import annotations + +import asyncio +import struct +import sys +from unittest.mock import AsyncMock, MagicMock, patch + +sys.path[0:0] = [""] + +from test.asynchronous import AsyncUnitTest, unittest + +from pymongo.common import MAX_MESSAGE_SIZE +from pymongo.errors import ProtocolError +from pymongo.network_layer import PyMongoProtocol, _async_socket_receive + + +async def _make_protocol(timeout=None): + protocol = PyMongoProtocol(timeout=timeout) + mock_transport = MagicMock() + mock_transport.is_closing.return_value = False + protocol.transport = mock_transport + return protocol + + +def _make_header(length, request_id, response_to, op_code): + return struct.pack(" bool: "test_async_loop_safety.py", "test_async_contextvars_reset.py", "test_async_loop_unblocked.py", + "test_async_network_layer.py", ]