Skip to content

Commit ec3819e

Browse files
authored
Merge branch 'master' into PYTHON-5087
2 parents fb8ed79 + c8d3afd commit ec3819e

10 files changed

+653
-63
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright 2016-present MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Test the monitoring of the server heartbeats."""
16+
from __future__ import annotations
17+
18+
import sys
19+
20+
sys.path[0:0] = [""]
21+
22+
from test.asynchronous import AsyncIntegrationTest, client_knobs, unittest
23+
from test.utils import AsyncMockPool, HeartbeatEventListener, async_wait_until
24+
25+
from pymongo.asynchronous.monitor import Monitor
26+
from pymongo.errors import ConnectionFailure
27+
from pymongo.hello import Hello, HelloCompat
28+
29+
_IS_SYNC = False
30+
31+
32+
class TestHeartbeatMonitoring(AsyncIntegrationTest):
33+
async def create_mock_monitor(self, responses, uri, expected_results):
34+
listener = HeartbeatEventListener()
35+
with client_knobs(
36+
heartbeat_frequency=0.1, min_heartbeat_interval=0.1, events_queue_frequency=0.1
37+
):
38+
39+
class MockMonitor(Monitor):
40+
async def _check_with_socket(self, *args, **kwargs):
41+
if isinstance(responses[1], Exception):
42+
raise responses[1]
43+
return Hello(responses[1]), 99
44+
45+
_ = await self.async_single_client(
46+
h=uri,
47+
event_listeners=(listener,),
48+
_monitor_class=MockMonitor,
49+
_pool_class=AsyncMockPool,
50+
connect=True,
51+
)
52+
53+
expected_len = len(expected_results)
54+
# Wait for *at least* expected_len number of results. The
55+
# monitor thread may run multiple times during the execution
56+
# of this test.
57+
await async_wait_until(
58+
lambda: len(listener.events) >= expected_len, "publish all events"
59+
)
60+
61+
# zip gives us len(expected_results) pairs.
62+
for expected, actual in zip(expected_results, listener.events):
63+
self.assertEqual(expected, actual.__class__.__name__)
64+
self.assertEqual(actual.connection_id, responses[0])
65+
if expected != "ServerHeartbeatStartedEvent":
66+
if isinstance(actual.reply, Hello):
67+
self.assertEqual(actual.duration, 99)
68+
self.assertEqual(actual.reply._doc, responses[1])
69+
else:
70+
self.assertEqual(actual.reply, responses[1])
71+
72+
async def test_standalone(self):
73+
responses = (
74+
("a", 27017),
75+
{HelloCompat.LEGACY_CMD: True, "maxWireVersion": 4, "minWireVersion": 0, "ok": 1},
76+
)
77+
uri = "mongodb://a:27017"
78+
expected_results = ["ServerHeartbeatStartedEvent", "ServerHeartbeatSucceededEvent"]
79+
80+
await self.create_mock_monitor(responses, uri, expected_results)
81+
82+
async def test_standalone_error(self):
83+
responses = (("a", 27017), ConnectionFailure("SPECIAL MESSAGE"))
84+
uri = "mongodb://a:27017"
85+
# _check_with_socket failing results in a second attempt.
86+
expected_results = [
87+
"ServerHeartbeatStartedEvent",
88+
"ServerHeartbeatFailedEvent",
89+
"ServerHeartbeatStartedEvent",
90+
"ServerHeartbeatFailedEvent",
91+
]
92+
93+
await self.create_mock_monitor(responses, uri, expected_results)
94+
95+
96+
if __name__ == "__main__":
97+
unittest.main()

0 commit comments

Comments
 (0)