Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
19 changes: 13 additions & 6 deletions sdk/test-utils/recorder/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The new recorder is version 2.0.0 of the `@azure-tools/test-recorder` package. U
// ...
"devDependencies": {
// ...
"@azure-tools/test-recorder": "^2.0.0",
"@azure-tools/test-recorder": "^2.0.0"
}
}
```
Expand Down Expand Up @@ -152,23 +152,30 @@ In this example, the name of the queue used in the recording is randomized. Howe

A powerful feature of the legacy recorder was its `customizationsOnRecordings` option, which allowed for arbitrary replacements to be made to recordings. The new recorder's analog to this is the sanitizer functionality.

### GeneralRegexSanitizer
### General sanitizers

For a simple find/replace, a `GeneralRegexSanitizer` can be used. For example:
For a simple find/replace, `generalSanitizers` can be used. For example:

```ts
await recorder.addSanitizers({
generalRegexSanitizers: [
generalSanitizers: [
Comment thread
HarshaNalluru marked this conversation as resolved.
{
regex: "find", // This should be a .NET regular expression as it is passed to the .NET proxy tool
target: "find", // With `regex` unspecified, this matches a plaintext string
value: "replace",
},
{
regex: true, // Enable regex matching
target: "[Rr]egex", // This is a .NET regular expression that will be compiled by the proxy tool.
value: "replace",
},
// add additional sanitizers here as required
],
});
```

This example would replace all instances of `find` in the recording with `replace`.
This example has two sanitizers:
- The first sanitizer replaces all instances of "find" in the recording with "replace".
- The second example demonstrates the use of a regular expression for replacement, where anything matching the .NET regular expression `[Rr]egex` (i.e. "Regex" and "regex") would be replaced with "replace".

### ConnectionStringSanitizer

Expand Down
52 changes: 26 additions & 26 deletions sdk/test-utils/recorder/src/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

import {
createDefaultHttpClient,
createPipelineRequest,
HttpClient,
HttpMethods,
Pipeline,
PipelinePolicy,
PipelineRequest,
Expand All @@ -27,7 +25,7 @@ import { Test } from "mocha";
import { sessionFilePath } from "./utils/sessionFilePath";
import { SanitizerOptions } from "./utils/utils";
import { paths } from "./utils/paths";
import { Sanitizer } from "./sanitizer";
import { addSanitizers, transformsInfo } from "./sanitizer";
import { handleEnvSetup } from "./utils/envSetupForPlayback";
import { Matcher, setMatcher } from "./matcher";
import {
Expand All @@ -37,6 +35,7 @@ import {
WebResource,
WebResourceLike,
} from "@azure/core-http";
import { createRecordingRequest } from "./utils/createRecordingRequest";

/**
* This client manages the recorder life cycle and interacts with the proxy-tool to do the recording,
Expand All @@ -55,7 +54,6 @@ export class Recorder {
private stateManager = new RecordingStateManager();
private httpClient?: HttpClient;
private sessionFile?: string;
private sanitizer?: Sanitizer;
private variables: Record<string, string>;

constructor(private testContext?: Test | undefined) {
Expand All @@ -68,7 +66,6 @@ export class Recorder {
"Unable to determine the recording file path, testContext provided is not defined."
);
}
this.sanitizer = new Sanitizer(this.url, this.httpClient);
}
this.variables = {};
}
Expand Down Expand Up @@ -113,8 +110,12 @@ export class Recorder {
*/
async addSanitizers(options: SanitizerOptions): Promise<void> {
// If check needed because we only sanitize when the recording is being generated, and we need a recording to apply the sanitizers on.
if (isRecordMode() && ensureExistence(this.sanitizer, "this.sanitizer")) {
return this.sanitizer.addSanitizers(options);
if (
isRecordMode() &&
ensureExistence(this.httpClient, "this.httpClient") &&
ensureExistence(this.recordingId, "this.recordingId")
) {
return addSanitizers(this.httpClient, this.url, this.recordingId, options);
}
}

Expand All @@ -135,7 +136,7 @@ export class Recorder {
const startUri = `${this.url}${isPlaybackMode() ? paths.playback : paths.record}${
paths.start
}`;
const req = this._createRecordingRequest(startUri);
const req = createRecordingRequest(startUri, this.sessionFile, this.recordingId);

if (ensureExistence(this.httpClient, "TestProxyHttpClient.httpClient")) {
const rsp = await this.httpClient.sendRequest({
Expand All @@ -153,12 +154,14 @@ export class Recorder {
if (isPlaybackMode()) {
this.variables = rsp.bodyAsText ? JSON.parse(rsp.bodyAsText) : {};
}
if (ensureExistence(this.sanitizer, "TestProxyHttpClient.sanitizer")) {
// Setting the recordingId in the sanitizer,
// the sanitizers added will take the recording id and only be part of the current test
this.sanitizer.setRecordingId(this.recordingId);
await handleEnvSetup(options.envSetupForPlayback, this.sanitizer);
}

await handleEnvSetup(
this.httpClient,
this.url,
this.recordingId,
options.envSetupForPlayback
);

// Sanitizers to be added only in record mode
if (isRecordMode() && options.sanitizerOptions) {
// Makes a call to the proxy-tool to add the sanitizers for the current recording id
Expand All @@ -177,7 +180,7 @@ export class Recorder {
this.stateManager.state = "stopped";
if (this.recordingId !== undefined) {
const stopUri = `${this.url}${isPlaybackMode() ? paths.playback : paths.record}${paths.stop}`;
const req = this._createRecordingRequest(stopUri);
const req = createRecordingRequest(stopUri, undefined, this.recordingId);
req.headers.set("x-recording-save", "true");

if (isRecordMode()) {
Expand Down Expand Up @@ -211,19 +214,16 @@ export class Recorder {
}
}

/**
* Adds the recording file and the recording id headers to the requests that are sent to the proxy tool.
* These are required to appropriately save the recordings in the record mode and picking them up in playback.
*/
private _createRecordingRequest(url: string, method: HttpMethods = "POST") {
const req = createPipelineRequest({ url, method });
if (ensureExistence(this.sessionFile, "sessionFile")) {
req.body = JSON.stringify({ "x-recording-file": this.sessionFile });
async transformsInfo(): Promise<string | null | undefined> {
if (isLiveMode()) {
throw new RecorderError("Cannot call transformsInfo in live mode");
}
if (this.recordingId !== undefined) {
req.headers.set("x-recording-id", this.recordingId);

if (ensureExistence(this.httpClient, "this.httpClient")) {
return await transformsInfo(this.httpClient, this.url, this.recordingId!);
}
return req;

throw new RecorderError("Expected httpClient to be defined");
Comment thread
timovv marked this conversation as resolved.
}

/**
Expand Down
Loading