From f6dd31d06fc093141637a60a2018796df0d8a33b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 09:49:02 +0000 Subject: [PATCH 1/2] perf: Use aiofiles for reading gemini oauth creds Co-authored-by: sheepdestroyer <1377479+sheepdestroyer@users.noreply.github.com> --- router/main.py | 11 +++++----- router/tests/test_get_gemini_oauth_status.py | 14 +++++++++---- router/tests/test_read_json_file_sync.py | 21 ++++++++++++-------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/router/main.py b/router/main.py index 1b23603b..2487b4b6 100644 --- a/router/main.py +++ b/router/main.py @@ -1291,10 +1291,11 @@ async def classify_request( return "agent-advanced-core", latency, False, "advanced (exception)" -def _read_json_file_sync(file_path: str) -> dict: - """Helper to read JSON files synchronously.""" - with open(file_path, "r") as f: - return json.load(f) +async def _read_json_file_async(file_path: str) -> dict: + """Helper to read JSON files asynchronously.""" + async with aiofiles.open(file_path, "r", encoding="utf-8") as f: + content = await f.read() + return json.loads(content) @@ -1307,7 +1308,7 @@ async def get_gemini_oauth_status() -> dict: "detail": "No oauth_creds.json found", "expiry_ms": 0, } - data = await asyncio.to_thread(_read_json_file_sync, GEMINI_OAUTH_CREDS_PATH) + data = await _read_json_file_async(GEMINI_OAUTH_CREDS_PATH) access_token = data.get("access_token") expiry_ms = data.get("expiry_date", 0) current_ms = int(time.time() * 1000) diff --git a/router/tests/test_get_gemini_oauth_status.py b/router/tests/test_get_gemini_oauth_status.py index 016b5356..89cfc3be 100644 --- a/router/tests/test_get_gemini_oauth_status.py +++ b/router/tests/test_get_gemini_oauth_status.py @@ -1,6 +1,6 @@ import pytest import json -from unittest.mock import patch, mock_open +from unittest.mock import patch, AsyncMock from router import main @@ -13,8 +13,11 @@ async def test_get_gemini_oauth_status_missing_file(): @pytest.mark.asyncio async def test_get_gemini_oauth_status_no_access_token(): mock_data = {"expiry_date": 1234567890000} + mock_file = AsyncMock() + mock_file.read.return_value = json.dumps(mock_data) + mock_file.__aenter__.return_value = mock_file with patch("os.path.exists", return_value=True), \ - patch("builtins.open", mock_open(read_data=json.dumps(mock_data))): + patch("aiofiles.open", return_value=mock_file): result = await main.get_gemini_oauth_status() assert result == {"status": "missing", "detail": "No access token in file", "expiry_ms": 0} @@ -31,8 +34,11 @@ async def test_get_gemini_oauth_status_scenarios(delta, expected_status, expecte current_time_ms = 1000000000000 expiry_ms = current_time_ms + delta mock_data = {"access_token": "test_token", "expiry_date": expiry_ms} + mock_file = AsyncMock() + mock_file.read.return_value = json.dumps(mock_data) + mock_file.__aenter__.return_value = mock_file with patch("os.path.exists", return_value=True), \ - patch("builtins.open", mock_open(read_data=json.dumps(mock_data))), \ + patch("aiofiles.open", return_value=mock_file), \ patch("time.time", return_value=current_time_ms / 1000.0): result = await main.get_gemini_oauth_status() assert result == {"status": expected_status, "detail": expected_detail, "expiry_ms": expiry_ms} @@ -40,6 +46,6 @@ async def test_get_gemini_oauth_status_scenarios(delta, expected_status, expecte @pytest.mark.asyncio async def test_get_gemini_oauth_status_exception(): with patch("os.path.exists", return_value=True), \ - patch("builtins.open", side_effect=Exception("Test error")): + patch("aiofiles.open", side_effect=Exception("Test error")): result = await main.get_gemini_oauth_status() assert result == {"status": "error", "detail": "Test error", "expiry_ms": 0} diff --git a/router/tests/test_read_json_file_sync.py b/router/tests/test_read_json_file_sync.py index 4d385d6d..89fdce58 100644 --- a/router/tests/test_read_json_file_sync.py +++ b/router/tests/test_read_json_file_sync.py @@ -1,14 +1,18 @@ import json -from unittest.mock import mock_open, patch +from unittest.mock import patch, AsyncMock import pytest from router import main -def test_read_json_file_sync_success(): +@pytest.mark.asyncio +async def test_read_json_file_sync_success(): mock_data = '{"key": "value"}' - with patch("builtins.open", mock_open(read_data=mock_data)): - result = main._read_json_file_sync("dummy_path.json") + mock_file = AsyncMock() + mock_file.read.return_value = mock_data + mock_file.__aenter__.return_value = mock_file + with patch("aiofiles.open", return_value=mock_file): + result = await main._read_json_file_async("dummy_path.json") assert result == {"key": "value"} @@ -16,7 +20,7 @@ def test_read_json_file_sync_success(): "mock_kwargs, expected_exc, match_msg", [ ( - {"new": mock_open(read_data='{"key": "value"')}, + {"return_value": AsyncMock(__aenter__=AsyncMock(return_value=AsyncMock(read=AsyncMock(return_value='{"key": "value"'))))}, json.JSONDecodeError, r"Unterminated string starting at|Expecting", ), @@ -32,7 +36,8 @@ def test_read_json_file_sync_success(): ), ], ) -def test_read_json_file_sync_errors(mock_kwargs, expected_exc, match_msg): - with patch("builtins.open", **mock_kwargs): +@pytest.mark.asyncio +async def test_read_json_file_sync_errors(mock_kwargs, expected_exc, match_msg): + with patch("aiofiles.open", **mock_kwargs): with pytest.raises(expected_exc, match=match_msg): - main._read_json_file_sync("dummy_path.json") + await main._read_json_file_async("dummy_path.json") From 96f3d4e96e3b6cb3a1b2afcd86ccfbe92e974278 Mon Sep 17 00:00:00 2001 From: boy Date: Fri, 24 Jul 2026 12:37:54 +0200 Subject: [PATCH 2/2] refactor: rename test_read_json_file_sync.py to test_read_json_file_async.py for consistency --- ...st_read_json_file_sync.py => test_read_json_file_async.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename router/tests/{test_read_json_file_sync.py => test_read_json_file_async.py} (91%) diff --git a/router/tests/test_read_json_file_sync.py b/router/tests/test_read_json_file_async.py similarity index 91% rename from router/tests/test_read_json_file_sync.py rename to router/tests/test_read_json_file_async.py index 89fdce58..85ae0044 100644 --- a/router/tests/test_read_json_file_sync.py +++ b/router/tests/test_read_json_file_async.py @@ -6,7 +6,7 @@ @pytest.mark.asyncio -async def test_read_json_file_sync_success(): +async def test_read_json_file_async_success(): mock_data = '{"key": "value"}' mock_file = AsyncMock() mock_file.read.return_value = mock_data @@ -37,7 +37,7 @@ async def test_read_json_file_sync_success(): ], ) @pytest.mark.asyncio -async def test_read_json_file_sync_errors(mock_kwargs, expected_exc, match_msg): +async def test_read_json_file_async_errors(mock_kwargs, expected_exc, match_msg): with patch("aiofiles.open", **mock_kwargs): with pytest.raises(expected_exc, match=match_msg): await main._read_json_file_async("dummy_path.json")