Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/quilt_hp/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async def intercept_unary_unary(
return await cast("Awaitable[object]", call)
except grpc.aio.AioRpcError as exc:
if exc.code() == grpc.StatusCode.UNAUTHENTICATED and self._refresh_callback:
logger.warning("Retrying unary RPC after UNAUTHENTICATED response")
logger.info("Retrying unary RPC after UNAUTHENTICATED response")
return await self._refresh_and_retry_unary(
continuation, client_call_details, request
)
Expand All @@ -155,7 +155,7 @@ async def intercept_unary_stream(
await cast("Any", call).wait_for_connection()
except grpc.aio.AioRpcError as exc:
if exc.code() == grpc.StatusCode.UNAUTHENTICATED and self._refresh_callback:
logger.warning("Retrying streaming RPC setup after UNAUTHENTICATED response")
logger.info("Retrying streaming RPC setup after UNAUTHENTICATED response")
await self._refresh()
retried = await continuation(self._patch(client_call_details), request)
try:
Expand Down
82 changes: 82 additions & 0 deletions tests/test_transport_interceptor_extra.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import inspect
import logging
from unittest.mock import MagicMock

import grpc
Expand Down Expand Up @@ -136,6 +137,87 @@ async def _continuation(call_details: grpc.aio.ClientCallDetails, request: objec
assert refreshed == ["yes"]


@pytest.mark.asyncio
async def test_auth_interceptor_logs_unary_retry_at_info(
caplog: pytest.LogCaptureFixture,
) -> None:
refreshed: list[str] = []

async def _refresh(_context: transport.TokenRefreshContext) -> None:
refreshed.append("yes")

interceptor = transport._AuthInterceptor(lambda: "******", refresh_callback=_refresh)
details = grpc.aio.ClientCallDetails(
method="/svc/method",
timeout=1,
metadata=None,
credentials=None,
wait_for_ready=False,
)

calls = 0

async def _continuation(_call_details: grpc.aio.ClientCallDetails, request: object) -> object:
nonlocal calls
calls += 1
if calls == 1:
return _FakeCall(error=_FakeRpcError(grpc.StatusCode.UNAUTHENTICATED, "expired"))
return _FakeCall(result=request)

with caplog.at_level(logging.INFO):
assert await interceptor.intercept_unary_unary(_continuation, details, "req") == "req"

matching = [
record
for record in caplog.records
if record.getMessage() == "Retrying unary RPC after UNAUTHENTICATED response"
]
assert matching
assert all(record.levelno == logging.INFO for record in matching)
assert refreshed == ["yes"]


@pytest.mark.asyncio
async def test_auth_interceptor_logs_stream_setup_retry_at_info(
caplog: pytest.LogCaptureFixture,
) -> None:
refreshed: list[str] = []

async def _refresh(_context: transport.TokenRefreshContext) -> None:
refreshed.append("yes")

interceptor = transport._AuthInterceptor(lambda: "******", refresh_callback=_refresh)
details = grpc.aio.ClientCallDetails(
method="/svc/method",
timeout=1,
metadata=None,
credentials=None,
wait_for_ready=False,
)

calls = 0

async def _continuation(_call_details: grpc.aio.ClientCallDetails, request: object) -> object:
nonlocal calls
calls += 1
if calls == 1:
return _FakeCall(error=_FakeRpcError(grpc.StatusCode.UNAUTHENTICATED, "expired"))
return _FakeCall(result=request)

with caplog.at_level(logging.INFO):
stream_call = await interceptor.intercept_unary_stream(_continuation, details, "req")

matching = [
record
for record in caplog.records
if record.getMessage() == "Retrying streaming RPC setup after UNAUTHENTICATED response"
]
assert matching
assert all(record.levelno == logging.INFO for record in matching)
assert await stream_call == "req" # type: ignore[misc]
assert refreshed == ["yes"]


@pytest.mark.asyncio
async def test_auth_interceptor_non_retry_paths() -> None:
interceptor = transport._AuthInterceptor(lambda: "Bearer abc")
Expand Down