Skip to content

Commit 2e111fa

Browse files
authored
[Test Proxy] Add registration methods for all sanitizers (#20819)
1 parent 17117b5 commit 2e111fa

File tree

4 files changed

+204
-50
lines changed

4 files changed

+204
-50
lines changed

tools/azure-sdk-tools/devtools_testutils/__init__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .mgmt_testcase import AzureMgmtTestCase, AzureMgmtPreparer
2-
from .azure_recorded_testcase import add_sanitizer, AzureRecordedTestCase
2+
from .azure_recorded_testcase import AzureRecordedTestCase
33
from .azure_testcase import AzureTestCase, is_live, get_region_override
44
from .resource_testcase import (
55
FakeResource,
@@ -16,12 +16,30 @@
1616
from .keyvault_preparer import KeyVaultPreparer
1717
from .powershell_preparer import PowerShellPreparer
1818
from .proxy_testcase import RecordedByProxy
19-
from .enums import ProxyRecordingSanitizer
19+
from .sanitizers import (
20+
add_body_key_sanitizer,
21+
add_body_regex_sanitizer,
22+
add_continuation_sanitizer,
23+
add_general_regex_sanitizer,
24+
add_header_regex_sanitizer,
25+
add_oauth_response_sanitizer,
26+
add_remove_header_sanitizer,
27+
add_request_subscription_id_sanitizer,
28+
add_uri_regex_sanitizer,
29+
)
2030
from .helpers import ResponseCallback, RetryCounter
2131
from .fake_credential import FakeTokenCredential
2232

2333
__all__ = [
24-
"add_sanitizer",
34+
"add_body_key_sanitizer",
35+
"add_body_regex_sanitizer",
36+
"add_continuation_sanitizer",
37+
"add_general_regex_sanitizer",
38+
"add_header_regex_sanitizer",
39+
"add_oauth_response_sanitizer",
40+
"add_remove_header_sanitizer",
41+
"add_request_subscription_id_sanitizer",
42+
"add_uri_regex_sanitizer",
2543
"AzureMgmtTestCase",
2644
"AzureMgmtPreparer",
2745
"AzureRecordedTestCase",
@@ -38,7 +56,6 @@
3856
"RandomNameResourceGroupPreparer",
3957
"CachedResourceGroupPreparer",
4058
"PowerShellPreparer",
41-
"ProxyRecordingSanitizer",
4259
"RecordedByProxy",
4360
"ResponseCallback",
4461
"RetryCounter",

tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import logging
88
import os
99
import os.path
10-
import requests
1110
import six
1211
import sys
1312
import time
@@ -21,8 +20,6 @@
2120

2221
from . import mgmt_settings_fake as fake_settings
2322
from .azure_testcase import _is_autorest_v3, get_resource_name, get_qualified_method_name
24-
from .config import PROXY_URL
25-
from .enums import ProxyRecordingSanitizer
2623

2724
try:
2825
# Try to import the AsyncFakeCredential, if we cannot assume it is Python 2
@@ -37,38 +34,6 @@
3734
load_dotenv(find_dotenv())
3835

3936

40-
def add_sanitizer(sanitizer, **kwargs):
41-
# type: (ProxyRecordingSanitizer, **Any) -> None
42-
"""Registers a sanitizer, matcher, or transform with the test proxy.
43-
44-
:param sanitizer: The name of the sanitizer, matcher, or transform you want to add.
45-
:type sanitizer: ProxyRecordingSanitizer or str
46-
47-
:keyword str value: The substitution value.
48-
:keyword str regex: A regex for a sanitizer. Can be defined as a simple regex, or if a ``group_for_replace`` is
49-
provided, a substitution operation.
50-
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
51-
a simple replacement operation.
52-
"""
53-
request_args = {}
54-
request_args["value"] = kwargs.get("value") or "fakevalue"
55-
request_args["regex"] = (
56-
kwargs.get("regex") or "(?<=\\/\\/)[a-z]+(?=(?:|-secondary)\\.(?:table|blob|queue)\\.core\\.windows\\.net)"
57-
)
58-
request_args["group_for_replace"] = kwargs.get("group_for_replace")
59-
60-
if sanitizer == ProxyRecordingSanitizer.URI:
61-
requests.post(
62-
"{}/Admin/AddSanitizer".format(PROXY_URL),
63-
headers={"x-abstraction-identifier": ProxyRecordingSanitizer.URI.value},
64-
json={
65-
"regex": request_args["regex"],
66-
"value": request_args["value"],
67-
"groupForReplace": request_args["group_for_replace"],
68-
},
69-
)
70-
71-
7237
def is_live():
7338
"""A module version of is_live, that could be used in pytest marker."""
7439
if not hasattr(is_live, "_cache"):

tools/azure-sdk-tools/devtools_testutils/enums.py

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
import requests
7+
from typing import TYPE_CHECKING
8+
9+
from .config import PROXY_URL
10+
11+
if TYPE_CHECKING:
12+
from typing import Any, Dict
13+
14+
15+
def add_body_key_sanitizer(**kwargs):
16+
# type: (**Any) -> None
17+
"""Registers a sanitizer that offers regex update of a specific JTokenPath within a returned body.
18+
19+
For example, "TableName" within a json response body having its value replaced by whatever substitution is offered.
20+
21+
:keyword str json_path: The SelectToken path (which could possibly match multiple entries) that will be used to
22+
select JTokens for value replacement.
23+
:keyword str value: The substitution value.
24+
:keyword str regex: A regex. Can be defined as a simple regex replace OR if groupForReplace is set, a subsitution
25+
operation. Defaults to replacing the entire string.
26+
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
27+
a simple replacement operation.
28+
"""
29+
30+
request_args = _get_request_args(**kwargs)
31+
_send_request("BodyKeySanitizer", request_args)
32+
33+
34+
def add_body_regex_sanitizer(**kwargs):
35+
# type: (**Any) -> None
36+
"""Registers a sanitizer that offers regex replace within a returned body.
37+
38+
Specifically, this means regex applying to the raw JSON. If you are attempting to simply replace a specific key, the
39+
BodyKeySanitizer is probably the way to go.
40+
41+
:keyword str value: The substitution value.
42+
:keyword str regex: A regex. Can be defined as a simple regex, or if a ``group_for_replace`` is provided, a
43+
substitution operation.
44+
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
45+
a simple replacement operation.
46+
"""
47+
48+
request_args = _get_request_args(**kwargs)
49+
_send_request("BodyRegexSanitizer", request_args)
50+
51+
52+
def add_continuation_sanitizer(**kwargs):
53+
# type: (**Any) -> None
54+
"""Registers a sanitizer that's used to anonymize private keys in response/request pairs.
55+
56+
For instance, a request hands back a "sessionId" that needs to be present in the next request. Supports "all further
57+
requests get this key" as well as "single response/request pair". Defaults to maintaining same key for rest of
58+
recording.
59+
60+
:keyword str key: The name of the header whos value will be replaced from response -> next request.
61+
:keyword str method: The method by which the value of the targeted key will be replaced. Defaults to guid
62+
replacement.
63+
:keyword str reset_after_first: Do we need multiple pairs replaced? Or do we want to replace each value with the
64+
same value?
65+
"""
66+
67+
request_args = _get_request_args(**kwargs)
68+
_send_request("ContinuationSanitizer", request_args)
69+
70+
71+
def add_general_regex_sanitizer(**kwargs):
72+
# type: (**Any) -> None
73+
"""Registers a sanitizer that offers a general regex replace across request/response Body, Headers, and URI.
74+
75+
For the body, this means regex applying to the raw JSON.
76+
77+
:keyword str value: The substitution value.
78+
:keyword str regex: A regex. Can be defined as a simple regex, or if a ``group_for_replace`` is provided, a
79+
substitution operation.
80+
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
81+
a simple replacement operation.
82+
"""
83+
84+
request_args = _get_request_args(**kwargs)
85+
_send_request("GeneralRegexSanitizer", request_args)
86+
87+
88+
def add_header_regex_sanitizer(**kwargs):
89+
# type: (**Any) -> None
90+
"""Registers a sanitizer that offers regex replace on returned headers.
91+
92+
Can be used for multiple purposes: 1) To replace a key with a specific value, do not set "regex" value. 2) To do a
93+
simple regex replace operation, define arguments "key", "value", and "regex". 3) To do a targeted substitution of a
94+
specific group, define all arguments "key", "value", and "regex".
95+
96+
:keyword str key: The name of the header we're operating against.
97+
:keyword str value: The substitution or whole new header value, depending on "regex" setting.
98+
:keyword str regex: A regex. Can be defined as a simple regex, or if a ``group_for_replace`` is provided, a
99+
substitution operation.
100+
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
101+
a simple replacement operation.
102+
"""
103+
104+
request_args = _get_request_args(**kwargs)
105+
_send_request("HeaderRegexSanitizer", request_args)
106+
107+
108+
def add_oauth_response_sanitizer():
109+
# type: () -> None
110+
"""Registers a sanitizer that cleans out all request/response pairs that match an oauth regex in their URI."""
111+
112+
_send_request("OAuthResponseSanitizer", {})
113+
114+
115+
def add_remove_header_sanitizer(**kwargs):
116+
# type: (**Any) -> None
117+
"""Registers a sanitizer that removes specified headers before saving a recording.
118+
119+
:keyword str headers: A comma separated list. Should look like "Location, Transfer-Encoding" or something along
120+
those lines. Don't worry about whitespace between the commas separating each key. They will be ignored.
121+
"""
122+
123+
request_args = _get_request_args(**kwargs)
124+
_send_request("RemoveHeaderSanitizer", request_args)
125+
126+
127+
def add_request_subscription_id_sanitizer(**kwargs):
128+
# type: (**Any) -> None
129+
"""Registers a sanitizer that replaces subscription IDs in requests.
130+
131+
Subscription IDs are replaced with "00000000-0000-0000-0000-000000000000" by default.
132+
133+
:keyword str value: The fake subscriptionId that will be placed where the real one is in the real request.
134+
"""
135+
136+
request_args = _get_request_args(**kwargs)
137+
_send_request("ReplaceRequestSubscriptionId", request_args)
138+
139+
140+
def add_uri_regex_sanitizer(**kwargs):
141+
# type: (**Any) -> None
142+
"""Registers a sanitizer for cleaning URIs via regex.
143+
144+
:keyword str value: The substitution value.
145+
:keyword str regex: A regex. Can be defined as a simple regex, or if a ``group_for_replace`` is provided, a
146+
substitution operation.
147+
:keyword str group_for_replace: The capture group that needs to be operated upon. Do not provide if you're invoking
148+
a simple replacement operation.
149+
"""
150+
151+
request_args = _get_request_args(**kwargs)
152+
_send_request("UriRegexSanitizer", request_args)
153+
154+
155+
def _get_request_args(**kwargs):
156+
# type: (**Any) -> Dict
157+
"""Returns a dictionary of sanitizer constructor headers"""
158+
159+
request_args = {}
160+
request_args["groupForReplace"] = kwargs.get("group_for_replace")
161+
request_args["headersForRemoval"] = kwargs.get("headers")
162+
request_args["jsonPath"] = kwargs.get("json_path")
163+
request_args["key"] = kwargs.get("key")
164+
request_args["method"] = kwargs.get("method")
165+
request_args["regex"] = kwargs.get("regex")
166+
request_args["resetAfterFirst"] = kwargs.get("reset_after_first")
167+
request_args["value"] = kwargs.get("value")
168+
return request_args
169+
170+
171+
def _send_request(sanitizer, parameters):
172+
# type: (str, Dict) -> None
173+
"""Send a POST request to the test proxy endpoint to register the specified sanitizer.
174+
175+
:param str sanitizer: The name of the sanitizer to add.
176+
:param dict parameters: The sanitizer constructor parameters, as a dictionary.
177+
"""
178+
179+
requests.post(
180+
"{}/Admin/AddSanitizer".format(PROXY_URL),
181+
headers={"x-abstraction-identifier": sanitizer},
182+
json=parameters
183+
)

0 commit comments

Comments
 (0)