diff --git a/doc/dev/tests.md b/doc/dev/tests.md index 4b98e6b2288..c8d45fff550 100644 --- a/doc/dev/tests.md +++ b/doc/dev/tests.md @@ -181,6 +181,13 @@ Live Azure resources will be necessary in order to run live tests and produce re resource management commands, documented in [/eng/common/TestResources][test_resources], that streamline this process. Both pure ARM templates (`test-resources.json`) and BICEP files (`test-resources.bicep`) are supported. +User-based authentication is preferred when using test resources. To enable this: +- Use the [`-UserAuth` command flag][user_auth_flag] when running the `New-TestResources` script. +- Set the environment variable `AZURE_TEST_USE_PWSH_AUTH` to "true" to authenticate with Azure PowerShell, or +`AZURE_TEST_USE_CLI_AUTH` to "true" to authenticate with Azure CLI. + - Ensure you're logged into the tool you choose -- if +you used `New-TestResources.ps1` to deploy resources, you'll already have logged in with Azure PowerShell. + If you haven't yet set up a `test-resources` file for test resource deployment and/or want to use test resources of your own, you can just configure credentials to target these resources instead. @@ -209,14 +216,20 @@ environment variables necessary to run live tests for the service. After storing -- formatted as `VARIABLE=value` on separate lines -- your credentials and test configuration variables will be set in our environment when running tests. -If your service doesn't have a `test-resources` file for test deployment, you'll need to set environment variables -for `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` at minimum. +If you used the [`-UserAuth` command flag][user_auth_flag] to deploy test resources, set either +`AZURE_TEST_USE_PWSH_AUTH` or `AZURE_TEST_USE_CLI_AUTH` to "true" to authenticate with Azure PowerShell or Azure CLI, +respectively. If both are set to true, Azure PowerShell will be used. +If your service doesn't have a `test-resources` file for test deployment, you'll need to set environment variables +for authentication at minimum. For user-based authentication, use `AZURE_TEST_USE_PWSH_AUTH` or +`AZURE_TEST_USE_CLI_AUTH` as described above. + +For service principal authentication: 1. Set the `AZURE_SUBSCRIPTION_ID` variable to your organization's subscription ID. You can find it in the "Overview" section of the "Subscriptions" blade in the [Azure Portal][azure_portal]. 2. Define the `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` of a test service principal. If you do not - have a service principal, use the Azure CLI's [az ad sp create-for-rbac][azure_cli_service_principal] command (ideally, - using your alias as the service principal's name prefix): + have a service principal, use the Azure CLI's [az ad sp create-for-rbac][azure_cli_service_principal] command + (ideally, using your alias as the service principal's name prefix): ``` az login @@ -326,7 +339,9 @@ well. To run tests in playback, either set `AZURE_TEST_RUN_LIVE` to "false" or l ### Run and record tests -With the `AZURE_TEST_RUN_LIVE` environment variable set to "true", use `pytest` to run your test(s) in live mode. +First, refer to the [Configure test variables](#configure-test-variables) section to ensure environment variables are +set for test resources and authentication. With the `AZURE_TEST_RUN_LIVE` environment variable set to "true", use +`pytest` to run your test(s) in live mode. ``` (env) azure-sdk-for-python\sdk\my-service\my-package> pytest tests @@ -339,18 +354,18 @@ Playback test errors most frequently indicate a need for additional sanitizers a [Sanitize secrets](#sanitize-secrets)). If you encounter any unexpected errors, refer to the [test proxy troubleshooting guide][troubleshooting_guide]. -At this point there should folder called `recordings` inside your package's `tests` directory. Each recording in this -folder will be a `.json` file that captures the HTTP traffic that was generated while running the test matching the -file's name. +If tests were recorded for a new library, there should now be a folder called `recordings` inside your package's +`tests` directory. Each recording in this folder will be a `.json` file that captures the HTTP traffic that was +generated while running the test matching the file's name. The final step in setting up recordings is to move these files out of the `azure-sdk-for-python` and into the `azure-sdk-assets` repository. The [recording migration guide][recording_move] describes how to do so. This step only -needs to be completed once. Your library will have an `assets.json` file at its root, which stores the `azure-sdk-assets` -tag that contains the current set of recordings. +needs to be completed once. Your library will have an `assets.json` file at its root, which stores the +`azure-sdk-assets` tag that contains the current set of recordings. -From this point on, recordings will automatically be fetched when tests are run in playback mode -- either from -a local cache (described in [Update test recordings](#update-test-recordings)), or from `azure-sdk-assets` if they're -not locally available. +From this point on, recordings will automatically be fetched when tests are run in playback mode -- either from a local +cache (described in [Update test recordings](#update-test-recordings)), or from `azure-sdk-assets` if they're not +locally available. #### Update test recordings @@ -725,3 +740,4 @@ Tests that use the Shared Access Signature (SAS) to authenticate a client should [test_proxy_startup]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md#start-the-proxy-server [test_resources]: https://github.com/Azure/azure-sdk-for-python/tree/main/eng/common/TestResources#readme [troubleshooting_guide]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_troubleshooting.md +[user_auth_flag]: https://github.com/Azure/azure-sdk-for-python/blob/main/eng/common/TestResources/New-TestResources.ps1.md#-userauth diff --git a/tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py b/tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py index 4747c2f0bb1..ea323e53c06 100644 --- a/tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py +++ b/tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py @@ -4,6 +4,7 @@ # license information. # -------------------------------------------------------------------------- import functools +import logging import os import os.path import six @@ -24,6 +25,8 @@ from .helpers import is_live, trim_kwargs_from_test_function from .sanitizers import add_general_string_sanitizer +_LOGGER = logging.getLogger() + load_dotenv(find_dotenv()) @@ -87,23 +90,54 @@ class AzureRecordedTestCase(object): tenant_id = os.environ.get("AZURE_TENANT_ID", getattr(os.environ, "TENANT_ID", None)) client_id = os.environ.get("AZURE_CLIENT_ID", getattr(os.environ, "CLIENT_ID", None)) secret = os.environ.get("AZURE_CLIENT_SECRET", getattr(os.environ, "CLIENT_SECRET", None)) + + use_pwsh = os.environ.get("AZURE_TEST_USE_PWSH_AUTH", "false") + use_cli = os.environ.get("AZURE_TEST_USE_CLI_AUTH", "false") is_async = kwargs.pop("is_async", False) - if tenant_id and client_id and secret and self.is_live: - if _is_autorest_v3(client_class): - # Create azure-identity class - from azure.identity import ClientSecretCredential + # Return live credentials only in live mode + if self.is_live: + # User-based authentication through Azure PowerShell, if requested + if use_pwsh.lower() == "true": + _LOGGER.info( + "Environment variable AZURE_TEST_USE_PWSH_AUTH set to 'true'. Using AzurePowerShellCredential." + ) + from azure.identity import AzurePowerShellCredential if is_async: - from azure.identity.aio import ClientSecretCredential - return ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=secret) - else: - # Create msrestazure class - from msrestazure.azure_active_directory import ( - ServicePrincipalCredentials, - ) + from azure.identity.aio import AzurePowerShellCredential + return AzurePowerShellCredential() + # User-based authentication through Azure CLI, if requested + if use_cli.lower() == "true": + _LOGGER.info("Environment variable AZURE_TEST_USE_CLI_AUTH set to 'true'. Using AzureCliCredential.") + from azure.identity import AzureCliCredential - return ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=secret) + if is_async: + from azure.identity.aio import AzureCliCredential + return AzureCliCredential() + + # Service principal authentication + if tenant_id and client_id and secret: + # Check for track 2 client + if _is_autorest_v3(client_class): + _LOGGER.info( + "Service principal client ID, secret, and tenant ID detected. Using ClientSecretCredential.\n" + "For user-based auth, set AZURE_TEST_USE_PWSH_AUTH or AZURE_TEST_USE_CLI_AUTH to 'true'." + ) + from azure.identity import ClientSecretCredential + + if is_async: + from azure.identity.aio import ClientSecretCredential + return ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=secret) + else: + # Create msrestazure class + from msrestazure.azure_active_directory import ( + ServicePrincipalCredentials, + ) + + return ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=secret) + + # For playback tests, return credentials that will accept playback `get_token` calls else: if _is_autorest_v3(client_class): if is_async: