To users writing SDK tests: This document is not intended to be a test preparation reference. You should instead refer to documentation in your specific language repository in order to configure recorded tests.
- Azure SDK Tools Test Proxy
- Test documentation by language:
- Installation
- Command line arguments
- Environment Variables
- How do I use the test-proxy to get a recording?
- How do I use the test-proxy to play a recording back?
- Session and Test Level Transforms, Sanitizers, and Matchers
- Recording Options
- Testing
- SSL Support
- Troubleshooting
- Asset Sync (Retrieve External Test Recordings)
This test proxy is intended to provide out-of-process record/playback capabilities compatible with any language. It offers session and recording level customization during both record
and playback
of a test.
All that is required to start recording is to make minor updates to the requests made within a given test. A standard request looks something like this:
Modified to be recordable by the test proxy, it should look like this:
There is a walkthrough through the process below in the how do I use the test proxy to get a recording.
For a more detailed explanation of how the test proxy works, along with links to demo projects for various languages, refer to the following post on the Azure SDK blog:
Level up your cloud testing game with the Azure SDK test proxy
- Install .NET 5.0 or 6.0
- Install test-proxy
dotnet tool update azure.sdk.tools.testproxy --global --add-source https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json --version "1.0.0-dev*" --ignore-failed-sources
The test-proxy is also available from the azure-sdk-for-net public feed
Note: if you're not authorized to access these feeds, make sure you have Azure Artifacts Credential Provider installed. You can also download executable.
To uninstall an existing test-proxy
dotnet tool uninstall --global azure.sdk.tools.testproxy
After successful installation, run the tool:
test-proxy --storage-location <location>
If you've already installed the tool, you can always check the installed version by invoking:
test-proxy --version
Standalone executable versions of the test-proxy are published to github releases on this repository.
These executables are produced for multiple platforms and are available attached as assets
:
The version suffix for each release is based on the date. In most cases, the latest version should be totally stable.
For safety, the "official target" version that the azure-sdk team uses is present within eng/common/testproxy/target_version.txt
. New "official" versions are tested by all consumers prior to updating the target version within this file.
This is the help information for test-proxy. It uses the nuget package System.CommandLine
to parse arguments.
The test-proxy executable fulfills one of two primary purposes:
- The test-proxy server (the only option up to this point)
asset-sync
verbspush
restore
reset
config
This is surfaced by only showing options for the default commands. Each individual command has its own argument set that can be detailed by invoking test-proxy <command> --help
.
/>Azure.Sdk.Tools.TestProxy --help
Description:
This tool is used by the Azure SDK team in two primary ways:
- Run as a http record/playback server. ("start" / default verb)
- Invoke a CLI Tool to interact with recordings in an external store. ("push", "restore", "reset", "config")
Usage:
Azure.Sdk.Tools.TestProxy [command] [options]
Options:
-l, --storage-location <storage-location> The path to the target local git repo. If not provided as an argument, Environment
variable TEST_PROXY_FOLDER will be consumed. Lacking both, the current working
directory will be utilized.
-p, --storage-plugin <storage-plugin> The plugin for the selected storage, default is Git storage is GitStore. (Currently
the only option) [default: GitStore]
--version Show version information
-?, -h, --help Show help and usage information
Commands:
start <args> Start the TestProxy.
push Push the assets, referenced by assets.json, into git.
restore Restore the assets, referenced by assets.json, from git.
reset Reset the assets, referenced by assets.json, from git to their original files referenced by the tag. Will prompt if
there are pending changes unless indicated by -y/--yes.
config Interact with an assets.json.
For the config
verb, there are subverbs!
/>Azure.Sdk.Tools.TestProxy config --help
Description:
Interact with an assets.json.
Usage:
Azure.Sdk.Tools.TestProxy config [command] [options]
Options:
-l, --storage-location <storage-location> The path to the target local git repo. If not provided as an argument, Environment
variable TEST_PROXY_FOLDER will be consumed. Lacking both, the current working
directory will be utilized.
-p, --storage-plugin <storage-plugin> The plugin for the selected storage, default is Git storage is GitStore. (Currently
the only option) [default: GitStore]
-?, -h, --help Show help and usage information
Commands:
create Enter a prompt and create an assets.json.
show Show the content of a given assets.json.
locate Get the assets repo root for a given assets.json path.
The test-proxy resolves the storage location via:
- Command Line argument
--storage-location
or the abbreviation-l
- Environment variable TEST_PROXY_FOLDER
- If neither are present, the working directory from which the server is invoked.
By default, the server will listen on the following port mappings:
protocol | port |
---|---|
http | 5000 |
https | 5001 |
Warning
MacOS users should be aware that airplay
by default utilizes port 5000. Ensure the port is free or use a non-default port as described below.
Set ASPNETCORE_URLS
to define a custom port for either http or https (or both). Here are some examples:
$env:ASPNETCORE_URLS="http://*:3331" // Set custom port for http only
$env:ASPNETCORE_URLS="http://*3331;https://*:8881" // set custom ports for both http and https
When starting the test proxy there are Verbs, as shown in the test-proxy --help output above. For the start
verb, there can be additional command arguments that need to get passed to Host.CreateDefaultBuilder 'as is'. The way this is done is through the use of --
or dashdash as it's referred to. If --
is on the command line, everything after will be treated as arguments that will be passed into this Host call.
For example, you can use command line argument --urls
to bind to a non-default host and port. This configuration will override the environment configuration. To bind to localhost http 9000, provide the argument -- --urls http://localhost:9000
. Note that --
, space, then the --urls http://localhost:9000
.
test-proxy -- --urls "http://localhost:9000;https://localhost:9001"
The test-proxy is integrated with the following environment variables.
Variable | Usage |
---|---|
TEST_PROXY_FOLDER |
if command-line argument storage-location is not provided when invoking the proxy, this environment variable is also checked for a valid directory to use as test-proxy context. |
Logging__LogLevel__Default |
Defaults to Information . Possible valid values are Debug , Information , Warning , Error , Critical .Do not set for .NET test runs as it would cause the tests themselves to start emitting logs. |
Logging__LogLevel__Azure.Sdk.Tools.TestProxy |
Set to Debug to see request level logs emitted by the Test Proxy. |
Before we begin a technical explanation, lets first discuss the general use of the test-proxy.
- User starts test-proxy, default url the proxy will be available on is
http://localhost:5000
. - User initiates a POST to the proxy url
http://localhost:5000/Record/Start
with a body (which we will describe later) describing what we are recording. - User sends requests through the test-proxy by modifying their actual test requests as described below.
- User initates a POST to the proxy url
http://localhost:5000/Record/Stop
. - Repeat steps 2 through 4 as necessary for each test.
There is a lot of detail omitted from the above, but this is the general process.
The test-proxy is really meant to be integrated with a test framework. One that allows steps 2 and 4 to be handled by setup
and teardown
of individual record/playback sessions as well as updating the test requests so that they flow to the test-proxy instead of their actual target.
Please reference the clients under sample-clients/
folder for examples of what the process of modifying the requests actually looks like.
Reference the Installation section of this readme. SSL Configuration is discussed below in SSL Support.
A couple notes before running the test-proxy:
- Reference command line arguments and understand the options.
- The test-proxy runs in a "context" which is just a directory on your disk. When initializing a recording, all paths should be relative to this context directory.
Recall in the previous section that the test-proxy started in a context
. Again, this is just a directory on your disk. For the azure-sdk repositories, the test-proxy is normally started in the root of the repo. All recording files are then referenced relative from the root of that repo.
For example, let's invoke the test-proxy:
test-proxy --storage-location "C:/repo/sdk-for-net/"
We start a test run by POST-ing to either /Record/Start
or /Playback/Start
. Within the body of the post request we provide a file location within JSON body key x-recording-file
.
This key is used in combination with the context
directory to either store or load an existing recording.
For example, lets say that:
- The test-proxy has been started in directory
C:/repo/sdk-for-net/
. - The user POSTS to
/Record/Start
- The key passed in
x-recording-file
is a valid path:sdk/anomalydetector/Azure.AI.AnomalyDetector/tests/SessionRecords/GetresultForChangePoint.json
The test-proxy effectively joins the context directory and the incoming path to come up with a final location on disk.
context = C:/repo/sdk-for-net/
key = sdk/anomalydetector/Azure.AI.AnomalyDetector/tests/SessionRecords/GetresultForChangePoint.json
final path = C:/repo/sdk-for-net/sdk/anomalydetector/Azure.AI.AnomalyDetector/tests/SessionRecords/GetresultForChangePoint.json
When the user POSTS to /Record/Stop
the recording will be written to the file as described directly above.
During a playback
start, the value for x-recording-file
is used to load an existing recording into memory and serve requests from it!
Please note that if a absolute path is presented in header x-recording-file
. The test-proxy will write directly to that file, wherever it is. If the parent folders do not exist, they will be created at run-time during the write operation.
To start an individual test recording or playback, users will POST to a route on the running test-proxy. In real-world cases, this initial POST should be taken care of by the setup
function of an individual test.
// Targeted URI: https://localhost:5001/record/start
// request body
{
"x-recording-file": "<path-to-test>/<testfile>.<testname>"
}
// if the x-recording-file doesn't end with ".json", that will be appended prior to writing.
You will receive a recordingId in the reponse under header x-recording-id
. This value should be included under header x-recording-id
in all further requests.
For playback, you will receive the location of the recording file (if it is on disk) in the header x-base64-recording-file-location
. This will be a base64 encoded string, as it can contain characters that are not allowed in header values.
The implicit assumption about this proxy is that you as a dev have some way to reroute your existing requests (with some header additions) to the test-proxy.
The implementation is language specific, but what you want to do is:
- Prevent each request originating from the test test from hitting their original endpoint.
- Make the following changes to every outgoing request
- Place original request scheme + hostname in header
x-recording-upstream-base-uri
- Example header setting:
x-recording-upstream-base-uri: "https://fakeazsdktestaccount.table.core.windows.net"
- Example header setting:
- Replace request scheme:hostname with Proxy Server scheme:hostname. (currently
https://localhost:5001
orhttp://localhost:5000
)- Example transformation:
https://fakeazsdktestaccount.table.core.windows.net/Tables
->http://localhost:5001/Tables
.
- Example transformation:
- Add header
"x-recording-id": <x-recording-id>
from startup step - Add header
"x-recording-mode": "record"
- Place original request scheme + hostname in header
- As each request hits the test proxy (due to the fact the target hostname has been updated), the test-proxy will invoke the requests and store their results prior to returning to the test code.
- The request/response results are saved into memory based on the header
x-recording-id
. Forgetting this means your recordings will always be empty! - Recordings are saved after STOPPING your test.
- The request/response results are saved into memory based on the header
A custom transport or request policy are both examples of implementing the above logic.
After your test has finished and there are no additional requests to be recorded, a test must be stopped to save the recording to disk.
POST to the proxy server:
// Targeted URI: https://localhost:5001/record/start
// header dictionary
{
"x-recording-id": "<x-recording-id>",
"Content-Type": "application/json"
}
// optional body storing VARIABLE values. See section below for additional detail.
{
"key1": "value1",
"key2": "value2"
}
The Content-Type
must be set ONLY if a body with values is also sent. Read section directly below storing variables for a description.
This will finalize your recording by:
- Removing from active sessions.
- Applying session/recording sanitizers.
- Saving to disk.
In test frameworks integrating with the test-proxy, this function should be invoked in the teardown
function or the language equivalent.
In the above example notice that there is an optional body. This is extremely useful when your tests have an element of "randomness" to them. A great example of non-secret randomness would be a tablename
provided during tables storage
tests. It is extremely common for a given azure-sdk test framework to generate a name like u324bca
. Unfortunately, randomness can lead to difficulties during playback
. The URI, headers, and body of a request must match exactly with a recording entry.
Given that recordings are not traditionally accessible to the client code, there is no way to "retrieve" what those random non-secret values WERE. Without that capability, one must sanitize everything that could be possibly random.
An alternative is this variable
concept. During a final POST to /Record/Stop
, set the Content-Type
header and make the body
of the request a simple JSON map. The test-proxy will pass back these values in the body
of /Playback/Start
.
Some tests send large request bodies that are not meaningful and should not be stored in the session records. In order to disable storing the request body for a specific request, add the request header "x-recording-skip" and set the value to "request-body". This header can also be used to skip an entire request/response pair from being included in the recording - this is useful for cleanup code that you might have as part of your test. To skip the request/response pair, set the "x-recording-skip" header value to "request-response". Note that the "x-recording-skip" should only be specified when in Record
mode. As a result, any request that would use the "request-response" value when in Record
mode should not be sent when in Playback
mode. For requests that use "request-body" in Record
mode, you should either null out the body of the request before sending to the test proxy when in Playback
mode, or you can set a CustomDefaultMatcher
with compareBodies = false
.
One can also prevent update of a recording file on disk by providing a header of value x-recording-skip: "request-response"
along with your POST to /Record/Stop
.
Extremely similar to recording start.
POST to the proxy server:
// Targeted URI: https://localhost:5001/playback/start
// request body
{
"x-recording-file": "<path-to-test>/recordings/<testfile>.<testname>"
}
As with /record/start
, check response header x-recording-id
to get the recording-id for usage later on.
In the case where a user set variables
in /Record/Stop
, those values will also be returned in the body
of the result from /Playback/Start
. There is no manipulation of these values, whatever is saved during /Record/Stop
should be identical to what is available from /Playback/Start
.
As one could guess based on the routes, these variables are saved and returned on a per-recording basis.
The configuration here is practically identical to what we lay out in Run your tests. The only difference is that x-recording-mode
header should be set to playback
.
This really only allows the server to free up a few bits, but:
POST to the proxy server:
// targeted URI: https://localhost:5001/playback/stop
// header dictionary
{
"x-recording-id": "<x-recording-id>"
}
If a user does not provide a fileId
via body key x-recording-file
, the recording will be saved in-memory only. If a recording is saved into memory, the only way to retrieve it is to access the playback by passing along the original recordingId that you recorded it with.
Start the recording without a x-recording-file
body value.
// targeted URI: https://localhost:5001/record/start
// the request body will be NULL / unset
The POST will return a valid recordingId value which we will call X
.
To load this recording for playback...
// Targeted URI https://localhost:5001/playback/start
// header dictionary
{
"x-recording-id": "X"
}
When attempting to use in-memory recording, you cannot submit empty body {}
to /Record/Start
. Doing so will result in an error, as it is expecting a recording file if a body provided.
Of course, feel free to check any of the examples to see actual test code and invocations.
The test-proxy is a record/playback solution. As a result, there a few concepts that devs will likely recognize from other record/playback solutions:
- A
Sanitizer
is used to remove sensitive information prior to storage. Sanitizers are applied...- To the request matching against the recording entries during
playback
mode. - To the recording entries loaded from disk when starting a
playback
session. - To the recording entries before they are saved to disk when stopping a
record
session.
- To the request matching against the recording entries during
Matchers
are used to retrieve a request/response pair from a previous recording. By default, it functions by comparingURI
,Headers
, andBody
. As of now, only a single matcher can be used when retrieving an entry during playback.- A
Transform
is used when a user needs to "transform" a matched recording response with some value from the incoming request. This action is specific toplayback
mode. For instance, the test-proxy has two defaulttransforms
:x-ms-client-id
is copied from request and applied to response prior to return.x-ms-client-request-id
is copied from request and applied to response prior to return.
Default sets of matcher
, transforms
, and sanitizers
are applied during recording and playback. These default settings are all set at the session
level. Customization is allowed for these default sets by accessing the Admin
controller.
When creating a custom sanitizer/matcher/transform, a single constructor must be provided.
This is due to the fact that if there are arguments to the constructor, the body attributes will be mapped by name.
Add a simple Uri Sanitizer that leverages lookahead to ensure it's not overly aggressive:
// POST TO Targeted URI: <proxyURL>/Admin/AddSanitizer
// header dictionary
{
"x-abstraction-identifier": "UriRegexSanitizer"
}
// request body
{
"value": "fakeaccount",
"regex": "[a-z]+(?=\\.(?:table|blob|queue)\\.core\\.windows\\.net)"
}
Add a more expansive Header sanitizer that uses a target group instead of filtering by lookahead:
// POST to URI <proxyURL>/Admin/AddSanitizer
// headers
{
"x-abstraction-identifier": "HeaderRegexSanitizer"
}
// request body
{
"key": "Location",
"value": "fakeaccount",
"regex": "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net",
"groupForReplace": "account"
}
Note: Regex strings are being passed as a member of a JSON object. As visible in the above example, escape characters must be double escaped.
\n
->\\n
.\\
->\\\\
. Read the "string" description on json.org for more detail.
Each sanitizer is optionally prefaced with the specific part of the request/response pair that it applies to. These prefixes are
Uri
Header
Body
A sanitizer that does not include this prefix is something different, and probably applies at the session level instead on an individual request/response pair.
In some cases, users need to register a lot (10+) of sanitizers. In this case, going back and forth with the proxy server individually is not very efficient. To ameliorate this, the proxy honors multiple sanitizers in the same request if the user utilizes /Admin/AddSanitizers
.
// POST to URI <proxyURL>/Admin/AddSanitizers
// note the request body is simply an array of objects
[
{
"Name": "GeneralRegexSanitizer",
"Body": {
"regex": "[a-zA-Z]?",
"value": "hello_there",
"condition": {
"UriRegex": ".+/Tables"
}
}
},
{
"Name": "HeaderRegexSanitizer",
"Body": { // <-- the contents of this property mirror what would be passed in the request body for individual AddSanitizer()
"key": "Location",
"value": "fakeaccount",
"regex": "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net",
"groupForReplace": "account"
}
}
]
When AddSanitizer
or AddSanitizers
is called, check the response body
for an array containing the ids of sanitizers that have been registered.
Example response body:
// POSTS to Admin/AddSanitizer has individual result
{
"Sanitizer": "3"
}
// POSTS to Admin/AddSanitizers has multiple results
{
"Sanitizers": ["3", "4", "9"]
}
Following #8120, sanitizers were given identifiers so that they can be removed.
- The default
session
sanitizers list can be found in code here. - Visiting
http://localhost:5000/Info/Active
on your browser when the proxy is running on your machine will present you with an easy summary of these available sanitizers as well.
When a recording or playback session is begun (Playback/Start
or Record/Start
), all the current session sanitizers are applied to the recording. Session sanitizers added after record or playback has begun do not apply to the prior-started session.
To remove a session-level sanitizer, one only must...
// request method = `POST`
// request URI = <proxyUrl>/Admin/RemoveSanitizers
// request headers =
{
"Content-Type": "application/json",
"Content-Length": 36
}
// request body =
{
Sanitizers: ["AZSDK002", "AZSDK003"]
}
On successful request, users will receive a list of the removed identifiers.
// response body
{
Removed: ["ID1"]
}
To remove a sanitizer from a specific recording...
// request method = `POST`
// request URI = <proxyUrl>/Admin/RemoveSanitizers
// request headers =
{
"Content-Type": "application/json",
"Content-Length": 36,
"x-recording-id": "your-recording-id-here"
}
// request body =
{
Sanitizers: ["AZSDK002", "AZSDK003"]
}
Setting a matcher is just like adding a sanitizer
. Set the x-abstraction-identifier
value to the name of the matcher you want to instantiate, and provide the proper constructor arguments in the body! Check Info/Available/
for available matchers.
// POST to URI <proxyURL>/Admin/SetMatcher
// headers
{
"x-abstraction-identifier": "BodilessMatcher"
}
// request body is just empty JSON for a BodilessMatcher
{}
The default matcher
for test-proxy is usable in most situations. Sanitizers
can be used to clear non-available information prior to saving to disk, and playback tests should ensure that they match the expected values in the recordings. Sanization can usually eliminate the need for custom matching, but in some circumstances this is just not feasible.
If a dev must only change a couple elements of the default matcher, the CustomDefault
matcher is the way to go!
// POST to URI <proxyURL>/Admin/SetMatcher
// headers
{
"x-abstraction-identifier": "CustomDefaultMatcher"
}
// request body
{
// Should the body value be compared during lookup operations?
"compareBodies": true,
// A comma separated list of additional headers that should be excluded during matching. "Excluded" headers are entirely ignored.
"excludedHeaders": "traceparent",
// A comma separated list of additional headers that should be ignored during matching. Any headers that are "ignored" will not do value comparison when matching.
// The "presence" of the headers will still be checked however.
"ignoredHeaders": "User-Agent, Origin, Content-Length",
// By default, the test-proxy does not sort query params before matching. Setting true will sort query params alphabetically before comparing URI.
"ignoredQueryOrdering": false,
// A comma separated list of query parameterse that should be ignored during matching.
"ignoredQueryParameters" "token"
}
Just like sanitizers
and matchers
, select an abstraction-id in header, provide a json body with any arguments/details.
// POST to URI <proxyURL>/Admin/AddTransform
// headers
{
"x-abstraction-identifier": "ApiVersionTransform"
}
// empty request body for ApiVersionTransform
{}
This will add a transform that copies api-version
header from request onto the matched response during playback
.
When invoked as basic requests to the Admin
controller, these settings will be applied to all further requests and responses. Both Playback
and Recording
. Where applicable.
sanitizers
are applied before the recording is saved to disk AND on an incoming request prior to thematch
operation.- A custom
matcher
can be set for a session or individual recording and is applied when retrieving an entry from a loaded recording. Only a single matcher can be honored when matching requests to recorded entries. Registering two matchers one after another will simply result in matching using the last matcher provided. transforms
are applied when returning a request during playback.
Currently, the configured set of transforms/playback/sanitizers are NOT propogated onto disk alongside the recording.
Launch the test-proxy through your chosen method, then visit:
<proxyUrl>/Info/Available
to see all available.<proxyUrl>/Info/Active
to see all currently active for all sessions.
Note that the constructor arguments
that are documented must be present (where documented as such) in the body of the POST sent to the Admin Interface.
This only works while a session is available. A specific session is only available before it has been stopped. Once that happens it has been written to disk or evacuated from server memory.
Example flow
- Start playback for "hello_world.json"
- Receive a recordingId back
- Place a breakpoint before the part of your code that calls
/Record/Stop
orPlayback/Stop
. - Visit the url
<proxyUrl>/Info/Active?id=<your-recording-id>
Given that the test-proxy offers the ability to set up customizations for an entire session or a single recording, it also must provide the ability to reset these settings without entirely restarting the server.
This is allowed through the use of the /Admin/Reset
API. A reset
operation "returns to default".
To reset a session to default customization, POST
to Admin/Reset
.
This API operates exclusively on the Session
level if no recordingId is provided in the header. Any customizations on individual recordings are left untouched.
However, if a recordingId is provided in the header dictionary, the reset operation applies to only that individual recording.
// POST TO url: <proxyURL>/Admin/Reset
// header dictionary
{
"x-recording-id": "<guid>"
}
The session level updates will remain unchanged.
The test-proxy offers further customization beyond that offered by sanitizers, matchers, and transforms. To access this additional functionality, one must POST to /Admin/SetRecordingOptions
with a json body that contains the options.
// below is an object representing all valid inputs for SetRecordingOptions body
// POST to /Admin/SetRecordingOptions
{
// boolean value accepted. string or raw.
"HandleRedirects": "true/false"
// setting context directory will change the "root" path that the test proxy uses when loading a recording
"ContextDirectory": "<valid path on local disk>",
// as yet unused. will allow to swap away from git-backed recording storage
"AssetsStore": "<NullStore/GitStore>",
// customizes some transport settings all or a single recording
"Transport": {
// any number of certificates will be allowed here
"Certificates": [
{
"PemValue": "<string content>",
"PemKey": "<string content>",
}
],
// used specifically so that an SSL connection presenting a non-standard certificate can still be validated
"TLSValidationCert": "<public key portion of TLS cert>",
// if not provided, the TLS Validation validation callbacks will be used for all targeted hosts
// if provided, only requests to the hostname contained herein will be validated against the cert present in TLSValidationCert
"TLSValidationCertHost": "<hostname for the targeted resource associated with TLS Cert>",
}
}
The test-proxy follows redirects by default. That means that if the initial request sent by the test-proxy results in some 3XX
redirect status, it will follow the redirect.
In certain cases, a user will want to utilize both behaviors in their tests. For instance, the javascript browser
tests run with redirect enabled, however for their node
versions, the redirect functionality is explicitly disabled. The test-proxy exposes this as a setting HandleRedirects
within the settings object POST-ed to /Admin/SetRecordingOptions
.
Example:
// POST to URI: https://localhost:5001/Admin/SetRecordingOptions
// body is a json dictionary, the value of HandleRedirects can be multiple representation of "true"
{
"HandleRedirects": true
}
// ...or
{
"HandleRedirects": 1
}
// to disable, it's just the opposite, with similar alternative support
{
"HandleRedirects": false
}
// ...or
{
"HandleRedirects": "false"
}
In normal running, the test-proxy actually sets the Host header automatically. If one wants to provide a specific header that gets used during the request, the request must be accompanied by header:
"x-recording-upstream-host-header": "<host value>"
This project uses Xunit
as the test framework. This is the most popular .NET test solution according to this twitter poll and it's also what the majority of the test projects in the Azure/azure-sdk-tools
repo utilize as well.
The test-proxy server supports SSL, but due to its local-hosted nature, SSL validation will always be an issue without some manual intervention. Real SSL certificates are not available for localhost! As a result of this, if attempting to leverage SSL when recording, some additional setup will be required.
Within this repository there is a single certificate.
eng/common/testproxy/dotnet-devcert.pfx
: generated on aUbuntu
distribution usingopenssl
.
If you get the message dialog The project doesn't know how to run the profile Azure.Sdk.Tools.TestProxy
, you can fix it by reviewing the next two things:
Run Visual Studio installer and make sure ASP.NET and web development is installed.
Then, confirm in the right panel that Development time IIS support
is not checked:
Add Internet Information Services to your Windows installation. Here is the list of features to enable:
The test-proxy
optionally offers integration with other git repositories for storing and retrieving recordings. This enables the proxy to work against repositories that do not emplace their test recordings directly alongside their test implementations.
For further reading about this feature, please refer to the asset-sync documentation folder.