Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

Commit 19f6ddc

Browse files
committed
add tests
1 parent 851900d commit 19f6ddc

4 files changed

Lines changed: 226 additions & 14 deletions

File tree

google/auth/aio/transport/aiohttp.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
"""Transport adapter for Asynchronous HTTP Requests based on aiohttp.
16-
"""
15+
"""Transport adapter for Asynchronous HTTP Requests based on aiohttp."""
1716

1817
import asyncio
1918
import logging
@@ -29,8 +28,9 @@
2928

3029
if typing.TYPE_CHECKING:
3130
from aiohttp import ClientTimeout
31+
3232
else:
33-
ClientTimeout: typing.Type = Any
33+
ClientTimeout = Any
3434
try:
3535
from aiohttp import ClientTimeout
3636
except ImportError:
@@ -189,8 +189,12 @@ async def __call__(
189189
raise client_exc from caught_exc
190190

191191
except asyncio.TimeoutError as caught_exc:
192+
if isinstance(timeout, aiohttp.ClientTimeout):
193+
timeout_seconds = timeout.total
194+
else:
195+
timeout_seconds = timeout
192196
timeout_exc = exceptions.TimeoutError(
193-
f"Request timed out after {timeout} seconds."
197+
f"Request timed out after {timeout_seconds} seconds."
194198
)
195199
raise timeout_exc from caught_exc
196200

google/auth/aio/transport/sessions.py

Lines changed: 199 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@
3333

3434
if typing.TYPE_CHECKING:
3535
from aiohttp import ClientTimeout
36+
3637
else:
37-
ClientTimeout: typing.Type = Any
38+
ClientTimeout = Any
3839
try:
3940
from aiohttp import ClientTimeout
4041
except ImportError:
4142
ClientTimeout = None
4243

44+
4345
@asynccontextmanager
4446
async def timeout_guard(timeout):
4547
"""
@@ -214,8 +216,46 @@ async def get(
214216
total_attempts: Optional[int] = transport.DEFAULT_MAX_RETRY_ATTEMPTS,
215217
**kwargs,
216218
) -> transport.Response:
219+
"""
220+
Args:
221+
url (str): The URI to be requested.
222+
data (Optional[bytes]): The payload or body in HTTP request.
223+
headers (Optional[Mapping[str, str]]): Request headers.
224+
timeout (float, aiohttp.ClientTimeout):
225+
The amount of time in seconds to wait for the server response
226+
with each individual request.
227+
max_allowed_time (float):
228+
If the method runs longer than this, a ``Timeout`` exception is
229+
automatically raised. Unlike the ``timeout`` parameter, this
230+
value applies to the total method execution time, even if
231+
multiple requests are made under the hood.
232+
total_attempts (int):
233+
The total number of retry attempts.
234+
235+
Mind that it is not guaranteed that the timeout error is raised
236+
at ``max_allowed_time``. It might take longer, for example, if
237+
an underlying request takes a lot of time, but the request
238+
itself does not timeout, e.g. if a large file is being
239+
transmitted. The timeout error will be raised after such
240+
request completes.
241+
242+
Returns:
243+
google.auth.aio.transport.Response: The HTTP response.
244+
245+
Raises:
246+
google.auth.exceptions.TimeoutError: If the method does not complete within
247+
the configured `max_allowed_time` or the request exceeds the configured
248+
`timeout`.
249+
"""
217250
return await self.request(
218-
"GET", url, data, headers, max_allowed_time, timeout, total_attempts, **kwargs
251+
"GET",
252+
url,
253+
data,
254+
headers,
255+
max_allowed_time,
256+
timeout,
257+
total_attempts,
258+
**kwargs,
219259
)
220260

221261
@functools.wraps(request)
@@ -229,8 +269,46 @@ async def post(
229269
total_attempts: Optional[int] = transport.DEFAULT_MAX_RETRY_ATTEMPTS,
230270
**kwargs,
231271
) -> transport.Response:
272+
"""
273+
Args:
274+
url (str): The URI to be requested.
275+
data (Optional[bytes]): The payload or body in HTTP request.
276+
headers (Optional[Mapping[str, str]]): Request headers.
277+
timeout (float, aiohttp.ClientTimeout):
278+
The amount of time in seconds to wait for the server response
279+
with each individual request.
280+
max_allowed_time (float):
281+
If the method runs longer than this, a ``Timeout`` exception is
282+
automatically raised. Unlike the ``timeout`` parameter, this
283+
value applies to the total method execution time, even if
284+
multiple requests are made under the hood.
285+
total_attempts (int):
286+
The total number of retry attempts.
287+
288+
Mind that it is not guaranteed that the timeout error is raised
289+
at ``max_allowed_time``. It might take longer, for example, if
290+
an underlying request takes a lot of time, but the request
291+
itself does not timeout, e.g. if a large file is being
292+
transmitted. The timeout error will be raised after such
293+
request completes.
294+
295+
Returns:
296+
google.auth.aio.transport.Response: The HTTP response.
297+
298+
Raises:
299+
google.auth.exceptions.TimeoutError: If the method does not complete within
300+
the configured `max_allowed_time` or the request exceeds the configured
301+
`timeout`.
302+
"""
232303
return await self.request(
233-
"POST", url, data, headers, max_allowed_time, timeout, total_attempts, **kwargs
304+
"POST",
305+
url,
306+
data,
307+
headers,
308+
max_allowed_time,
309+
timeout,
310+
total_attempts,
311+
**kwargs,
234312
)
235313

236314
@functools.wraps(request)
@@ -244,8 +322,46 @@ async def put(
244322
total_attempts: Optional[int] = transport.DEFAULT_MAX_RETRY_ATTEMPTS,
245323
**kwargs,
246324
) -> transport.Response:
325+
"""
326+
Args:
327+
url (str): The URI to be requested.
328+
data (Optional[bytes]): The payload or body in HTTP request.
329+
headers (Optional[Mapping[str, str]]): Request headers.
330+
timeout (float, aiohttp.ClientTimeout):
331+
The amount of time in seconds to wait for the server response
332+
with each individual request.
333+
max_allowed_time (float):
334+
If the method runs longer than this, a ``Timeout`` exception is
335+
automatically raised. Unlike the ``timeout`` parameter, this
336+
value applies to the total method execution time, even if
337+
multiple requests are made under the hood.
338+
total_attempts (int):
339+
The total number of retry attempts.
340+
341+
Mind that it is not guaranteed that the timeout error is raised
342+
at ``max_allowed_time``. It might take longer, for example, if
343+
an underlying request takes a lot of time, but the request
344+
itself does not timeout, e.g. if a large file is being
345+
transmitted. The timeout error will be raised after such
346+
request completes.
347+
348+
Returns:
349+
google.auth.aio.transport.Response: The HTTP response.
350+
351+
Raises:
352+
google.auth.exceptions.TimeoutError: If the method does not complete within
353+
the configured `max_allowed_time` or the request exceeds the configured
354+
`timeout`.
355+
"""
247356
return await self.request(
248-
"PUT", url, data, headers, max_allowed_time, timeout, total_attempts, **kwargs
357+
"PUT",
358+
url,
359+
data,
360+
headers,
361+
max_allowed_time,
362+
timeout,
363+
total_attempts,
364+
**kwargs,
249365
)
250366

251367
@functools.wraps(request)
@@ -259,8 +375,46 @@ async def patch(
259375
total_attempts: Optional[int] = transport.DEFAULT_MAX_RETRY_ATTEMPTS,
260376
**kwargs,
261377
) -> transport.Response:
378+
"""
379+
Args:
380+
url (str): The URI to be requested.
381+
data (Optional[bytes]): The payload or body in HTTP request.
382+
headers (Optional[Mapping[str, str]]): Request headers.
383+
timeout (float, aiohttp.ClientTimeout):
384+
The amount of time in seconds to wait for the server response
385+
with each individual request.
386+
max_allowed_time (float):
387+
If the method runs longer than this, a ``Timeout`` exception is
388+
automatically raised. Unlike the ``timeout`` parameter, this
389+
value applies to the total method execution time, even if
390+
multiple requests are made under the hood.
391+
total_attempts (int):
392+
The total number of retry attempts.
393+
394+
Mind that it is not guaranteed that the timeout error is raised
395+
at ``max_allowed_time``. It might take longer, for example, if
396+
an underlying request takes a lot of time, but the request
397+
itself does not timeout, e.g. if a large file is being
398+
transmitted. The timeout error will be raised after such
399+
request completes.
400+
401+
Returns:
402+
google.auth.aio.transport.Response: The HTTP response.
403+
404+
Raises:
405+
google.auth.exceptions.TimeoutError: If the method does not complete within
406+
the configured `max_allowed_time` or the request exceeds the configured
407+
`timeout`.
408+
"""
262409
return await self.request(
263-
"PATCH", url, data, headers, max_allowed_time, timeout, total_attempts, **kwargs
410+
"PATCH",
411+
url,
412+
data,
413+
headers,
414+
max_allowed_time,
415+
timeout,
416+
total_attempts,
417+
**kwargs,
264418
)
265419

266420
@functools.wraps(request)
@@ -270,12 +424,50 @@ async def delete(
270424
data: Optional[bytes] = None,
271425
headers: Optional[Mapping[str, str]] = None,
272426
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
273-
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
427+
timeout: Union[float, ClientTimeout] = transport._DEFAULT_TIMEOUT_SECONDS,
274428
total_attempts: Optional[int] = transport.DEFAULT_MAX_RETRY_ATTEMPTS,
275429
**kwargs,
276430
) -> transport.Response:
431+
"""
432+
Args:
433+
url (str): The URI to be requested.
434+
data (Optional[bytes]): The payload or body in HTTP request.
435+
headers (Optional[Mapping[str, str]]): Request headers.
436+
timeout (float, aiohttp.ClientTimeout):
437+
The amount of time in seconds to wait for the server response
438+
with each individual request.
439+
max_allowed_time (float):
440+
If the method runs longer than this, a ``Timeout`` exception is
441+
automatically raised. Unlike the ``timeout`` parameter, this
442+
value applies to the total method execution time, even if
443+
multiple requests are made under the hood.
444+
total_attempts (int):
445+
The total number of retry attempts.
446+
447+
Mind that it is not guaranteed that the timeout error is raised
448+
at ``max_allowed_time``. It might take longer, for example, if
449+
an underlying request takes a lot of time, but the request
450+
itself does not timeout, e.g. if a large file is being
451+
transmitted. The timeout error will be raised after such
452+
request completes.
453+
454+
Returns:
455+
google.auth.aio.transport.Response: The HTTP response.
456+
457+
Raises:
458+
google.auth.exceptions.TimeoutError: If the method does not complete within
459+
the configured `max_allowed_time` or the request exceeds the configured
460+
`timeout`.
461+
"""
277462
return await self.request(
278-
"DELETE", url, data, headers, max_allowed_time, timeout, total_attempts, **kwargs
463+
"DELETE",
464+
url,
465+
data,
466+
headers,
467+
max_allowed_time,
468+
timeout,
469+
total_attempts,
470+
**kwargs,
279471
)
280472

281473
async def close(self) -> None:

tests/transport/aio/test_aiohttp.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from google.auth import exceptions
2323
import google.auth.aio.transport.aiohttp as auth_aiohttp
2424

25-
2625
try:
2726
import aiohttp # type: ignore
2827
except ImportError as caught_exc: # pragma: NO COVER
@@ -153,9 +152,11 @@ async def test_request_call_raises_timeout_error(self, aiohttp_request):
153152
m.get("http://example.com", exception=asyncio.TimeoutError)
154153

155154
with pytest.raises(exceptions.TimeoutError) as exc:
156-
await aiohttp_request("http://example.com")
155+
await aiohttp_request(
156+
"http://example.com", timeout=aiohttp.ClientTimeout(total=120)
157+
)
157158

158-
exc.match("Request timed out after 180 seconds.")
159+
exc.match("Request timed out after 120 seconds.")
159160

160161
async def test_request_call_raises_transport_error_for_closed_session(
161162
self, aiohttp_request

tests/transport/aio/test_sessions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ async def __call__(
5555
body=None,
5656
headers=None,
5757
timeout=_DEFAULT_TIMEOUT_SECONDS,
58+
total_attempts=DEFAULT_MAX_RETRY_ATTEMPTS,
5859
**kwargs,
5960
):
6061
self.call_count += 1
@@ -258,6 +259,20 @@ async def test_request_max_allowed_time_exceeded_error(self):
258259
with pytest.raises(TimeoutError):
259260
await authed_session.request("GET", self.TEST_URL, max_allowed_time=1)
260261

262+
@pytest.mark.parametrize("retry_status", DEFAULT_RETRYABLE_STATUS_CODES)
263+
@pytest.mark.asyncio
264+
async def test_request_total_attempt_1(self, retry_status):
265+
mocked_response = MockResponse(status_code=retry_status)
266+
auth_request = MockRequest(mocked_response)
267+
with patch("asyncio.sleep", return_value=None):
268+
authed_session = sessions.AsyncAuthorizedSession(
269+
self.credentials, auth_request
270+
)
271+
await authed_session.request(
272+
"GET", self.TEST_URL, max_allowed_time=float("inf"), total_attempts=1
273+
)
274+
assert auth_request.call_count == 1
275+
261276
@pytest.mark.parametrize("retry_status", DEFAULT_RETRYABLE_STATUS_CODES)
262277
@pytest.mark.asyncio
263278
async def test_request_max_retries(self, retry_status):

0 commit comments

Comments
 (0)