refactor(V2): IBKR client — log tickle, type _http, retry once on 401
Code review fixes (commit 0c74691):
- _maybe_tickle logs failures via logger.debug instead of silent pass
- _http typed as httpx.AsyncClient | None
- 30s timeout commented (matches Alpaca, IBKR gateway latency)
- _request retries once on 401 with forced LST refresh (spec §4 IBKR_AUTH_FAILED)
- New tests: test_request_retries_once_on_401, test_request_raises_on_persistent_401
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,3 +52,37 @@ async def test_get_account_summary(httpx_mock: HTTPXMock, client):
|
||||
)
|
||||
data = await client.get_account()
|
||||
assert "netliquidation" in data
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_request_retries_once_on_401(httpx_mock: HTTPXMock, client):
|
||||
httpx_mock.add_response(url=re.compile(r".*/tickle"), json={})
|
||||
# First call returns 401
|
||||
httpx_mock.add_response(
|
||||
url=re.compile(r".*/portfolio/DU1234/summary"),
|
||||
status_code=401, text="session expired",
|
||||
)
|
||||
# Second call (after LST refresh) succeeds
|
||||
httpx_mock.add_response(
|
||||
url=re.compile(r".*/portfolio/DU1234/summary"),
|
||||
json={"netliquidation": {"amount": 5000}},
|
||||
)
|
||||
data = await client.get_account()
|
||||
assert data["netliquidation"]["amount"] == 5000
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_request_raises_on_persistent_401(httpx_mock: HTTPXMock, client):
|
||||
from cerbero_mcp.exchanges.ibkr.oauth import IBKRAuthError
|
||||
httpx_mock.add_response(url=re.compile(r".*/tickle"), json={})
|
||||
# Both attempts return 401
|
||||
httpx_mock.add_response(
|
||||
url=re.compile(r".*/portfolio/DU1234/summary"),
|
||||
status_code=401, text="bad creds",
|
||||
)
|
||||
httpx_mock.add_response(
|
||||
url=re.compile(r".*/portfolio/DU1234/summary"),
|
||||
status_code=401, text="bad creds",
|
||||
)
|
||||
with pytest.raises(IBKRAuthError, match="after retry"):
|
||||
await client.get_account()
|
||||
|
||||
Reference in New Issue
Block a user