diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/assets.json b/sdk/appconfiguration/azure-appconfiguration-provider/assets.json index 9b6a07887233..fb9ecf518942 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/assets.json +++ b/sdk/appconfiguration/azure-appconfiguration-provider/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/appconfiguration/azure-appconfiguration-provider", - "Tag": "python/appconfiguration/azure-appconfiguration-provider_d81e6a8e3c" + "Tag": "python/appconfiguration/azure-appconfiguration-provider_d4cf1efd37" } diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider.py index 749ed9d929ba..530784670cae 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider.py @@ -11,7 +11,7 @@ from testcase import has_feature_flag from asynctestcase import AppConfigTestCase from test_constants import ( - APPCONFIGURATION_CONNECTION_STRING, + APPCONFIGURATION_ENDPOINT_STRING, APPCONFIGURATION_KEYVAULT_SECRET_URL, FEATURE_MANAGEMENT_KEY, ) @@ -23,22 +23,28 @@ AppConfigProviderPreparer = functools.partial( EnvironmentVariableLoader, "appconfiguration", - appconfiguration_connection_string=APPCONFIGURATION_CONNECTION_STRING, + appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, appconfiguration_keyvault_secret_url=APPCONFIGURATION_KEYVAULT_SECRET_URL, ) +AppConfigProviderNoSecretPreparer = functools.partial( + EnvironmentVariableLoader, + "appconfiguration", + appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, +) + class TestAppConfigurationProvider(AppConfigTestCase): # method: provider_creation @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_creation(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + async def test_provider_creation(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, ) as client: - assert client["message"] == "hi" + assert client.get("message") == "hi" assert client["my_json"]["key"] == "value" assert ".appconfig.featureflag/Alpha" not in client assert FEATURE_MANAGEMENT_KEY in client @@ -47,12 +53,10 @@ async def test_provider_creation(self, appconfiguration_connection_string, appco # method: provider_trim_prefixes @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_trim_prefixes( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url - ): + async def test_provider_trim_prefixes(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): trimmed = {"test."} async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, trim_prefixes=trimmed, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, @@ -67,10 +71,10 @@ async def test_provider_trim_prefixes( # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_selectors(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + async def test_provider_selectors(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="message*", label_filter="dev")} async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, ) as client: @@ -82,11 +86,11 @@ async def test_provider_selectors(self, appconfiguration_connection_string, appc @AppConfigProviderPreparer() @recorded_by_proxy_async async def test_provider_key_vault_reference( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): selects = {SettingSelector(key_filter="*", label_filter="prod")} async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, ) as client: @@ -95,10 +99,10 @@ async def test_provider_key_vault_reference( # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_secret_resolver(self, appconfiguration_connection_string): + async def test_provider_secret_resolver(self, appconfiguration_endpoint_string): selects = {SettingSelector(key_filter="*", label_filter="prod")} async with await self.create_client( - connection_string=appconfiguration_connection_string, selects=selects, secret_resolver=secret_resolver + endpoint=appconfiguration_endpoint_string, selects=selects, secret_resolver=secret_resolver ) as client: assert client["secret"] == "Resolver Value" @@ -106,12 +110,12 @@ async def test_provider_secret_resolver(self, appconfiguration_connection_string @AppConfigProviderPreparer() @recorded_by_proxy_async async def test_provider_key_vault_reference_options( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): selects = {SettingSelector(key_filter="*", label_filter="prod")} key_vault_options = AzureAppConfigurationKeyVaultOptions() async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, key_vault_options=key_vault_options, @@ -121,101 +125,85 @@ async def test_provider_key_vault_reference_options( # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_secret_resolver_options(self, appconfiguration_connection_string): + async def test_provider_secret_resolver_options(self, appconfiguration_endpoint_string): selects = {SettingSelector(key_filter="*", label_filter="prod")} key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_resolver=secret_resolver) async with await self.create_client( - connection_string=appconfiguration_connection_string, selects=selects, key_vault_options=key_vault_options + endpoint=appconfiguration_endpoint_string, selects=selects, key_vault_options=key_vault_options ) as client: assert client["secret"] == "Resolver Value" - @pytest.mark.asyncio - async def test_process_key_value_content_type(self): - with patch( - "azure.appconfiguration.provider.aio._azureappconfigurationproviderasync.ConfigurationClientManager" - ) as MockClientManager: - # Mock the client manager and its methods - mock_client_manager = MockClientManager.return_value - mock_client_manager.load_configuration_settings.return_value = [ - {"key": "test_key", "value": '{"key": "value"}', "content_type": "application/json"} - ] - - # Create the provider with the mocked client manager - provider = await _buildprovider("=mock_connection_string;;", None, None) - provider._replica_client_manager = mock_client_manager - - # Call the method to process key-value pairs - processed_value = await provider._process_key_value( - MagicMock(content_type="application/json", value='{"key": "value"}') - ) - - # Assert the processed value is as expected - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == False - assert provider._tracing_context.uses_aicc_configuration == False - - mock_client_manager.load_configuration_settings.return_value = [ - { - "key": "test_key", - "value": '{"key": "value"}', - "content_type": "https://azconfig.io/mime-profiles/ai/", - } - ] - processed_value = await provider._process_key_value( - MagicMock( - content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/"', - value='{"key": "value"}', - ) - ) - - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == True - assert provider._tracing_context.uses_aicc_configuration == False - - mock_client_manager.load_configuration_settings.return_value = [ - { - "key": "test_key", - "value": '{"key": "value"}', - "content_type": 'application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', - } - ] - processed_value = await provider._process_key_value( - MagicMock( - content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', - value='{"key": "value"}', - ) - ) - - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == True - assert provider._tracing_context.uses_aicc_configuration == True - @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_provider_tag_filters(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + async def test_provider_tag_filters(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="*", tag_filters=["a=b"])} async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, feature_flag_enabled=True, feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, keyvault_secret_url=appconfiguration_keyvault_secret_url, ) as client: assert "tagged_config" in client + assert "two_tagged" in client + assert "only_second_tag" not in client + assert FEATURE_MANAGEMENT_KEY in client + assert has_feature_flag(client, "TaggedFeatureFlag") + assert "message" not in client + + @AppConfigProviderPreparer() + @recorded_by_proxy_async + async def test_provider_two_tag_filters( + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url + ): + selects = {SettingSelector(key_filter="*", tag_filters=["a=b", "second=tag"])} + async with await self.create_client( + endpoint=appconfiguration_endpoint_string, + selects=selects, + feature_flag_enabled=True, + feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, + keyvault_secret_url=appconfiguration_keyvault_secret_url, + ) as client: + assert "tagged_config" not in client + assert "two_tagged" in client + assert "only_second_tag" not in client assert FEATURE_MANAGEMENT_KEY in client assert has_feature_flag(client, "TaggedFeatureFlag") assert "message" not in client + @AppConfigProviderNoSecretPreparer() + @recorded_by_proxy_async + async def test_provider_special_chars_tag_filters(self, appconfiguration_endpoint_string): + selects = {SettingSelector(key_filter="*", tag_filters=["Special:Tag=Value:With:Colons"])} + async with await self.create_client( + endpoint=appconfiguration_endpoint_string, + selects=selects, + ) as client: + assert "tagged_config" not in client + assert "two_tagged" not in client + assert "only_second_tag" not in client + assert "complex_tag" in client + + selects = {SettingSelector(key_filter="*", tag_filters=["Tag@With@At=Value@With@At"])} + async with await self.create_client( + endpoint=appconfiguration_endpoint_string, + selects=selects, + ) as client: + assert "tagged_config" not in client + assert "two_tagged" not in client + assert "only_second_tag" not in client + assert "complex_tag" in client + # method: load @AppConfigProviderPreparer() @recorded_by_proxy_async - async def test_configuration_mapper(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + async def test_configuration_mapper(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): async def test_mapper(setting): if setting.key == "message": setting.value = "mapped" async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, configuration_mapper=test_mapper, ) as client: @@ -226,14 +214,14 @@ async def test_mapper(setting): @AppConfigProviderPreparer() @recorded_by_proxy_async async def test_configuration_mapper_with_trimming( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): async def test_mapper(setting): if setting.key == "message": setting.value = "mapped" async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, configuration_mapper=test_mapper, trim_prefixes=["refresh_"], @@ -247,14 +235,14 @@ async def test_mapper(setting): @AppConfigProviderPreparer() @recorded_by_proxy_async async def test_configuration_mapper_with_feature_flags( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): async def test_mapper(setting): if setting.key == ".appconfig.featureflag/Alpha": setting.content_type = "application/json" async with await self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, configuration_mapper=test_mapper, @@ -264,6 +252,67 @@ async def test_mapper(setting): assert "Alpha" not in client assert client["feature_management"]["feature_flags"][0]["id"] == "Alpha" + @pytest.mark.asyncio + async def test_process_key_value_content_type(self): + with patch( + "azure.appconfiguration.provider.aio._azureappconfigurationproviderasync.ConfigurationClientManager" + ) as MockClientManager: + # Mock the client manager and its methods + mock_client_manager = MockClientManager.return_value + mock_client_manager.load_configuration_settings.return_value = [ + {"key": "test_key", "value": '{"key": "value"}', "content_type": "application/json"} + ] + + # Create the provider with the mocked client manager + provider = await _buildprovider("=mock_connection_string;;", None, None) + provider._replica_client_manager = mock_client_manager + + # Call the method to process key-value pairs + processed_value = await provider._process_key_value( + MagicMock(content_type="application/json", value='{"key": "value"}') + ) + + # Assert the processed value is as expected + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == False + assert provider._tracing_context.uses_aicc_configuration == False + + mock_client_manager.load_configuration_settings.return_value = [ + { + "key": "test_key", + "value": '{"key": "value"}', + "content_type": "https://azconfig.io/mime-profiles/ai/", + } + ] + processed_value = await provider._process_key_value( + MagicMock( + content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/"', + value='{"key": "value"}', + ) + ) + + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == True + assert provider._tracing_context.uses_aicc_configuration == False + + mock_client_manager.load_configuration_settings.return_value = [ + { + "key": "test_key", + "value": '{"key": "value"}', + "content_type": 'application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', + } + ] + processed_value = await provider._process_key_value( + MagicMock( + content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', + value='{"key": "value"}', + ) + ) + + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == True + assert provider._tracing_context.uses_aicc_configuration == True + async def secret_resolver(_): return "Resolver Value" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider_aad.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider_aad.py deleted file mode 100644 index 85646addbb05..000000000000 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/aio/test_async_provider_aad.py +++ /dev/null @@ -1,142 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools -from devtools_testutils import EnvironmentVariableLoader -from devtools_testutils.aio import recorded_by_proxy_async -from testcase import has_feature_flag -from asynctestcase import AppConfigTestCase -from test_constants import ( - APPCONFIGURATION_ENDPOINT_STRING, - APPCONFIGURATION_KEYVAULT_SECRET_URL, - FEATURE_MANAGEMENT_KEY, -) -from azure.appconfiguration.provider import SettingSelector, AzureAppConfigurationKeyVaultOptions - -AppConfigProviderPreparer = functools.partial( - EnvironmentVariableLoader, - "appconfiguration", - appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, - appconfiguration_keyvault_secret_url=APPCONFIGURATION_KEYVAULT_SECRET_URL, -) - - -class TestAppConfigurationProvider(AppConfigTestCase): - # method: provider_creation_aad - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_creation_aad(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - feature_flag_enabled=True, - ) as client: - assert client.get("message") == "hi" - assert client["my_json"]["key"] == "value" - assert ".appconfig.featureflag/Alpha" not in client - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "Alpha") - - # method: provider_trim_prefixes - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_trim_prefixes(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - trimmed = {"test."} - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - trim_prefixes=trimmed, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - feature_flag_enabled=True, - ) as client: - assert client["message"] == "hi" - assert client["my_json"]["key"] == "value" - assert client["trimmed"] == "key" - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "Alpha") - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_selectors(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - selects = {SettingSelector(key_filter="message*", label_filter="dev")} - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) as client: - assert client["message"] == "test" - assert "test.trimmed" not in client - assert FEATURE_MANAGEMENT_KEY not in client - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_key_vault_reference( - self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url - ): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) as client: - assert client["secret"] == "Very secret value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_secret_resolver(self, appconfiguration_endpoint_string): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, selects=selects, secret_resolver=secret_resolver - ) as client: - assert client["secret"] == "Resolver Value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_key_vault_reference_options( - self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url - ): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - key_vault_options = AzureAppConfigurationKeyVaultOptions() - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - key_vault_options=key_vault_options, - ) as client: - assert client["secret"] == "Very secret value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_secret_resolver_options(self, appconfiguration_endpoint_string): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_resolver=secret_resolver) - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, selects=selects, key_vault_options=key_vault_options - ) as client: - assert client["secret"] == "Resolver Value" - - @AppConfigProviderPreparer() - @recorded_by_proxy_async - async def test_provider_tag_filters(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - selects = {SettingSelector(key_filter="*", tag_filters=["a=b"])} - async with await self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - feature_flag_enabled=True, - feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) as client: - assert "tagged_config" in client - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "TaggedFeatureFlag") - assert "message" not in client - - -async def secret_resolver(_): - return "Resolver Value" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/conftest.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/conftest.py index cfe5f86e84fd..21fa582e4734 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/conftest.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/conftest.py @@ -8,10 +8,10 @@ add_remove_header_sanitizer, add_uri_string_sanitizer, is_live, + get_credential, ) import pytest from azure.appconfiguration import AzureAppConfigurationClient -from azure.identity import DefaultAzureCredential from testcase import setup_configs, cleanup_test_resources # autouse=True will trigger this fixture on each pytest run, even if it's not explicitly used by a test method @@ -32,10 +32,10 @@ def setup_app_config_keys(): yield return - credential = DefaultAzureCredential() + credential = get_credential() client = AzureAppConfigurationClient(endpoint, credential) - keyvault_secret_url = os.environ.get("APPCONFIGURATION_KEY_VAULT_REFERENCE") - keyvault_secret_url2 = os.environ.get("APPCONFIGURATION_KEY_VAULT_REFERENCE2") + keyvault_secret_url = os.environ.get("APPCONFIGURATION_KEYVAULT_SECRET_URL") + keyvault_secret_url2 = os.environ.get("APPCONFIGURATION_KEYVAULT_SECRET_URL2") snap_name, ff_snap_name = setup_configs(client, keyvault_secret_url, keyvault_secret_url2) snapshot_names["snapshot"] = snap_name @@ -49,18 +49,25 @@ def setup_app_config_keys(): @pytest.fixture(scope="session", autouse=True) def add_sanitizers(test_proxy): add_general_regex_sanitizer( - value="https://sanitized.azconfig.io", - regex=os.environ.get("APPCONFIGURATION_ENDPOINT_STRING", "https://sanitized.azconfig.io"), + value="https://Sanitized.azconfig.io", + regex=os.environ.get("APPCONFIGURATION_ENDPOINT_STRING", "https://Sanitized.azconfig.io"), ) add_general_regex_sanitizer( - value="sanitized", - regex=os.environ.get("APPCONFIGURATION_CONNECTION_STRING", "https://sanitized.azconfig.io"), + value="Sanitized", + regex=os.environ.get("APPCONFIGURATION_CONNECTION_STRING", "https://Sanitized.azconfig.io"), ) add_uri_string_sanitizer() + # Register the longer URL2 sanitizer FIRST to prevent URL1's sanitizer from partially matching within URL2 add_general_string_sanitizer( - value="https://sanitized.vault.azure.net/secrets/fake-secret/", + value="https://Sanitized.vault.azure.net/secrets/TestSecret2/", target=os.environ.get( - "APPCONFIGURATION_KEY_VAULT_REFERENCE", "https://sanitized.vault.azure.net/secrets/fake-secret/" + "APPCONFIGURATION_KEYVAULT_SECRET_URL2", "https://Sanitized.vault.azure.net/secrets/TestSecret2/" + ), + ) + add_general_string_sanitizer( + value="https://Sanitized.vault.azure.net/secrets/TestSecret/", + target=os.environ.get( + "APPCONFIGURATION_KEYVAULT_SECRET_URL", "https://Sanitized.vault.azure.net/secrets/TestSecret/" ), ) add_remove_header_sanitizer(headers="Correlation-Context") diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_constants.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_constants.py index 54c34bb43abb..7b5ede6f8aaf 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_constants.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_constants.py @@ -2,10 +2,10 @@ FEATURE_FLAG_KEY = "feature_flags" APPCONFIGURATION_CONNECTION_STRING = ( - "Endpoint=https://sanitized.azconfig.io;" + "Endpoint=https://Sanitized.azconfig.io;" "Id=0-l4-s0:h5htBaY5Z1LwFz50bIQv;" "Secret=lamefakesecretlamefakesecretlamefakesecrett=" # cspell: disable-line ) -APPCONFIGURATION_ENDPOINT_STRING = "https://sanitized.azconfig.io" -APPCONFIGURATION_KEYVAULT_SECRET_URL = "https://sanitized.vault.azure.net/secrets/fake-secret/" -APPCONFIGURATION_KEYVAULT_SECRET_URL2 = "https://sanitized.vault.azure.net/secrets/fake-secret2/" +APPCONFIGURATION_ENDPOINT_STRING = "https://Sanitized.azconfig.io" +APPCONFIGURATION_KEYVAULT_SECRET_URL = "https://Sanitized.vault.azure.net/secrets/TestSecret/" +APPCONFIGURATION_KEYVAULT_SECRET_URL2 = "https://Sanitized.vault.azure.net/secrets/TestSecret2/" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py index 6e481c172e78..066404773bf9 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py @@ -4,12 +4,12 @@ # license information. # -------------------------------------------------------------------------- import datetime -from unittest.mock import MagicMock, patch import functools +from unittest.mock import MagicMock, patch from devtools_testutils import EnvironmentVariableLoader, recorded_by_proxy from testcase import AppConfigTestCase, has_feature_flag from test_constants import ( - APPCONFIGURATION_CONNECTION_STRING, + APPCONFIGURATION_ENDPOINT_STRING, APPCONFIGURATION_KEYVAULT_SECRET_URL, FEATURE_MANAGEMENT_KEY, ) @@ -19,18 +19,17 @@ ) from azure.appconfiguration.provider._azureappconfigurationprovider import _buildprovider - AppConfigProviderPreparer = functools.partial( EnvironmentVariableLoader, "appconfiguration", - appconfiguration_connection_string=APPCONFIGURATION_CONNECTION_STRING, + appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, appconfiguration_keyvault_secret_url=APPCONFIGURATION_KEYVAULT_SECRET_URL, ) AppConfigProviderNoSecretPreparer = functools.partial( EnvironmentVariableLoader, "appconfiguration", - appconfiguration_connection_string=APPCONFIGURATION_CONNECTION_STRING, + appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, ) @@ -42,9 +41,9 @@ class TestAppConfigurationProvider(AppConfigTestCase): # method: provider_creation @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_creation(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_provider_creation(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, ) @@ -57,10 +56,10 @@ def test_provider_creation(self, appconfiguration_connection_string, appconfigur # method: provider_trim_prefixes @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_trim_prefixes(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_provider_trim_prefixes(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): trimmed = {"test."} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, trim_prefixes=trimmed, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, @@ -75,10 +74,10 @@ def test_provider_trim_prefixes(self, appconfiguration_connection_string, appcon # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_selectors(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_provider_selectors(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="message*", label_filter="dev")} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, ) @@ -89,12 +88,10 @@ def test_provider_selectors(self, appconfiguration_connection_string, appconfigu # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_key_vault_reference( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url - ): + def test_provider_key_vault_reference(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="*", label_filter="prod")} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, ) @@ -103,10 +100,10 @@ def test_provider_key_vault_reference( # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_secret_resolver(self, appconfiguration_connection_string): + def test_provider_secret_resolver(self, appconfiguration_endpoint_string): selects = {SettingSelector(key_filter="*", label_filter="prod")} client = self.create_client( - connection_string=appconfiguration_connection_string, selects=selects, secret_resolver=secret_resolver + endpoint=appconfiguration_endpoint_string, selects=selects, secret_resolver=secret_resolver ) assert client["secret"] == "Resolver Value" @@ -114,12 +111,12 @@ def test_provider_secret_resolver(self, appconfiguration_connection_string): @AppConfigProviderPreparer() @recorded_by_proxy def test_provider_key_vault_reference_options( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): selects = {SettingSelector(key_filter="*", label_filter="prod")} key_vault_options = AzureAppConfigurationKeyVaultOptions() client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, keyvault_secret_url=appconfiguration_keyvault_secret_url, key_vault_options=key_vault_options, @@ -129,92 +126,20 @@ def test_provider_key_vault_reference_options( # method: provider_selectors @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_secret_resolver_options(self, appconfiguration_connection_string): + def test_provider_secret_resolver_options(self, appconfiguration_endpoint_string): selects = {SettingSelector(key_filter="*", label_filter="prod")} key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_resolver=secret_resolver) client = self.create_client( - connection_string=appconfiguration_connection_string, selects=selects, key_vault_options=key_vault_options + endpoint=appconfiguration_endpoint_string, selects=selects, key_vault_options=key_vault_options ) assert client["secret"] == "Resolver Value" - # method: delay_failure - @patch("time.sleep", side_effect=sleep) - def test_delay_failure(self, mock_sleep): - start_time = datetime.datetime.now() - delay_failure(start_time) - assert mock_sleep.call_count == 1 - - mock_sleep.reset_mock() - start_time = datetime.datetime.now() - datetime.timedelta(seconds=10) - delay_failure(start_time) - mock_sleep.assert_not_called() - - def test_process_key_value_content_type(self): - with patch( - "azure.appconfiguration.provider._azureappconfigurationprovider.ConfigurationClientManager" - ) as MockClientManager: - # Mock the client manager and its methods - mock_client_manager = MockClientManager.return_value - mock_client_manager.load_configuration_settings.return_value = [ - {"key": "test_key", "value": '{"key": "value"}', "content_type": "application/json"} - ] - - # Create the provider with the mocked client manager - provider = _buildprovider("=mock_connection_string;;", None, None) - provider._replica_client_manager = mock_client_manager - - # Call the method to process key-value pairs - processed_value = provider._process_key_value( - MagicMock(content_type="application/json", value='{"key": "value"}') - ) - - # Assert the processed value is as expected - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == False - assert provider._tracing_context.uses_aicc_configuration == False - - mock_client_manager.load_configuration_settings.return_value = [ - { - "key": "test_key", - "value": '{"key": "value"}', - "content_type": "https://azconfig.io/mime-profiles/ai/", - } - ] - processed_value = provider._process_key_value( - MagicMock( - content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/"', - value='{"key": "value"}', - ) - ) - - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == True - assert provider._tracing_context.uses_aicc_configuration == False - - mock_client_manager.load_configuration_settings.return_value = [ - { - "key": "test_key", - "value": '{"key": "value"}', - "content_type": 'application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', - } - ] - processed_value = provider._process_key_value( - MagicMock( - content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', - value='{"key": "value"}', - ) - ) - - assert processed_value == {"key": "value"} - assert provider._tracing_context.uses_ai_configuration == True - assert provider._tracing_context.uses_aicc_configuration == True - @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_tag_filters(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_provider_tag_filters(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="*", tag_filters=["a=b"])} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, feature_flag_enabled=True, feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, @@ -229,10 +154,10 @@ def test_provider_tag_filters(self, appconfiguration_connection_string, appconfi @AppConfigProviderPreparer() @recorded_by_proxy - def test_provider_two_tag_filters(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_provider_two_tag_filters(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): selects = {SettingSelector(key_filter="*", tag_filters=["a=b", "second=tag"])} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, feature_flag_enabled=True, feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, @@ -247,10 +172,10 @@ def test_provider_two_tag_filters(self, appconfiguration_connection_string, appc @AppConfigProviderNoSecretPreparer() @recorded_by_proxy - def test_provider_special_chars_tag_filters(self, appconfiguration_connection_string): + def test_provider_special_chars_tag_filters(self, appconfiguration_endpoint_string): selects = {SettingSelector(key_filter="*", tag_filters=["Special:Tag=Value:With:Colons"])} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, ) assert "tagged_config" not in client @@ -260,7 +185,7 @@ def test_provider_special_chars_tag_filters(self, appconfiguration_connection_st selects = {SettingSelector(key_filter="*", tag_filters=["Tag@With@At=Value@With@At"])} client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, selects=selects, ) assert "tagged_config" not in client @@ -271,13 +196,13 @@ def test_provider_special_chars_tag_filters(self, appconfiguration_connection_st # method: load @AppConfigProviderPreparer() @recorded_by_proxy - def test_configuration_mapper(self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url): + def test_configuration_mapper(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): def test_mapper(setting): if setting.key == "message": setting.value = "mapped" client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, configuration_mapper=test_mapper, @@ -289,14 +214,14 @@ def test_mapper(setting): @AppConfigProviderPreparer() @recorded_by_proxy def test_configuration_mapper_with_trimming( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): def test_mapper(setting): if setting.key == "message": setting.value = "mapped" client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, configuration_mapper=test_mapper, trim_prefixes=["refresh_"], @@ -311,14 +236,14 @@ def test_mapper(setting): @AppConfigProviderPreparer() @recorded_by_proxy def test_configuration_mapper_with_feature_flags( - self, appconfiguration_connection_string, appconfiguration_keyvault_secret_url + self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url ): def test_mapper(setting): if setting.key == ".appconfig.featureflag/Alpha": setting.content_type = "application/json" client = self.create_client( - connection_string=appconfiguration_connection_string, + endpoint=appconfiguration_endpoint_string, keyvault_secret_url=appconfiguration_keyvault_secret_url, feature_flag_enabled=True, configuration_mapper=test_mapper, @@ -328,6 +253,78 @@ def test_mapper(setting): assert "Alpha" not in client assert client["feature_management"]["feature_flags"][0]["id"] == "Alpha" + # method: delay_failure + @patch("time.sleep", side_effect=sleep) + def test_delay_failure(self, mock_sleep): + start_time = datetime.datetime.now() + delay_failure(start_time) + assert mock_sleep.call_count == 1 + + mock_sleep.reset_mock() + start_time = datetime.datetime.now() - datetime.timedelta(seconds=10) + delay_failure(start_time) + mock_sleep.assert_not_called() + + def test_process_key_value_content_type(self): + with patch( + "azure.appconfiguration.provider._azureappconfigurationprovider.ConfigurationClientManager" + ) as MockClientManager: + # Mock the client manager and its methods + mock_client_manager = MockClientManager.return_value + mock_client_manager.load_configuration_settings.return_value = [ + {"key": "test_key", "value": '{"key": "value"}', "content_type": "application/json"} + ] + + # Create the provider with the mocked client manager + provider = _buildprovider("=mock_connection_string;;", None, None) + provider._replica_client_manager = mock_client_manager + + # Call the method to process key-value pairs + processed_value = provider._process_key_value( + MagicMock(content_type="application/json", value='{"key": "value"}') + ) + + # Assert the processed value is as expected + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == False + assert provider._tracing_context.uses_aicc_configuration == False + + mock_client_manager.load_configuration_settings.return_value = [ + { + "key": "test_key", + "value": '{"key": "value"}', + "content_type": "https://azconfig.io/mime-profiles/ai/", + } + ] + processed_value = provider._process_key_value( + MagicMock( + content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/"', + value='{"key": "value"}', + ) + ) + + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == True + assert provider._tracing_context.uses_aicc_configuration == False + + mock_client_manager.load_configuration_settings.return_value = [ + { + "key": "test_key", + "value": '{"key": "value"}', + "content_type": 'application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', + } + ] + processed_value = provider._process_key_value( + MagicMock( + content_type='application/json; profile="https://azconfig.io/mime-profiles/ai/chat-completion"', + value='{"key": "value"}', + ) + ) + + assert processed_value == {"key": "value"} + assert provider._tracing_context.uses_ai_configuration == True + assert provider._tracing_context.uses_aicc_configuration == True + def secret_resolver(_): return "Resolver Value" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py deleted file mode 100644 index dd1e18f68a7b..000000000000 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py +++ /dev/null @@ -1,139 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools -from devtools_testutils import EnvironmentVariableLoader, recorded_by_proxy -from testcase import AppConfigTestCase, has_feature_flag -from test_constants import ( - APPCONFIGURATION_ENDPOINT_STRING, - APPCONFIGURATION_KEYVAULT_SECRET_URL, - FEATURE_MANAGEMENT_KEY, -) -from azure.appconfiguration.provider import SettingSelector, AzureAppConfigurationKeyVaultOptions - -AppConfigProviderPreparer = functools.partial( - EnvironmentVariableLoader, - "appconfiguration", - appconfiguration_endpoint_string=APPCONFIGURATION_ENDPOINT_STRING, - appconfiguration_keyvault_secret_url=APPCONFIGURATION_KEYVAULT_SECRET_URL, -) - - -class TestAppConfigurationProvider(AppConfigTestCase): - # method: provider_creation_aad - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_creation_aad(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - feature_flag_enabled=True, - ) - assert client["message"] == "hi" - assert client["my_json"]["key"] == "value" - assert ".appconfig.featureflag/Alpha" not in client - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "Alpha") - - # method: provider_trim_prefixes - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_trim_prefixes(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - trimmed = {"test."} - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - trim_prefixes=trimmed, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - feature_flag_enabled=True, - ) - assert client["message"] == "hi" - assert client["my_json"]["key"] == "value" - assert client["trimmed"] == "key" - assert "test.trimmed" not in client - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "Alpha") - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_selectors(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - selects = {SettingSelector(key_filter="message*", label_filter="dev")} - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) - assert client["message"] == "test" - assert "test.trimmed" not in client - assert FEATURE_MANAGEMENT_KEY not in client - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_key_vault_reference(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) - assert client["secret"] == "Very secret value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_secret_resolver(self, appconfiguration_endpoint_string): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - client = self.create_client( - endpoint=appconfiguration_endpoint_string, selects=selects, secret_resolver=secret_resolver - ) - assert client["secret"] == "Resolver Value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_key_vault_reference_options( - self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url - ): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - key_vault_options = AzureAppConfigurationKeyVaultOptions() - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - key_vault_options=key_vault_options, - ) - assert client["secret"] == "Very secret value" - - # method: provider_selectors - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_secret_resolver_options(self, appconfiguration_endpoint_string): - selects = {SettingSelector(key_filter="*", label_filter="prod")} - key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_resolver=secret_resolver) - client = self.create_client( - endpoint=appconfiguration_endpoint_string, selects=selects, key_vault_options=key_vault_options - ) - assert client["secret"] == "Resolver Value" - - @AppConfigProviderPreparer() - @recorded_by_proxy - def test_provider_tag_filters(self, appconfiguration_endpoint_string, appconfiguration_keyvault_secret_url): - selects = {SettingSelector(key_filter="*", tag_filters=["a=b"])} - client = self.create_client( - endpoint=appconfiguration_endpoint_string, - selects=selects, - feature_flag_enabled=True, - feature_flag_selectors={SettingSelector(key_filter="*", tag_filters=["a=b"])}, - keyvault_secret_url=appconfiguration_keyvault_secret_url, - ) - assert "tagged_config" in client - assert FEATURE_MANAGEMENT_KEY in client - assert has_feature_flag(client, "TaggedFeatureFlag") - assert "message" not in client - - -def secret_resolver(_): - return "Resolver Value"