Skip to content

Commit ed2ff2d

Browse files
test(streaming): add empty-monitors edge case for stream_alerts (#0db470)
Guard the path where stream_alerts receives an empty monitors list on first poll: verify nothing is yielded, asyncio.sleep is still called (the loop continues), and monitors appearing on the second poll set the baseline without triggering transition alerts.
1 parent d3f964c commit ed2ff2d

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

‎tests/unit/test_streaming.py‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,63 @@ async def capturing_sleep(interval: float) -> None:
290290

291291
assert recorded_intervals[0] == 5.0
292292

293+
async def test_stream_alerts_empty_monitors_yields_nothing(
294+
self, async_client: AsyncHyperpingClient
295+
) -> None:
296+
"""Empty monitors list on first poll yields nothing."""
297+
with (
298+
patch.object(async_client, "_request", new=AsyncMock(return_value=[])),
299+
patch("asyncio.sleep", new=AsyncMock(side_effect=asyncio.CancelledError)),
300+
):
301+
results = await _drain(
302+
async_client.stream_alerts(poll_interval=0.0), until_cancelled=True
303+
)
304+
305+
assert results == []
306+
307+
async def test_stream_alerts_empty_monitors_sleep_still_called(
308+
self, async_client: AsyncHyperpingClient
309+
) -> None:
310+
"""asyncio.sleep is still called when the monitors list is empty."""
311+
recorded_intervals: list[float] = []
312+
313+
async def capturing_sleep(interval: float) -> None:
314+
recorded_intervals.append(interval)
315+
raise asyncio.CancelledError
316+
317+
with (
318+
patch.object(async_client, "_request", new=AsyncMock(return_value=[])),
319+
patch("asyncio.sleep", new=capturing_sleep),
320+
):
321+
await _drain(async_client.stream_alerts(poll_interval=0.0), until_cancelled=True)
322+
323+
assert len(recorded_intervals) == 1
324+
325+
async def test_stream_alerts_empty_then_monitors_appear_no_transition(
326+
self, async_client: AsyncHyperpingClient
327+
) -> None:
328+
"""Monitors appearing after an empty first poll set the baseline without yielding."""
329+
poll1: list = []
330+
poll2 = [_monitor_dict("mon_1", "Test", down=False)]
331+
332+
sleep_calls = 0
333+
334+
async def controlled_sleep(_interval: float) -> None:
335+
nonlocal sleep_calls
336+
sleep_calls += 1
337+
if sleep_calls >= 2:
338+
raise asyncio.CancelledError
339+
340+
with (
341+
patch.object(async_client, "_request", new=AsyncMock(side_effect=[poll1, poll2])),
342+
patch("asyncio.sleep", new=controlled_sleep),
343+
):
344+
results = await _drain(
345+
async_client.stream_alerts(poll_interval=0.0), until_cancelled=True
346+
)
347+
348+
assert results == []
349+
293350

294351
# ---------------------------------------------------------------------------
295352
# stream_incident_updates tests

0 commit comments

Comments
 (0)