-
Notifications
You must be signed in to change notification settings - Fork 0
🧪 [Add URL support and test coverage for get_redis] #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aebd1e5
88c2705
b939201
dcb8f70
6b533ef
d710325
1249025
32f5cbe
29905d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import pytest | ||
| import sys | ||
| import os | ||
| from pathlib import Path | ||
| from unittest.mock import patch, MagicMock | ||
|
|
||
| os.environ["CONFIG_PATH"] = str(Path(__file__).resolve().parent.parent / "config.yaml") | ||
| sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) | ||
|
|
||
| from main import get_goose_sessions | ||
|
|
||
| def test_get_goose_sessions_no_db(): | ||
| with patch('os.path.exists', return_value=False): | ||
| assert get_goose_sessions() == [] | ||
|
|
||
| def test_get_goose_sessions_success(): | ||
| mock_sqlite3 = MagicMock() | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
|
|
||
| mock_sqlite3.connect.return_value = mock_conn | ||
| mock_conn.cursor.return_value = mock_cursor | ||
|
|
||
| mock_cursor.fetchall.return_value = [ | ||
| {"id": 1, "name": "s1"}, | ||
| {"id": 2, "name": "s2"} | ||
| ] | ||
|
|
||
| with patch('os.path.exists', return_value=True): | ||
| with patch.dict(sys.modules, {'sqlite3': mock_sqlite3}): | ||
| result = get_goose_sessions() | ||
|
|
||
| assert len(result) == 2 | ||
| assert result[0] == {"id": 1, "name": "s1"} | ||
| mock_sqlite3.connect.assert_called_once_with("/config/goose_sessions/sessions/sessions.db", timeout=1.0) | ||
| mock_cursor.execute.assert_called_once() | ||
| mock_conn.close.assert_called_once() | ||
|
|
||
| def test_get_goose_sessions_exception(): | ||
| mock_sqlite3 = MagicMock() | ||
| mock_sqlite3.connect.side_effect = Exception("DB error") | ||
|
|
||
| with patch('os.path.exists', return_value=True): | ||
| with patch.dict(sys.modules, {'sqlite3': mock_sqlite3}): | ||
| result = get_goose_sessions() | ||
| assert result == [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,3 +99,38 @@ def test_get_redis_initialization_exception(mock_logger_warning, mock_redis, moc | |
| assert main._redis_last_init_attempt == 110.0 | ||
| mock_logger_warning.assert_called_once() | ||
| assert "Test Exception" in mock_logger_warning.call_args[0][0] | ||
|
|
||
| @patch("router.main.time.monotonic") | ||
| @patch("router.main.aioredis.Redis.from_url") | ||
| @patch.dict(os.environ, {"VALKEY_URL": "redis://my-url:1234"}) | ||
| def test_get_redis_simulation_flow_url(mock_from_url, mock_monotonic): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Assert that This test only checks that Suggested implementation: # 1. First attempt fails
mock_monotonic.return_value = 10.0
mock_from_url.side_effect = Exception("Connection error")
assert main.get_redis() is None
assert main._redis_last_init_attempt == 10.0
# Redis.from_url should have been called once with the VALKEY_URL and expected options
mock_from_url.assert_called_once()
called_args, called_kwargs = mock_from_url.call_args
# First positional argument is the VALKEY_URL
assert called_args[0] == os.environ["VALKEY_URL"]
# Assert important keyword arguments to guard configuration regressions
assert "decode_responses" in called_kwargs
assert "socket_timeout" in called_kwargs
# 2. Second attempt during cooldown (e.g. 12.0s)
mock_monotonic.return_value = 12.0
mock_from_url.reset_mock()To fully meet your comment about asserting the exact options, you should:
|
||
| """Simulate the full flow for from_url: failure -> cooldown -> success -> cached.""" | ||
| # State is reset by the autouse fixture reset_redis_globals | ||
|
|
||
| # 1. First attempt fails | ||
| mock_monotonic.return_value = 10.0 | ||
| mock_from_url.side_effect = Exception("Connection error") | ||
| assert main.get_redis() is None | ||
| assert main._redis_last_init_attempt == 10.0 | ||
|
|
||
| # 2. Second attempt during cooldown (e.g. 12.0s) | ||
| mock_monotonic.return_value = 12.0 | ||
| mock_from_url.reset_mock() | ||
| assert main.get_redis() is None | ||
| mock_from_url.assert_not_called() | ||
|
|
||
| # 3. Third attempt after cooldown (e.g. 16.0s) succeeds | ||
| mock_monotonic.return_value = 16.0 | ||
| mock_redis_instance = MagicMock() | ||
| mock_from_url.side_effect = None | ||
| mock_from_url.return_value = mock_redis_instance | ||
| client = main.get_redis() | ||
| assert client is mock_redis_instance | ||
| assert main._redis_client is mock_redis_instance | ||
| mock_from_url.assert_called_once() | ||
|
|
||
| # 4. Fourth attempt returns cached instance | ||
| mock_monotonic.return_value = 18.0 | ||
| mock_from_url.reset_mock() | ||
| assert main.get_redis() is mock_redis_instance | ||
| mock_from_url.assert_not_called() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
redis-pylibrary (imported here asaioredis) does not natively supportvalkey://orvalkeys://URL schemes. If a user configuresVALKEY_URLusing one of these schemes (which is highly likely given the variable name),aioredis.Redis.from_urlwill raise aValueError: Unknown URL scheme.To ensure compatibility, we should sanitize the URL by converting
valkey://andvalkeys://toredis://andrediss://respectively before passing it tofrom_url.