Skip to content

Commit 35a90f3

Browse files
Increased the time for 1s TTL tests (#693)
* Increased the time for 1s TTL tests Signed-off-by: Manav Gupta <[email protected]> * rebase and lint Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Manav Gupta <[email protected]> Signed-off-by: Mihai Criveti <[email protected]> Co-authored-by: Mihai Criveti <[email protected]>
1 parent 764d36f commit 35a90f3

File tree

3 files changed

+63
-57
lines changed

3 files changed

+63
-57
lines changed

mcpgateway/cache/resource_cache.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
>>> cache.get('a')
1919
1
2020
>>> import time
21-
>>> time.sleep(1.2)
21+
>>> time.sleep(1.5) # Use 1.5s to ensure expiration
2222
>>> cache.get('a') is None
2323
True
2424
>>> cache.set('a', 1)
@@ -74,7 +74,7 @@ class ResourceCache:
7474
>>> cache.get('a')
7575
1
7676
>>> import time
77-
>>> time.sleep(1.2)
77+
>>> time.sleep(1.5) # Use 1.5s to ensure expiration
7878
>>> cache.get('a') is None
7979
True
8080
>>> cache.set('a', 1)
@@ -135,7 +135,7 @@ def get(self, key: str) -> Optional[Any]:
135135
>>> short_cache.get('b')
136136
2
137137
>>> import time
138-
>>> time.sleep(1.2)
138+
>>> time.sleep(0.2) # Sleep longer than TTL (0.1s) to ensure expiration
139139
>>> short_cache.get('b') is None
140140
True
141141
"""

tests/unit/mcpgateway/cache/test_resource_cache.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ def test_get_missing(cache):
3838

3939
def test_expiration(cache):
4040
"""Test that cache entry expires after TTL."""
41+
# Use a more generous sleep duration to account for timing variability
4142
cache.set("foo", "bar")
42-
time.sleep(1.2)
43+
44+
# Sleep for 1.5 seconds (50% longer than TTL) to ensure expiration
45+
# This accounts for system load, clock precision, and floating point issues
46+
time.sleep(1.5)
47+
48+
# Entry should definitely be expired now
4349
assert cache.get("foo") is None
4450

4551

tests/unit/mcpgateway/services/test_logging_service_comprehensive.py

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ async def test_file_handler_creation_with_rotation():
3333
with tempfile.TemporaryDirectory() as tmpdir:
3434
log_file = "test.log"
3535
log_folder = tmpdir
36-
36+
3737
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
3838
mock_settings.log_to_file = True
3939
mock_settings.log_file = log_file
@@ -42,7 +42,7 @@ async def test_file_handler_creation_with_rotation():
4242
mock_settings.log_max_size_mb = 1
4343
mock_settings.log_backup_count = 3
4444
mock_settings.log_filemode = "a"
45-
45+
4646
handler = _get_file_handler()
4747
assert handler is not None
4848
assert handler.maxBytes == 1 * 1024 * 1024 # 1MB
@@ -55,18 +55,18 @@ async def test_file_handler_creation_without_rotation():
5555
with tempfile.TemporaryDirectory() as tmpdir:
5656
log_file = "test.log"
5757
log_folder = tmpdir
58-
58+
5959
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
6060
mock_settings.log_to_file = True
6161
mock_settings.log_file = log_file
6262
mock_settings.log_folder = log_folder
6363
mock_settings.log_rotation_enabled = False
6464
mock_settings.log_filemode = "a"
65-
65+
6666
# Reset global handler
6767
import mcpgateway.services.logging_service as ls
6868
ls._file_handler = None
69-
69+
7070
handler = _get_file_handler()
7171
assert handler is not None
7272
assert not hasattr(handler, 'maxBytes') # Regular FileHandler doesn't have this
@@ -77,11 +77,11 @@ async def test_file_handler_raises_when_disabled():
7777
"""Test that file handler raises ValueError when file logging is disabled."""
7878
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
7979
mock_settings.log_to_file = False
80-
80+
8181
# Reset global handler
8282
import mcpgateway.services.logging_service as ls
8383
ls._file_handler = None
84-
84+
8585
with pytest.raises(ValueError, match="File logging is disabled"):
8686
_get_file_handler()
8787

@@ -112,16 +112,16 @@ async def test_initialize_with_file_logging_enabled():
112112
mock_settings.log_max_size_mb = 2
113113
mock_settings.log_backup_count = 3
114114
mock_settings.log_filemode = "a"
115-
115+
116116
service = LoggingService()
117117
await service.initialize()
118-
118+
119119
root_logger = logging.getLogger()
120120
# Should have both text and file handlers
121121
handler_types = [type(h).__name__ for h in root_logger.handlers]
122122
assert 'StreamHandler' in handler_types
123123
assert 'RotatingFileHandler' in handler_types
124-
124+
125125
await service.shutdown()
126126

127127

@@ -131,15 +131,15 @@ async def test_initialize_with_file_logging_disabled():
131131
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
132132
mock_settings.log_to_file = False
133133
mock_settings.log_file = None
134-
134+
135135
service = LoggingService()
136136
await service.initialize()
137-
137+
138138
root_logger = logging.getLogger()
139139
# Should only have text handler
140140
handler_types = [type(h).__name__ for h in root_logger.handlers]
141141
assert 'StreamHandler' in handler_types
142-
142+
143143
await service.shutdown()
144144

145145

@@ -152,12 +152,12 @@ async def test_initialize_with_file_logging_error():
152152
mock_settings.log_folder = "/invalid/path"
153153
mock_settings.log_rotation_enabled = False
154154
mock_settings.log_filemode = "a"
155-
155+
156156
# Mock the file handler to raise an exception
157157
with patch("mcpgateway.services.logging_service._get_file_handler", side_effect=Exception("Cannot create file")):
158158
service = LoggingService()
159159
await service.initialize() # Should not raise, just log warning
160-
160+
161161
await service.shutdown()
162162

163163

@@ -171,7 +171,7 @@ async def test_configure_uvicorn_loggers():
171171
"""Test that uvicorn loggers are configured properly."""
172172
service = LoggingService()
173173
service._configure_uvicorn_loggers()
174-
174+
175175
uvicorn_loggers = ['uvicorn', 'uvicorn.access', 'uvicorn.error', 'uvicorn.asgi']
176176
for logger_name in uvicorn_loggers:
177177
logger = logging.getLogger(logger_name)
@@ -184,7 +184,7 @@ async def test_configure_uvicorn_loggers():
184184
async def test_configure_uvicorn_after_startup():
185185
"""Test public method to reconfigure uvicorn loggers after startup."""
186186
service = LoggingService()
187-
187+
188188
with patch.object(service, '_configure_uvicorn_loggers') as mock_config:
189189
service.configure_uvicorn_after_startup()
190190
mock_config.assert_called_once()
@@ -199,14 +199,14 @@ async def test_configure_uvicorn_after_startup():
199199
async def test_set_level_updates_all_loggers():
200200
"""Test that set_level updates all registered loggers."""
201201
service = LoggingService()
202-
202+
203203
# Create some loggers
204204
logger1 = service.get_logger("test1")
205205
logger2 = service.get_logger("test2")
206-
206+
207207
# Change level to ERROR
208208
await service.set_level(LogLevel.ERROR)
209-
209+
210210
# All loggers should be updated
211211
assert logger1.level == logging.ERROR
212212
assert logger2.level == logging.ERROR
@@ -217,7 +217,7 @@ async def test_set_level_updates_all_loggers():
217217
async def test_should_log_all_levels():
218218
"""Test _should_log for all log levels."""
219219
service = LoggingService()
220-
220+
221221
# Test each level (NOTICE, ALERT, EMERGENCY are also valid levels)
222222
test_cases = [
223223
(LogLevel.DEBUG, [LogLevel.DEBUG, LogLevel.INFO, LogLevel.NOTICE, LogLevel.WARNING, LogLevel.ERROR, LogLevel.CRITICAL, LogLevel.ALERT, LogLevel.EMERGENCY]),
@@ -227,10 +227,10 @@ async def test_should_log_all_levels():
227227
(LogLevel.ERROR, [LogLevel.ERROR, LogLevel.CRITICAL, LogLevel.ALERT, LogLevel.EMERGENCY]),
228228
(LogLevel.CRITICAL, [LogLevel.CRITICAL, LogLevel.ALERT, LogLevel.EMERGENCY]),
229229
]
230-
230+
231231
for min_level, should_pass in test_cases:
232232
service._level = min_level
233-
for level in [LogLevel.DEBUG, LogLevel.INFO, LogLevel.NOTICE, LogLevel.WARNING,
233+
for level in [LogLevel.DEBUG, LogLevel.INFO, LogLevel.NOTICE, LogLevel.WARNING,
234234
LogLevel.ERROR, LogLevel.CRITICAL, LogLevel.ALERT, LogLevel.EMERGENCY]:
235235
if level in should_pass:
236236
assert service._should_log(level), f"{level} should log at {min_level}"
@@ -247,13 +247,13 @@ async def test_should_log_all_levels():
247247
async def test_notify_with_logger_name():
248248
"""Test notify with a specific logger name."""
249249
service = LoggingService()
250-
250+
251251
with patch.object(service, 'get_logger') as mock_get_logger:
252252
mock_logger = MagicMock()
253253
mock_get_logger.return_value = mock_logger
254-
254+
255255
await service.notify("test message", LogLevel.INFO, logger_name="custom.logger")
256-
256+
257257
mock_get_logger.assert_called_with("custom.logger")
258258
mock_logger.info.assert_called_with("test message")
259259

@@ -262,13 +262,13 @@ async def test_notify_with_logger_name():
262262
async def test_notify_without_logger_name():
263263
"""Test notify without a specific logger name uses root logger."""
264264
service = LoggingService()
265-
265+
266266
with patch.object(service, 'get_logger') as mock_get_logger:
267267
mock_logger = MagicMock()
268268
mock_get_logger.return_value = mock_logger
269-
269+
270270
await service.notify("test message", LogLevel.WARNING)
271-
271+
272272
mock_get_logger.assert_called_with("")
273273
mock_logger.warning.assert_called_with("test message")
274274

@@ -277,12 +277,12 @@ async def test_notify_without_logger_name():
277277
async def test_notify_with_failed_subscriber():
278278
"""Test notify handles failed subscriber gracefully."""
279279
service = LoggingService()
280-
280+
281281
# Create a mock queue that raises an exception
282282
mock_queue = MagicMock()
283283
mock_queue.put = MagicMock(side_effect=Exception("Queue error"))
284284
service._subscribers.append(mock_queue)
285-
285+
286286
# Should not raise, just log the error
287287
await service.notify("test message", LogLevel.ERROR)
288288

@@ -300,13 +300,13 @@ async def test_get_logger_with_file_handler_error():
300300
mock_settings.log_to_file = True
301301
mock_settings.log_file = "test.log"
302302
mock_settings.log_folder = tmpdir
303-
303+
304304
service = LoggingService()
305-
305+
306306
# Mock file handler to raise exception
307307
with patch("mcpgateway.services.logging_service._get_file_handler", side_effect=Exception("File error")):
308308
logger = service.get_logger("test.logger")
309-
309+
310310
# Logger should still be created despite file handler error
311311
assert logger is not None
312312
assert logger.name == "test.logger"
@@ -316,10 +316,10 @@ async def test_get_logger_with_file_handler_error():
316316
async def test_get_logger_reuses_existing():
317317
"""Test get_logger returns existing logger instance."""
318318
service = LoggingService()
319-
319+
320320
logger1 = service.get_logger("test.app")
321321
logger2 = service.get_logger("test.app")
322-
322+
323323
assert logger1 is logger2
324324
assert len(service._loggers) == 1
325325

@@ -333,15 +333,15 @@ async def test_get_logger_reuses_existing():
333333
async def test_shutdown_clears_subscribers():
334334
"""Test shutdown clears all subscribers."""
335335
service = LoggingService()
336-
336+
337337
# Add some mock subscribers
338338
service._subscribers.append(MagicMock())
339339
service._subscribers.append(MagicMock())
340-
340+
341341
assert len(service._subscribers) == 2
342-
342+
343343
await service.shutdown()
344-
344+
345345
assert len(service._subscribers) == 0
346346

347347

@@ -355,34 +355,34 @@ async def test_dual_logging_integration():
355355
"""Integration test for dual logging to console and file."""
356356
with tempfile.TemporaryDirectory() as tmpdir:
357357
log_file = os.path.join(tmpdir, "integration.log")
358-
358+
359359
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
360360
mock_settings.log_to_file = True
361361
mock_settings.log_file = "integration.log"
362362
mock_settings.log_folder = tmpdir
363363
mock_settings.log_rotation_enabled = False
364364
mock_settings.log_filemode = "w"
365-
365+
366366
# Reset global handlers
367367
import mcpgateway.services.logging_service as ls
368368
ls._file_handler = None
369369
ls._text_handler = None
370-
370+
371371
service = LoggingService()
372372
await service.initialize()
373-
373+
374374
# Log some messages
375375
logger = service.get_logger("integration.test")
376376
logger.info("Integration test message")
377377
logger.error("Integration error message")
378-
378+
379379
# Configure uvicorn loggers
380380
service.configure_uvicorn_after_startup()
381381
uvicorn_logger = logging.getLogger("uvicorn.access")
382382
uvicorn_logger.info("127.0.0.1:8000 - \"GET /test HTTP/1.1\" 200")
383-
383+
384384
await service.shutdown()
385-
385+
386386
# Check file was created and contains expected content
387387
assert os.path.exists(log_file)
388388
with open(log_file, 'r') as f:
@@ -402,7 +402,7 @@ async def test_dual_logging_integration():
402402
async def test_get_logger_with_empty_name():
403403
"""Test get_logger with empty name returns root logger."""
404404
service = LoggingService()
405-
405+
406406
logger = service.get_logger("")
407407
assert logger.name == "root"
408408

@@ -411,7 +411,7 @@ async def test_get_logger_with_empty_name():
411411
async def test_notify_with_all_log_levels():
412412
"""Test notify works with all log level values including special ones."""
413413
service = LoggingService()
414-
414+
415415
# Test all levels including NOTICE, ALERT, EMERGENCY
416416
# which are now mapped to appropriate Python levels
417417
for level in [LogLevel.DEBUG, LogLevel.INFO, LogLevel.NOTICE, LogLevel.WARNING,
@@ -425,18 +425,18 @@ async def test_file_handler_creates_directory():
425425
"""Test that file handler creates log directory if it doesn't exist."""
426426
with tempfile.TemporaryDirectory() as tmpdir:
427427
log_folder = os.path.join(tmpdir, "new_logs")
428-
428+
429429
with patch("mcpgateway.services.logging_service.settings") as mock_settings:
430430
mock_settings.log_to_file = True
431431
mock_settings.log_file = "test.log"
432432
mock_settings.log_folder = log_folder
433433
mock_settings.log_rotation_enabled = False
434434
mock_settings.log_filemode = "a"
435-
435+
436436
# Reset global handler
437437
import mcpgateway.services.logging_service as ls
438438
ls._file_handler = None
439-
439+
440440
handler = _get_file_handler()
441441
assert handler is not None
442-
assert os.path.exists(log_folder)
442+
assert os.path.exists(log_folder)

0 commit comments

Comments
 (0)