Skip to content

Commit

Permalink
[Perf Framework] Support multiple test proxies (Azure#18031)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeharder authored Oct 6, 2021
1 parent 5022248 commit d54a817
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 19 deletions.
5 changes: 5 additions & 0 deletions sdk/test-utils/perfstress/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## 1.0.0 (Unreleased)

### 2021-10-05

- Support multiple test proxies
[#18031](https://github.com/Azure/azure-sdk-for-js/pull/18031)

### 2021-10-01

- Calls runAsync() once before starting recording, to avoid capturing one-time setup like authorization requests.
Expand Down
12 changes: 6 additions & 6 deletions sdk/test-utils/perfstress/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,21 +291,21 @@ Run this command

Reference: https://github.com/Azure/azure-sdk-tools/tree/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy#via-docker-image

To use the proxy-tool in your test pass this option in cli `--test-proxy http://localhost:5000`(Make sure the port is same as what you have used to run the `docker run` command).
To use the proxy-tool in your test pass this option in cli `--test-proxies http://localhost:5000`(Make sure the port is same as what you have used to run the `docker run` command).

Sample command(using storage-blob perf tests as example (Core-v1)!)

> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --test-proxy http://localhost:5000
> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --test-proxies http://localhost:5000
> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --parallel 2 --test-proxy http://localhost:5000
> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --parallel 2 --test-proxies http://localhost:5000
> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --parallel 2 --test-proxy https://localhost:5001 --insecure true
> npm run perf-test:node -- StorageBlobDownloadTest --warmup 2 --duration 7 --iterations 2 --parallel 2 --test-proxies https://localhost:5001 --insecure true
Sample command(using data-tables perf tests as example (Core-v2)!)

> npm run perf-test:node -- ListComplexEntitiesTest --duration 7 --iterations 2 --parallel 2 --test-proxy http://localhost:5000
> npm run perf-test:node -- ListComplexEntitiesTest --duration 7 --iterations 2 --parallel 2 --test-proxies http://localhost:5000
> npm run perf-test:node -- ListComplexEntitiesTest --duration 7 --iterations 2 --parallel 2 --test-proxy https://localhost:5001 --insecure true
> npm run perf-test:node -- ListComplexEntitiesTest --duration 7 --iterations 2 --parallel 2 --test-proxies https://localhost:5001 --insecure true
> npm run perf-test:node -- ListComplexEntitiesTest --duration 7 --iterations 2 --parallel 2
Expand Down
2 changes: 1 addition & 1 deletion sdk/test-utils/perfstress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Link to the wiki - [Writing-Performance-Tests](https://github.com/Azure/azure-sd
- PerfStress tests are executed as many times as possible until the `duration` parameter is specified. This process may repeat as many `iterations` are given. Before each iteration, tests might be called for a period of time up to `warmup`, to adjust to possible runtime optimizations. In each iteration, as many as `parallel` instances of the same test are called without waiting for each other, letting the event loop decide which one is prioritized (it's not true parallelism, but it's an approximation that aligns with the design in other languages, we might improve it over time).
- Each test can have a `globalSetup` method, which is called once before the process begins, a `globalCleanup` method, which is called once after the process finishes.
- Each test can have a `setup` method, which is called as many times as test instances are created (up to `parallel`), and help specify local state for each test instance. A `cleanup` method is also optional, called the same amount of times, but after finishing running the tests.
- `test-proxy` url option - this option can be leveraged to avoid hitting throttling scenarios while testing the services. This option lets the requests go through the proxy server based on the url provided, we run runAsync method once in record mode to save the requests and responses in memory and then a ton of times in playback. Workflow with the test-proxy below.
- `test-proxies` url option - this option can be leveraged to avoid hitting throttling scenarios while testing the services. This option lets the requests go through proxy server(s) based on the url(s) provided, we run runAsync method once in record mode to save the requests and responses in memory and then a ton of times in playback. Workflow with the test-proxies below.

## Workflow with test proxy

Expand Down
8 changes: 4 additions & 4 deletions sdk/test-utils/perfstress/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export interface DefaultPerfStressOptions {
iterations: number;
"no-cleanup": boolean;
"milliseconds-to-log": number;
"test-proxy": string;
"test-proxies": string;
insecure: boolean;
}

Expand Down Expand Up @@ -101,13 +101,13 @@ export const defaultPerfStressOptions: PerfStressOptionDictionary<DefaultPerfStr
"no-cleanup": {
description: "Disables test cleanup"
},
"test-proxy": {
description: "URI of TestProxy server",
"test-proxies": {
description: "URIs of TestProxy servers (separated by ';')",
defaultValue: undefined
},
insecure: {
description:
"Applied when test-proxy option is defined, connects with https(insecurely by disabling SSL validation)",
"Applied when test-proxies option is defined, connects with https(insecurely by disabling SSL validation)",
shortName: "ins",
defaultValue: false
},
Expand Down
4 changes: 2 additions & 2 deletions sdk/test-utils/perfstress/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export class PerfStressProgram {
}
}

if (this.tests[0].parsedOptions["test-proxy"].value) {
if (this.tests[0].parsedOptions["test-proxies"].value) {
// Records requests(in runAsync method) for all the instantiated PerfStressTest classes,
// and asks the proxy-tool to start playing back for future requests.
await Promise.all(this.tests.map((test) => this.recordAndStartPlayback(test)));
Expand All @@ -301,7 +301,7 @@ export class PerfStressProgram {
await this.runTest(i, Number(options.duration.value), "test");
}

if (this.tests[0].parsedOptions["test-proxy"].value) {
if (this.tests[0].parsedOptions["test-proxies"].value) {
await Promise.all(this.tests.map((test) => this.stopPlayback(test)));
}

Expand Down
26 changes: 20 additions & 6 deletions sdk/test-utils/perfstress/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,25 @@ export interface PerfStressTestConstructor<TOptions extends {} = {}> {
* (initializations are as many as the "parallel" command line parameter specifies).
*/
export abstract class PerfStressTest<TOptions = {}> {
private readonly testProxy!: string;
public testProxyHttpClient!: TestProxyHttpClient;
public testProxyHttpClientV1!: TestProxyHttpClientV1;
public abstract options: PerfStressOptionDictionary<TOptions>;

private static globalParallelIndex: number = 0;
protected readonly parallelIndex: number;

public constructor() {
this.parallelIndex = PerfStressTest.globalParallelIndex;
PerfStressTest.globalParallelIndex++;

const testProxies = this.parsedOptions["test-proxies"].value;
if (testProxies) {
const testProxiesArray = testProxies.split(";");
this.testProxy = testProxiesArray[this.parallelIndex % testProxiesArray.length];
}
}

public get parsedOptions(): PerfStressOptionDictionary<TOptions & DefaultPerfStressOptions> {
// This cast is needed because TS thinks
// PerfStressOptionDictionary<TOptions & DefaultPerfStressOptions>
Expand Down Expand Up @@ -67,9 +82,9 @@ export abstract class PerfStressTest<TOptions = {}> {
* Note: httpClient must be part of the options bag, it is required for the perf framework to update the underlying client properly
*/
public configureClientOptionsCoreV1<T>(options: T & { httpClient?: HttpClient }): T {
if (this.parsedOptions["test-proxy"].value) {
if (this.testProxy) {
this.testProxyHttpClientV1 = new TestProxyHttpClientV1(
this.parsedOptions["test-proxy"].value,
this.testProxy,
this.parsedOptions["insecure"].value!
);
options.httpClient = this.testProxyHttpClientV1;
Expand All @@ -86,16 +101,15 @@ export abstract class PerfStressTest<TOptions = {}> {
* Note: Client must expose the pipeline property which is required for the perf framework to add its policies correctly
*/
public configureClient<T>(client: T & { pipeline: Pipeline }): T {
const url = this.parsedOptions["test-proxy"].value;
if (url) {
if (this.testProxy) {
this.testProxyHttpClient = new TestProxyHttpClient(
url,
this.testProxy,
this.parsedOptions["insecure"].value!
);
client.pipeline.addPolicy(
testProxyHttpPolicy(
this.testProxyHttpClient,
url.startsWith("https"),
this.testProxy.startsWith("https"),
this.parsedOptions["insecure"].value!
)
);
Expand Down

0 comments on commit d54a817

Please sign in to comment.