|
8 | 8 | from __future__ import annotations |
9 | 9 |
|
10 | 10 | import logging |
11 | | -import time |
| 11 | +import threading |
12 | 12 |
|
13 | 13 | import pytest |
14 | 14 |
|
@@ -87,21 +87,33 @@ def test_stop_without_start_is_noop(): |
87 | 87 | assert mm.is_running() is False |
88 | 88 |
|
89 | 89 |
|
90 | | -def test_periodic_timer_fires(caplog): |
91 | | - caplog.set_level(logging.INFO, logger="gateway.memory_monitor") |
92 | | - # Short interval so we can observe multiple ticks inside the test budget. |
93 | | - mm.start_memory_monitoring(interval_seconds=0.1) |
94 | | - time.sleep(0.45) |
95 | | - mm.stop_memory_monitoring(timeout=1.0) |
| 90 | +def test_periodic_timer_fires(monkeypatch): |
| 91 | + periodic_ticks = 0 |
| 92 | + periodic_ticks_lock = threading.Lock() |
| 93 | + periodic_tick_event = threading.Event() |
| 94 | + original_log_memory_usage = mm.log_memory_usage |
| 95 | + |
| 96 | + def _instrumented_log_memory_usage(prefix: str = "") -> None: |
| 97 | + nonlocal periodic_ticks |
| 98 | + original_log_memory_usage(prefix=prefix) |
| 99 | + if prefix: |
| 100 | + return |
| 101 | + with periodic_ticks_lock: |
| 102 | + periodic_ticks += 1 |
| 103 | + if periodic_ticks >= 2: |
| 104 | + periodic_tick_event.set() |
| 105 | + |
| 106 | + monkeypatch.setattr(mm, "log_memory_usage", _instrumented_log_memory_usage) |
| 107 | + started = mm.start_memory_monitoring(interval_seconds=0.1) |
| 108 | + assert started is True |
| 109 | + |
| 110 | + try: |
| 111 | + # Behavioral contract: while running, monitor emits repeated periodic ticks. |
| 112 | + fired = periodic_tick_event.wait(timeout=1.0) |
| 113 | + finally: |
| 114 | + mm.stop_memory_monitoring(timeout=1.0) |
96 | 115 |
|
97 | | - periodic = [ |
98 | | - r for r in caplog.records |
99 | | - if r.getMessage().startswith("[MEMORY] rss=") or r.getMessage().startswith("[MEMORY] rss=unavailable") |
100 | | - ] |
101 | | - # baseline + at least 2 periodic + shutdown — but shutdown has the |
102 | | - # "shutdown " prefix so it won't match the strict "[MEMORY] rss=" start. |
103 | | - # We expect >= 3 bare "[MEMORY] rss=..." lines. |
104 | | - assert len(periodic) >= 3, [r.getMessage() for r in caplog.records] |
| 116 | + assert fired, f"expected at least two periodic ticks, saw {periodic_ticks}" |
105 | 117 |
|
106 | 118 |
|
107 | 119 | def test_thread_is_daemon(): |
|
0 commit comments