Skip to content

Commit 6908a02

Browse files
aranditohswong3i
authored andcommitted
Track retry mode and gzip feature ids (boto#3481)
* Track gzip request compression feature * Track retry mode feature ids * Move retry feature tracking to client.py * Reorganize tests
1 parent 994a156 commit 6908a02

File tree

5 files changed

+73
-1
lines changed

5 files changed

+73
-1
lines changed

botocore/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from botocore.model import ServiceModel
4343
from botocore.paginate import Paginator
4444
from botocore.retries import adaptive, standard
45-
from botocore.useragent import UserAgentString
45+
from botocore.useragent import UserAgentString, register_feature_id
4646
from botocore.utils import (
4747
CachedProperty,
4848
EventbridgeSignerSetter,
@@ -246,6 +246,9 @@ def _register_retries(self, client):
246246
self._register_v2_adaptive_retries(client)
247247
elif retry_mode == 'legacy':
248248
self._register_legacy_retries(client)
249+
else:
250+
return
251+
register_feature_id(f'RETRY_MODE_{retry_mode.upper()}')
249252

250253
def _register_v2_standard_retries(self, client):
251254
max_attempts = client.meta.config.retries.get('total_max_attempts')

botocore/compress.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from gzip import compress as gzip_compress
2323

2424
from botocore.compat import urlencode
25+
from botocore.useragent import register_feature_id
2526
from botocore.utils import determine_content_length
2627

2728
logger = logging.getLogger(__name__)
@@ -88,6 +89,7 @@ def _get_body_size(body):
8889

8990

9091
def _gzip_compress_body(body):
92+
register_feature_id('GZIP_REQUEST_COMPRESSION')
9193
if isinstance(body, str):
9294
return gzip_compress(body.encode('utf-8'))
9395
elif isinstance(body, (bytes, bytearray)):

botocore/useragent.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@
5757
_USERAGENT_FEATURE_MAPPINGS = {
5858
'WAITER': 'B',
5959
'PAGINATOR': 'C',
60+
"RETRY_MODE_LEGACY": "D",
61+
"RETRY_MODE_STANDARD": "E",
62+
"RETRY_MODE_ADAPTIVE": "F",
6063
'S3_TRANSFER': 'G',
64+
'GZIP_REQUEST_COMPRESSION': 'L',
6165
'PROTOCOL_RPC_V2_CBOR': 'M',
6266
'ENDPOINT_OVERRIDE': 'N',
6367
'ACCOUNT_ID_MODE_PREFERRED': 'P',

tests/functional/test_compress.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
from botocore.compress import COMPRESSION_MAPPING
1919
from botocore.config import Config
2020
from tests import ALL_SERVICES, ClientHTTPStubber, patch_load_service_model
21+
from tests.functional.test_useragent import (
22+
get_captured_ua_strings,
23+
parse_registered_feature_ids,
24+
)
2125

2226
FAKE_MODEL = {
2327
"version": "2.0",
@@ -127,3 +131,24 @@ def test_compression(patched_session, monkeypatch):
127131
serialized_body = f"{additional_params}&{serialized_params}"
128132
actual_body = gzip.decompress(http_stubber.requests[0].body)
129133
assert serialized_body.encode('utf-8') == actual_body
134+
135+
136+
def test_user_agent_has_gzip_feature_id(patched_session, monkeypatch):
137+
patch_load_service_model(
138+
patched_session, monkeypatch, FAKE_MODEL, FAKE_RULESET
139+
)
140+
client = patched_session.create_client(
141+
"otherservice",
142+
region_name="us-west-2",
143+
config=Config(request_min_compression_size_bytes=100),
144+
)
145+
with ClientHTTPStubber(client, strict=True) as http_stubber:
146+
http_stubber.add_response(status=200, body=b"<response/>")
147+
params_list = [
148+
{"MockOpParam": f"MockOpParamValue{i}"} for i in range(1, 21)
149+
]
150+
# The mock operation registers `'GZIP_REQUEST_COMPRESSION': 'L'`
151+
client.mock_operation(MockOpParamList=params_list)
152+
ua_string = get_captured_ua_strings(http_stubber)[0]
153+
feature_list = parse_registered_feature_ids(ua_string)
154+
assert 'L' in feature_list

tests/functional/test_retry.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
from botocore.config import Config
1919
from botocore.exceptions import ClientError
2020
from tests import BaseSessionTest, ClientHTTPStubber, mock
21+
from tests.functional.test_useragent import (
22+
get_captured_ua_strings,
23+
parse_registered_feature_ids,
24+
)
2125

2226
RETRY_MODES = ('legacy', 'standard', 'adaptive')
2327

@@ -49,6 +53,18 @@ def assert_will_retry_n_times(
4953
yield
5054
self.assertEqual(len(http_stubber.requests), num_responses)
5155

56+
def _get_feature_id_lists_from_retries(self, client):
57+
with ClientHTTPStubber(client) as http_stubber:
58+
# Add two failed responses followed by a success
59+
http_stubber.add_response(status=502, body=b'{}')
60+
http_stubber.add_response(status=502, body=b'{}')
61+
http_stubber.add_response(status=200, body=b'{}')
62+
client.list_tables()
63+
ua_strings = get_captured_ua_strings(http_stubber)
64+
return [
65+
parse_registered_feature_ids(ua_string) for ua_string in ua_strings
66+
]
67+
5268

5369
class TestRetryHeader(BaseRetryTest):
5470
def _retry_headers_test_cases(self):
@@ -264,6 +280,12 @@ def test_can_clobber_max_attempts_on_session(self):
264280
with self.assert_will_retry_n_times(client, 0):
265281
client.list_repositories()
266282

283+
def test_user_agent_has_legacy_mode_feature_id(self):
284+
client = self.session.create_client('dynamodb', self.region)
285+
feature_lists = self._get_feature_id_lists_from_retries(client)
286+
# Confirm all requests register `'RETRY_MODE_LEGACY': 'D'`
287+
assert all('D' in feature_list for feature_list in feature_lists)
288+
267289

268290
class TestRetriesV2(BaseRetryTest):
269291
def create_client_with_retry_mode(
@@ -349,3 +371,19 @@ def test_can_exhaust_default_retry_quota(self):
349371
self.assertTrue(
350372
e.exception.response['ResponseMetadata'].get('RetryQuotaReached')
351373
)
374+
375+
def test_user_agent_has_standard_mode_feature_id(self):
376+
client = self.create_client_with_retry_mode(
377+
'dynamodb', retry_mode='standard'
378+
)
379+
feature_lists = self._get_feature_id_lists_from_retries(client)
380+
# Confirm all requests register `'RETRY_MODE_STANDARD': 'E'`
381+
assert all('E' in feature_list for feature_list in feature_lists)
382+
383+
def test_user_agent_has_adaptive_mode_feature_id(self):
384+
client = self.create_client_with_retry_mode(
385+
'dynamodb', retry_mode='adaptive'
386+
)
387+
feature_lists = self._get_feature_id_lists_from_retries(client)
388+
# Confirm all requests register `'RETRY_MODE_ADAPTIVE': 'F'`
389+
assert all('F' in feature_list for feature_list in feature_lists)

0 commit comments

Comments
 (0)