""" Tests for decnet/templates/mongodb/server.py Covers the MongoDB wire-protocol (OP_MSG / OP_QUERY) happy path and regression tests for the zero-length msg_len infinite-loop bug and oversized msg_len. """ import importlib.util import struct import sys from unittest.mock import MagicMock import pytest from hypothesis import given, settings from hypothesis import strategies as st from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout # ── Helpers ─────────────────────────────────────────────────────────────────── def _load_mongodb(): for key in list(sys.modules): if key in ("mongodb_server", "syslog_bridge"): del sys.modules[key] sys.modules["syslog_bridge"] = make_fake_syslog_bridge() spec = importlib.util.spec_from_file_location("mongodb_server", "decnet/templates/mongodb/server.py") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod def _make_protocol(mod): proto = mod.MongoDBProtocol() transport = MagicMock() written: list[bytes] = [] transport.write.side_effect = written.append proto.connection_made(transport) return proto, transport, written def _minimal_bson() -> bytes: return b"\x05\x00\x00\x00\x00" # empty document def _op_msg_packet(request_id: int = 1) -> bytes: """Build a valid OP_MSG with an empty BSON body.""" flag_bits = struct.pack(" bytes: """Build a minimal OP_QUERY.""" flags = struct.pack("= 16 opcode = struct.unpack("= 16 opcode = struct.unpack("= 2 def test_connection_lost_does_not_raise(mongodb_mod): proto, _, _ = _make_protocol(mongodb_mod) proto.connection_lost(None) # ── Regression: malformed msg_len ──────────────────────────────────────────── def test_zero_msg_len_closes(mongodb_mod): proto, transport, _ = _make_protocol(mongodb_mod) # msg_len = 0 at bytes [0:4] LE — buffer has 16 bytes so outer while triggers data = b"\x00\x00\x00\x00" + b"\x00" * 12 run_with_timeout(proto.data_received, data) transport.close.assert_called() def test_msg_len_15_closes(mongodb_mod): proto, transport, _ = _make_protocol(mongodb_mod) # msg_len = 15 (below 16-byte wire-protocol minimum) data = struct.pack(" 48MB, so 48MB+1 must close data = struct.pack("