1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import pytest
from devtools_testutils import AzureRecordedTestCase, ResponseCallback
from devtools_testutils.aio import recorded_by_proxy_async
from azure.core.exceptions import (
HttpResponseError,
ResourceExistsError,
AzureError,
)
from azure.core.pipeline.policies import RetryMode
from azure.core.pipeline.transport import AioHttpTransport
from azure.data.tables.aio import TableServiceClient
from _shared.asynctestcase import AsyncTableTestCase
from async_preparers import tables_decorator_async
class RetryAioHttpTransport(AioHttpTransport):
"""Transport to test retry"""
def __init__(self, *args, **kwargs):
super(RetryAioHttpTransport, self).__init__(*args, **kwargs)
self.count = 0
async def send(self, request, **kwargs):
self.count += 1
response = await super(RetryAioHttpTransport, self).send(request, **kwargs)
return response
# --Test Class -----------------------------------------------------------------
class TestStorageRetryAsync(AzureRecordedTestCase, AsyncTableTestCase):
async def _set_up(
self, tables_storage_account_name, tables_primary_storage_account_key, url="table", default_table=True, **kwargs
):
self.table_name = self.get_resource_name("uttable")
self.ts = TableServiceClient(
self.account_url(tables_storage_account_name, url), credential=tables_primary_storage_account_key, **kwargs
)
self.table = self.ts.get_table_client(self.table_name)
if self.is_live and default_table:
try:
await self.ts.create_table(self.table_name)
except ResourceExistsError:
pass
self.query_tables = []
# --Test Cases --------------------------------------------
@tables_decorator_async
@recorded_by_proxy_async
async def test_retry_on_server_error_async(self, tables_storage_account_name, tables_primary_storage_account_key):
await self._set_up(tables_storage_account_name, tables_primary_storage_account_key, default_table=False)
try:
callback = ResponseCallback(status=201, new_status=500).override_status
new_table_name = self.get_resource_name("uttable")
# The initial create will return 201, but we overwrite it with 500 and retry.
# The retry will then get a 409 conflict.
with pytest.raises(ResourceExistsError):
await self.ts.create_table(new_table_name, raw_response_hook=callback)
finally:
await self.ts.delete_table(new_table_name)
await self._tear_down()
@tables_decorator_async
@recorded_by_proxy_async
async def test_retry_on_timeout_async(self, tables_storage_account_name, tables_primary_storage_account_key):
await self._set_up(
tables_storage_account_name,
tables_primary_storage_account_key,
default_table=False,
retry_mode=RetryMode.Exponential,
retry_backoff_factor=1,
)
callback = ResponseCallback(status=200, new_status=408).override_first_status
try:
# The initial create will return 201, but we overwrite it with 408 and retry.
# The retry will then succeed.
await self.ts.get_service_properties(raw_response_hook=callback)
finally:
await self._tear_down()
@pytest.mark.live_test_only
@tables_decorator_async
async def test_retry_on_socket_timeout_async(self, tables_storage_account_name, tables_primary_storage_account_key):
retry_transport = RetryAioHttpTransport(connection_timeout=11, read_timeout=0.000000000001)
await self._set_up(
tables_storage_account_name,
tables_primary_storage_account_key,
retry_mode=RetryMode.Fixed,
retry_backoff_factor=1,
transport=retry_transport,
default_table=False,
)
with pytest.raises(AzureError) as error:
await self.ts.get_service_properties()
# 3 retries + 1 original == 4
assert retry_transport.count == 4
# This call should succeed on the server side, but fail on the client side due to socket timeout
assert "Timeout on reading" in str(error.value), "Expected socket timeout but got different exception."
@tables_decorator_async
@recorded_by_proxy_async
async def test_no_retry_async(self, tables_storage_account_name, tables_primary_storage_account_key):
await self._set_up(
tables_storage_account_name, tables_primary_storage_account_key, retry_total=0, default_table=False
)
new_table_name = self.get_resource_name("uttable")
# Force the create call to error with a 500
callback = ResponseCallback(status=201, new_status=500).override_status
try:
with pytest.raises(HttpResponseError) as error:
await self.ts.create_table(new_table_name, raw_response_hook=callback)
assert error.value.response.status_code == 500
assert error.value.reason == "Created"
finally:
await self.ts.delete_table(new_table_name)
await self._tear_down()
# ------------------------------------------------------------------------------
|