Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Perf Framework] Support multiple test proxies #18031

Merged
merged 7 commits into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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