@@ -1093,89 +1093,132 @@ def add_credential_response(self, stubber):
10931093 stubber .add_response (body = json .dumps (response ).encode ('utf-8' ))
10941094
10951095
1096- class TestFeatureIdRegistered :
1097- @patch (
1098- "botocore.utils.InstanceMetadataFetcher.retrieve_iam_role_credentials"
1099- )
1100- @patch ("botocore.credentials.ContainerProvider.load" , return_value = None )
1101- @patch ("botocore.credentials.ConfigProvider.load" , return_value = None )
1102- @patch (
1103- "botocore.credentials.SharedCredentialProvider.load" , return_value = None
1104- )
1105- @patch ("botocore.credentials.EnvProvider.load" , return_value = None )
1106- def test_user_agent_has_imds_credentials_feature_id (
1107- self ,
1108- _unused_mock_env_load ,
1109- _unused_mock_shared_load ,
1110- _unused_mock_config_load ,
1111- _unused_mock_container_load ,
1112- mock_retrieve_iam_role_credentials ,
1113- patched_session ,
1114- ):
1115- fake_creds = {
1116- "role_name" : "FAKEROLE" ,
1117- "access_key" : "FAKEACCESSKEY" ,
1118- "secret_key" : "FAKESECRET" ,
1119- "token" : "FAKETOKEN" ,
1120- "expiry_time" : "2099-01-01T00:00:00Z" ,
1121- }
1122- mock_retrieve_iam_role_credentials .return_value = fake_creds
1123-
1124- client = patched_session .create_client ("s3" , region_name = "us-east-1" )
1125- with ClientHTTPStubber (client , strict = True ) as http_stubber :
1126- # We want to call this twice to assert that the feature id exists
1127- # for multiple calls with the same credentials
1128- http_stubber .add_response ()
1129- http_stubber .add_response ()
1130- client .list_buckets ()
1131- client .list_buckets ()
1132-
1133- ua_string = get_captured_ua_strings (http_stubber )
1134- feature_list_one = parse_registered_feature_ids (ua_string [0 ])
1135- feature_list_two = parse_registered_feature_ids (ua_string [1 ])
1136- assert '0' in feature_list_one and '0' in feature_list_two
1137-
1138- @patch ("botocore.credentials.ContainerMetadataFetcher.retrieve_full_uri" )
1139- @patch ("botocore.credentials.ConfigProvider.load" , return_value = None )
1140- @patch (
1141- "botocore.credentials.SharedCredentialProvider.load" , return_value = None
1142- )
1143- @patch ("botocore.credentials.EnvProvider.load" , return_value = None )
1144- def test_user_agent_has_http_credentials_feature_id (
1145- self ,
1146- _unused_mock_env_load ,
1147- _unused_mock_shared_load ,
1148- _unused_mock_config_load ,
1149- mock_load_http_credentials ,
1150- monkeypatch ,
1151- patched_session ,
1152- ):
1153- environ = {
1154- 'AWS_CONTAINER_CREDENTIALS_FULL_URI' : 'http://localhost/foo' ,
1155- 'AWS_CONTAINER_AUTHORIZATION_TOKEN' : 'Basic auth-token' ,
1156- }
1157- for var in environ :
1158- monkeypatch .setenv (var , environ [var ])
1159-
1160- fake_creds = {
1161- "AccessKeyId" : "FAKEACCESSKEY" ,
1162- "SecretAccessKey" : "FAKESECRET" ,
1163- "Token" : "FAKETOKEN" ,
1164- "Expiration" : "2099-01-01T00:00:00Z" ,
1165- "AccountId" : "01234567890" ,
1166- }
1167- mock_load_http_credentials .return_value = fake_creds
1168-
1169- client = patched_session .create_client ("s3" , region_name = "us-east-1" )
1170- with ClientHTTPStubber (client , strict = True ) as http_stubber :
1171- # We want to call this twice to assert that the feature id exists
1172- # for multiple calls with the same credentials
1173- http_stubber .add_response ()
1174- http_stubber .add_response ()
1175- client .list_buckets ()
1176- client .list_buckets ()
1177-
1178- ua_string = get_captured_ua_strings (http_stubber )
1179- feature_list_one = parse_registered_feature_ids (ua_string [0 ])
1180- feature_list_two = parse_registered_feature_ids (ua_string [1 ])
1181- assert 'z' in feature_list_one and 'z' in feature_list_two
1096+ @pytest .mark .parametrize (
1097+ "environ_vars,fake_credentials,patches,expected_feature_id" ,
1098+ [
1099+ # Test case 1: IMDS credentials
1100+ (
1101+ {},
1102+ {},
1103+ [
1104+ patch (
1105+ "botocore.utils.InstanceMetadataFetcher.retrieve_iam_role_credentials" ,
1106+ return_value = {
1107+ "role_name" : "FAKEROLE" ,
1108+ "access_key" : "FAKEACCESSKEY" ,
1109+ "secret_key" : "FAKESECRET" ,
1110+ "token" : "FAKETOKEN" ,
1111+ "expiry_time" : "2099-01-01T00:00:00Z" ,
1112+ },
1113+ ),
1114+ patch (
1115+ "botocore.credentials.ContainerProvider.load" ,
1116+ return_value = None ,
1117+ ),
1118+ patch (
1119+ "botocore.credentials.ConfigProvider.load" ,
1120+ return_value = None ,
1121+ ),
1122+ patch (
1123+ "botocore.credentials.SharedCredentialProvider.load" ,
1124+ return_value = None ,
1125+ ),
1126+ patch (
1127+ "botocore.credentials.EnvProvider.load" , return_value = None
1128+ ),
1129+ ],
1130+ '0' ,
1131+ ),
1132+ # Test case 2: HTTP credentials (container)
1133+ (
1134+ {
1135+ 'AWS_CONTAINER_CREDENTIALS_FULL_URI' : 'http://localhost/foo' ,
1136+ 'AWS_CONTAINER_AUTHORIZATION_TOKEN' : 'Basic auth-token' ,
1137+ },
1138+ {},
1139+ [
1140+ patch (
1141+ "botocore.credentials.ContainerMetadataFetcher.retrieve_full_uri" ,
1142+ return_value = {
1143+ "AccessKeyId" : "FAKEACCESSKEY" ,
1144+ "SecretAccessKey" : "FAKESECRET" ,
1145+ "Token" : "FAKETOKEN" ,
1146+ "Expiration" : "2099-01-01T00:00:00Z" ,
1147+ "AccountId" : "01234567890" ,
1148+ },
1149+ ),
1150+ patch (
1151+ "botocore.credentials.ConfigProvider.load" ,
1152+ return_value = None ,
1153+ ),
1154+ patch (
1155+ "botocore.credentials.SharedCredentialProvider.load" ,
1156+ return_value = None ,
1157+ ),
1158+ patch (
1159+ "botocore.credentials.EnvProvider.load" , return_value = None
1160+ ),
1161+ ],
1162+ 'z' ,
1163+ ),
1164+ # Test case 3: Credentials set via Environment variables
1165+ (
1166+ {
1167+ 'AWS_ACCESS_KEY_ID' : 'FAKEACCESSKEY' ,
1168+ 'AWS_SECRET_ACCESS_KEY' : 'FAKESECRET' ,
1169+ 'AWS_SESSION_TOKEN' : 'FAKETOKEN' ,
1170+ },
1171+ {},
1172+ [],
1173+ 'g' ,
1174+ ),
1175+ # Test case 4: Credentials set via code
1176+ (
1177+ {},
1178+ {
1179+ 'aws_access_key_id' : 'FAKEACCESSKEY' ,
1180+ 'aws_secret_access_key' : 'FAKESECRET' ,
1181+ 'aws_session_token' : 'FAKETOKEN' ,
1182+ },
1183+ [],
1184+ 'e' ,
1185+ ),
1186+ ],
1187+ )
1188+ def test_user_agent_feature_ids (
1189+ environ_vars ,
1190+ fake_credentials ,
1191+ patches ,
1192+ expected_feature_id ,
1193+ monkeypatch ,
1194+ patched_session ,
1195+ ):
1196+ for var , value in environ_vars .items ():
1197+ monkeypatch .setenv (var , value )
1198+
1199+ for patch_obj in patches :
1200+ patch_obj .start ()
1201+
1202+ try :
1203+ client = patched_session .create_client (
1204+ "s3" , region_name = "us-east-1" , ** fake_credentials
1205+ )
1206+ _assert_feature_ids_in_ua (client , expected_feature_id )
1207+ finally :
1208+ for patch_obj in patches :
1209+ patch_obj .stop ()
1210+
1211+
1212+ def _assert_feature_ids_in_ua (client , expected_feature_ids ):
1213+ """Helper to test feature IDs appear in user agent for multiple calls."""
1214+ with ClientHTTPStubber (client , strict = True ) as http_stubber :
1215+ http_stubber .add_response ()
1216+ http_stubber .add_response ()
1217+ client .list_buckets ()
1218+ client .list_buckets ()
1219+
1220+ ua_strings = get_captured_ua_strings (http_stubber )
1221+ for ua_string in ua_strings :
1222+ feature_list = parse_registered_feature_ids (ua_string )
1223+ for expected_id in expected_feature_ids :
1224+ assert expected_id in feature_list
0 commit comments