Skip to content

Commit e769b81

Browse files
authored
[KeyVault] Enable Test Proxy for KeyVault Secrets (Azure#22807)
* switch to assert from self.assert* * Adding in conftest * Make sleep patches into fixtures * Change class name for pytest * move from aztestcase to azrectestcase * fix import * change class name for pytest * decorate sync tests with proxy * decorate async tests * missing imports * changes to get the tests collectd by pytest * add in sanitizers & test proxy changes * secrets client async preparer * changes for preparer * update with further sanitizers * update to test and recordings * changes to async test case * update test_parse to record output * minor cleanups * move to async prepaper * updates * minor changes to get tests working * more recordings from test proxy * switch to assert from self.assert* * Adding in conftest * updates * updates * further merges * merges * merges * changes * more recordings for async tests * Changes for async tests and work around for test proxy * Changes to to get tests working * change for EnvironmentVariablesLoader & recordings * clean up for client creation * fix patches for sleep * add in http cache clean * mods for win-http * recordings using test proxy * set default vault url * changes for auth headers * changes for auth update * new recordings * delete vcrpy recordings * remove unused imports & code cleanup * minor changes around patching sleep * new recordings for 7.3 * new recordings * clean up recordings of 7.3 preview * remove 7.3 preview tests * removing customer default handler for auth * new recording for test * code clean up and formatting * remove temp fix for async recordings * code clean up for imports, better error messages * add cache challenge in to a teardown * new recordings with cache challenge change * change kv url error * fix wrong masking name * Fix SecretsClientPreparer typo * remove code block for async tests * remove unused imports
1 parent 1eec48b commit e769b81

File tree

279 files changed

+216280
-190627
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

279 files changed

+216280
-190627
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
import os
6+
7+
import pytest
8+
from azure.keyvault.secrets._shared.client_base import DEFAULT_VERSION
9+
from devtools_testutils import AzureRecordedTestCase, is_live
10+
11+
12+
class AsyncSecretsClientPreparer(AzureRecordedTestCase):
13+
def __init__(self, **kwargs) -> None:
14+
self.azure_keyvault_url = "https://vaultname.vault.azure.net"
15+
16+
if is_live():
17+
self.azure_keyvault_url = os.environ["AZURE_KEYVAULT_URL"]
18+
19+
self.is_logging_enabled = kwargs.pop("logging_enable", True)
20+
if is_live():
21+
os.environ["AZURE_TENANT_ID"] = os.environ["KEYVAULT_TENANT_ID"]
22+
os.environ["AZURE_CLIENT_ID"] = os.environ["KEYVAULT_CLIENT_ID"]
23+
os.environ["AZURE_CLIENT_SECRET"] = os.environ["KEYVAULT_CLIENT_SECRET"]
24+
25+
def __call__(self, fn):
26+
async def _preparer(test_class, api_version, **kwargs):
27+
self._skip_if_not_configured(api_version)
28+
if not self.is_logging_enabled:
29+
kwargs.update({"logging_enable": False})
30+
client = self.create_client(self.azure_keyvault_url, api_version=api_version, **kwargs)
31+
await fn(test_class, client)
32+
33+
return _preparer
34+
35+
def create_client(self, vault_uri, **kwargs):
36+
from azure.keyvault.secrets.aio import SecretClient
37+
38+
credential = self.get_credential(SecretClient, is_async=True)
39+
return self.create_client_from_credential(SecretClient, credential=credential, vault_url=vault_uri, **kwargs)
40+
41+
def _skip_if_not_configured(self, api_version, **kwargs):
42+
if is_live() and api_version != DEFAULT_VERSION:
43+
pytest.skip("This test only uses the default API version for live tests")

sdk/keyvault/azure-keyvault-secrets/tests/_shared/test_case.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,11 @@
44
# ------------------------------------
55
import time
66

7-
from azure_devtools.scenario_tests.patches import patch_time_sleep_api
8-
from devtools_testutils import AzureTestCase
7+
from azure.keyvault.secrets._shared import HttpChallengeCache
8+
from devtools_testutils import AzureRecordedTestCase
99

1010

11-
class KeyVaultTestCase(AzureTestCase):
12-
def __init__(self, *args, **kwargs):
13-
if "match_body" not in kwargs:
14-
kwargs["match_body"] = True
15-
16-
super(KeyVaultTestCase, self).__init__(*args, **kwargs)
17-
self.replay_patches.append(patch_time_sleep_api)
18-
19-
def setUp(self):
20-
self.list_test_size = 7
21-
super(KeyVaultTestCase, self).setUp()
22-
11+
class KeyVaultTestCase(AzureRecordedTestCase):
2312
def get_resource_name(self, name):
2413
"""helper to create resources with a consistent, test-indicative prefix"""
2514
return super(KeyVaultTestCase, self).get_resource_name("livekvtest{}".format(name))
@@ -48,3 +37,7 @@ def _poll_until_exception(self, fn, expected_exception, max_retries=20, retry_de
4837
return
4938

5039
self.fail("expected exception {expected_exception} was not raised")
40+
41+
def teardown_method(self, method):
42+
HttpChallengeCache.clear()
43+
assert len(HttpChallengeCache._cache) == 0

sdk/keyvault/azure-keyvault-secrets/tests/_shared/test_case_async.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,11 @@
44
# ------------------------------------
55
import asyncio
66

7-
from azure_devtools.scenario_tests.patches import mock_in_unit_test
8-
from devtools_testutils import AzureTestCase
7+
from azure.keyvault.secrets._shared import HttpChallengeCache
8+
from devtools_testutils import AzureRecordedTestCase
99

1010

11-
def skip_sleep(unit_test):
12-
async def immediate_return(_):
13-
return
14-
15-
return mock_in_unit_test(unit_test, "asyncio.sleep", immediate_return)
16-
17-
18-
class KeyVaultTestCase(AzureTestCase):
19-
def __init__(self, *args, match_body=True, **kwargs):
20-
super().__init__(*args, match_body=match_body, **kwargs)
21-
self.replay_patches.append(skip_sleep)
22-
23-
def setUp(self):
24-
self.list_test_size = 7
25-
super(KeyVaultTestCase, self).setUp()
26-
11+
class KeyVaultTestCase(AzureRecordedTestCase):
2712
def get_resource_name(self, name):
2813
"""helper to create resources with a consistent, test-indicative prefix"""
2914
return super(KeyVaultTestCase, self).get_resource_name("livekvtest{}".format(name))
@@ -51,3 +36,7 @@ async def _poll_until_exception(self, fn, expected_exception, max_retries=20, re
5136
except expected_exception:
5237
return
5338
self.fail("expected exception {expected_exception} was not raised")
39+
40+
def teardown_method(self, method):
41+
HttpChallengeCache.clear()
42+
assert len(HttpChallengeCache._cache) == 0

sdk/keyvault/azure-keyvault-secrets/tests/_test_case.py

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,49 @@
22
# Copyright (c) Microsoft Corporation.
33
# Licensed under the MIT License.
44
# ------------------------------------
5-
import functools
5+
import os
66

7+
import pytest
78
from azure.keyvault.secrets import ApiVersion
8-
from azure.keyvault.secrets._shared import HttpChallengeCache
99
from azure.keyvault.secrets._shared.client_base import DEFAULT_VERSION
10-
from devtools_testutils import AzureTestCase, PowerShellPreparer
11-
from parameterized import parameterized, param
12-
import pytest
13-
14-
15-
def client_setup(testcase_func):
16-
"""decorator that creates a client to be passed in to a test method"""
17-
@PowerShellPreparer("keyvault", azure_keyvault_url="https://vaultname.vault.azure.net")
18-
@functools.wraps(testcase_func)
19-
def wrapper(test_class_instance, azure_keyvault_url, api_version, **kwargs):
20-
test_class_instance._skip_if_not_configured(api_version)
21-
client = test_class_instance.create_client(azure_keyvault_url, api_version=api_version, **kwargs)
22-
23-
if kwargs.get("is_async"):
24-
import asyncio
25-
26-
coroutine = testcase_func(test_class_instance, client)
27-
loop = asyncio.get_event_loop()
28-
loop.run_until_complete(coroutine)
29-
else:
30-
testcase_func(test_class_instance, client)
31-
return wrapper
10+
from devtools_testutils import AzureRecordedTestCase, is_live
3211

3312

3413
def get_decorator(**kwargs):
3514
"""returns a test decorator for test parameterization"""
36-
params = [param(api_version=api_version, **kwargs) for api_version in ApiVersion]
37-
return functools.partial(parameterized.expand, params, name_func=suffixed_test_name)
15+
return [(api_version) for api_version in ApiVersion]
16+
3817

18+
class SecretsClientPreparer(AzureRecordedTestCase):
19+
def __init__(self, **kwargs) -> None:
20+
self.azure_keyvault_url = "https://vaultname.vault.azure.net"
3921

40-
def suffixed_test_name(testcase_func, param_num, param):
41-
return "{}_{}".format(testcase_func.__name__, parameterized.to_safe_name(param.kwargs.get("api_version")))
22+
if is_live():
23+
self.azure_keyvault_url = os.environ["AZURE_KEYVAULT_URL"]
4224

25+
self.is_logging_enabled = kwargs.pop("logging_enable", True)
26+
if is_live():
27+
os.environ["AZURE_TENANT_ID"] = os.environ["KEYVAULT_TENANT_ID"]
28+
os.environ["AZURE_CLIENT_ID"] = os.environ["KEYVAULT_CLIENT_ID"]
29+
os.environ["AZURE_CLIENT_SECRET"] = os.environ["KEYVAULT_CLIENT_SECRET"]
4330

44-
class SecretsTestCase(AzureTestCase):
45-
def tearDown(self):
46-
HttpChallengeCache.clear()
47-
assert len(HttpChallengeCache._cache) == 0
48-
super(SecretsTestCase, self).tearDown()
31+
def __call__(self, fn):
32+
def _preparer(test_class, api_version, **kwargs):
33+
self._skip_if_not_configured(api_version)
34+
if not self.is_logging_enabled:
35+
kwargs.update({"logging_enable": False})
36+
client = self.create_client(self.azure_keyvault_url, **kwargs, api_version=api_version)
37+
with client:
38+
fn(test_class, client)
39+
40+
return _preparer
4941

5042
def create_client(self, vault_uri, **kwargs):
51-
if kwargs.pop("is_async", False):
52-
from azure.keyvault.secrets.aio import SecretClient
53-
credential = self.get_credential(SecretClient, is_async=True)
54-
else:
55-
from azure.keyvault.secrets import SecretClient
56-
credential = self.get_credential(SecretClient)
57-
return self.create_client_from_credential(
58-
SecretClient, credential=credential, vault_url=vault_uri, **kwargs
59-
)
43+
from azure.keyvault.secrets import SecretClient
44+
45+
credential = self.get_credential(SecretClient)
46+
return self.create_client_from_credential(SecretClient, credential=credential, vault_url=vault_uri, **kwargs)
6047

6148
def _skip_if_not_configured(self, api_version, **kwargs):
62-
if self.is_live and api_version != DEFAULT_VERSION:
49+
if is_live() and api_version != DEFAULT_VERSION:
6350
pytest.skip("This test only uses the default API version for live tests")
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# --------------------------------------------------------------------------
2+
#
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
#
5+
# The MIT License (MIT)
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the ""Software""), to
9+
# deal in the Software without restriction, including without limitation the
10+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11+
# sell copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in
15+
# all copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23+
# IN THE SOFTWARE.
24+
#
25+
# --------------------------------------------------------------------------
26+
import os
27+
import pytest
28+
from unittest import mock
29+
from devtools_testutils import is_live, test_proxy, add_oauth_response_sanitizer, add_general_regex_sanitizer
30+
31+
32+
@pytest.fixture(scope="session", autouse=True)
33+
def add_sanitizers(test_proxy):
34+
azure_keyvault_url = os.getenv("azure_keyvault_url", "https://vaultname.vault.azure.net")
35+
azure_keyvault_url = azure_keyvault_url.rstrip("/")
36+
keyvault_tenant_id = os.getenv("keyvault_tenant_id", "keyvault_tenant_id")
37+
keyvault_subscription_id = os.getenv("keyvault_subscription_id", "keyvault_subscription_id")
38+
39+
add_general_regex_sanitizer(regex=azure_keyvault_url, value="https://vaultname.vault.azure.net")
40+
add_general_regex_sanitizer(regex=keyvault_tenant_id, value="00000000-0000-0000-0000-000000000000")
41+
add_general_regex_sanitizer(regex=keyvault_subscription_id, value="00000000-0000-0000-0000-000000000000")
42+
add_oauth_response_sanitizer()
43+
44+
45+
@pytest.fixture(scope="session", autouse=True)
46+
def patch_async_sleep():
47+
async def immediate_return(_):
48+
return
49+
50+
if not is_live():
51+
with mock.patch("asyncio.sleep", immediate_return):
52+
yield
53+
54+
else:
55+
yield
56+
57+
58+
@pytest.fixture(scope="session", autouse=True)
59+
def patch_sleep():
60+
def immediate_return(_):
61+
return
62+
63+
if not is_live():
64+
with mock.patch("time.sleep", immediate_return):
65+
yield
66+
67+
else:
68+
yield

sdk/keyvault/azure-keyvault-secrets/tests/perfstress_tests/get_secret.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111

1212
class GetSecretTest(PerfStressTest):
13-
1413
def __init__(self, arguments):
1514
super().__init__(arguments)
1615

sdk/keyvault/azure-keyvault-secrets/tests/perfstress_tests/list_secrets.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313

1414
class ListSecretsTest(PerfStressTest):
15-
1615
def __init__(self, arguments):
1716
super().__init__(arguments)
1817

@@ -31,11 +30,15 @@ async def global_setup(self):
3130
# Validate that vault contains 0 secrets (including soft-deleted secrets), since additional secrets
3231
# (including soft-deleted) impact performance.
3332
async for secret in self.async_client.list_properties_of_secrets():
34-
raise Exception("KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test" \
35-
% self.async_client.vault_url)
33+
raise Exception(
34+
"KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test"
35+
% self.async_client.vault_url
36+
)
3637
async for secret in self.async_client.list_deleted_secrets():
37-
raise Exception("KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test" \
38-
% self.async_client.vault_url)
38+
raise Exception(
39+
"KeyVault %s must contain 0 secrets (including soft-deleted) before starting perf test"
40+
% self.async_client.vault_url
41+
)
3942

4043
await super().global_setup()
4144
create = [self.async_client.set_secret(name, "secret-value") for name in self.secret_names]
@@ -72,5 +75,5 @@ async def run_async(self):
7275
def add_arguments(parser):
7376
super(ListSecretsTest, ListSecretsTest).add_arguments(parser)
7477
parser.add_argument(
75-
'--count', nargs='?', type=int, help='Number of secrets to list. Defaults to 10', default=10
78+
"--count", nargs="?", type=int, help="Number of secrets to list. Defaults to 10", default=10
7679
)

0 commit comments

Comments
 (0)