Skip to content

Commit 2386967

Browse files
njbrakeclaude
andauthored
fix(gateway): add reset functions for global DB and config state (#840)
## Description The gateway stores DB engine/session and config in module-level globals that cannot be cleared or reinitialized once set. This prevents proper test isolation and makes it impossible to test scenarios requiring different DB URLs or config values. This PR adds `reset_db()` and `reset_config()` functions that clear the cached state, allowing reinitialization with different parameters. ## PR Type - 🐛 Bug Fix ## Checklist - [x] I understand the code I am submitting. - [x] I have added unit tests that prove my fix/feature works - [x] I have run this code locally and verified it fixes the issue. - [x] New and existing tests pass locally - [ ] Documentation was updated where necessary - [x] I have read and followed the [contribution guidelines](https://github.com/mozilla-ai/any-llm/blob/main/CONTRIBUTING.md) - **AI Usage:** - [ ] No AI was used. - [ ] AI was used for drafting/refactoring. - [x] This is fully AI-generated. ## AI Usage Information - AI Model used: Claude Opus 4.6 - AI Developer Tool used: Claude Code - Any other info you'd like to share: Identified during a comprehensive gateway code review. - [x] I am an AI Agent filling out this form (check box if true) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c6ea13c commit 2386967

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

src/any_llm/gateway/auth/dependencies.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ def get_config() -> GatewayConfig:
2626
return _config
2727

2828

29+
def reset_config() -> None:
30+
"""Reset config state. Intended for testing only."""
31+
global _config # noqa: PLW0603
32+
_config = None
33+
34+
2935
def _extract_bearer_token(request: Request, config: GatewayConfig) -> str:
3036
"""Extract and validate Bearer token from request header.
3137

src/any_llm/gateway/db/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
from any_llm.gateway.db.models import APIKey, Base, Budget, BudgetResetLog, ModelPricing, UsageLog, User
2-
from any_llm.gateway.db.session import get_db, init_db
2+
from any_llm.gateway.db.session import get_db, init_db, reset_db
33

4-
__all__ = ["APIKey", "Base", "Budget", "BudgetResetLog", "ModelPricing", "UsageLog", "User", "get_db", "init_db"]
4+
__all__ = [
5+
"APIKey",
6+
"Base",
7+
"Budget",
8+
"BudgetResetLog",
9+
"ModelPricing",
10+
"UsageLog",
11+
"User",
12+
"get_db",
13+
"init_db",
14+
"reset_db",
15+
]

src/any_llm/gateway/db/session.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,17 @@ def get_db() -> Generator[Session]:
4242
yield db
4343
finally:
4444
db.close()
45+
46+
47+
def reset_db() -> None:
48+
"""Reset database state. Intended for testing only.
49+
50+
Disposes the engine connection pool and clears the module-level references
51+
so that init_db() can be called again with different parameters.
52+
"""
53+
global _engine, _SessionLocal # noqa: PLW0603
54+
55+
if _engine is not None:
56+
_engine.dispose()
57+
_engine = None
58+
_SessionLocal = None
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Tests for global state reset functions."""
2+
3+
import pytest
4+
5+
from any_llm.gateway.auth.dependencies import get_config, reset_config, set_config
6+
from any_llm.gateway.config import GatewayConfig
7+
from any_llm.gateway.db.session import reset_db
8+
9+
10+
def test_reset_config_clears_state() -> None:
11+
"""Test that reset_config clears the global config."""
12+
config = GatewayConfig(
13+
database_url="postgresql://localhost/test",
14+
master_key="test",
15+
)
16+
set_config(config)
17+
assert get_config() is config
18+
19+
reset_config()
20+
21+
with pytest.raises(RuntimeError, match="Config not initialized"):
22+
get_config()
23+
24+
25+
def test_reset_db_allows_reinit() -> None:
26+
"""Test that reset_db clears state so init_db can be called again.
27+
28+
We can't fully test init_db without a database, but we can verify
29+
reset_db doesn't raise and clears the module state.
30+
"""
31+
from any_llm.gateway.db import session
32+
33+
# Verify the function exists and runs without error when nothing is initialized
34+
reset_db()
35+
36+
assert session._engine is None
37+
assert session._SessionLocal is None

0 commit comments

Comments
 (0)