Integrate Asset-Sync Features (#23405)
* updating create recording request * first draft. need to integrate node tests and then reach out to harsha * commiting prettier update * repair ascension algo * add initial assets.json. update gitignore. * move textanalytics recordings. time to try the node tests! * remaining recorder updates. properly setting the assets.json path now * using a different version of the proxy to ensure that we include all the bugfixes from recently * bunch of changes for RECORDING_ASSETS_PATH * lint applied * Update sdk/test-utils/recorder/src/utils/utils.ts Co-authored-by: Timo van Veenendaal <timov@microsoft.com> * Update sdk/test-utils/recorder/src/utils/createRecordingRequest.ts Co-authored-by: Timo van Veenendaal <timov@microsoft.com> * Update sdk/test-utils/recorder/src/utils/relativePathCalculator.browser.ts Co-authored-by: Timo van Veenendaal <timov@microsoft.com> * Update sdk/test-utils/recorder/src/utils/utils.ts Co-authored-by: Timo van Veenendaal <timov@microsoft.com> * Update sdk/test-utils/recorder/src/utils/utils.ts * Update sdk/test-utils/recorder/src/utils/createRecordingRequest.ts Co-authored-by: Timo van Veenendaal <timov@microsoft.com> * repair imports * linting commit * resolve failing node tests * handle undefined set in environment variable * commit recordings update now that the source has been updated * fix pipeline * if (!fs.existsSync(assetsPath)) return undefined; * format * fix lint * Some refactors; calculate assets path in browser using existing environment variable * Re-add second environment variable * undo assets changes Co-authored-by: Timo van Veenendaal <timov@microsoft.com> Co-authored-by: Harsha Nalluru <sanallur@microsoft.com>
This commit is contained in:
Родитель
9fc4cba9ed
Коммит
312a78f7f5
|
@ -93,7 +93,6 @@ TestResults/*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
./**/.vscode/*
|
./**/.vscode/*
|
||||||
|
|
||||||
|
|
||||||
# Node #
|
# Node #
|
||||||
**/node_modules/
|
**/node_modules/
|
||||||
**/cjs/
|
**/cjs/
|
||||||
|
@ -155,6 +154,9 @@ sdk/cosmosdb/cosmos/lib
|
||||||
*lintReport.html
|
*lintReport.html
|
||||||
tsdoc-metadata.json
|
tsdoc-metadata.json
|
||||||
|
|
||||||
|
# locally cloned assets
|
||||||
|
.assets
|
||||||
|
|
||||||
# autorest generated files
|
# autorest generated files
|
||||||
swagger/*.json
|
swagger/*.json
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// https://github.com/karma-runner/karma-chrome-launcher
|
// https://github.com/karma-runner/karma-chrome-launcher
|
||||||
const { relativeRecordingsPath } = require("./dist/index.js");
|
const { relativeRecordingsPath, relativeAssetsPath } = require("./dist/index.js");
|
||||||
process.env.CHROME_BIN = require("puppeteer").executablePath();
|
process.env.CHROME_BIN = require("puppeteer").executablePath();
|
||||||
require("dotenv").config({ path: "../.env" });
|
require("dotenv").config({ path: "../.env" });
|
||||||
|
|
||||||
process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath();
|
process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath();
|
||||||
|
process.env.RECORDING_ASSETS_PATH = relativeAssetsPath();
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set({
|
||||||
|
@ -49,7 +50,7 @@ module.exports = function (config) {
|
||||||
// inject following environment values into browser testing with window.__env__
|
// inject following environment values into browser testing with window.__env__
|
||||||
// environment values MUST be exported or set with same console running "karma start"
|
// environment values MUST be exported or set with same console running "karma start"
|
||||||
// https://www.npmjs.com/package/karma-env-preprocessor
|
// https://www.npmjs.com/package/karma-env-preprocessor
|
||||||
envPreprocessor: ["RECORDINGS_RELATIVE_PATH", "PROXY_MANUAL_START"],
|
envPreprocessor: ["RECORDINGS_RELATIVE_PATH", "PROXY_MANUAL_START", "RECORDING_ASSETS_PATH"],
|
||||||
|
|
||||||
// test results reporter to use
|
// test results reporter to use
|
||||||
// possible values: 'dots', 'progress'
|
// possible values: 'dots', 'progress'
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
export { Recorder } from "./recorder";
|
export { Recorder } from "./recorder";
|
||||||
export { relativeRecordingsPath } from "./utils/relativePathCalculator";
|
export { relativeRecordingsPath, relativeAssetsPath } from "./utils/relativePathCalculator";
|
||||||
export {
|
export {
|
||||||
SanitizerOptions,
|
SanitizerOptions,
|
||||||
RecorderStartOptions,
|
RecorderStartOptions,
|
||||||
|
|
|
@ -42,6 +42,7 @@ import { setRecordingOptions } from "./options";
|
||||||
import { isNode } from "@azure/core-util";
|
import { isNode } from "@azure/core-util";
|
||||||
import { env } from "./utils/env";
|
import { env } from "./utils/env";
|
||||||
import { decodeBase64 } from "./utils/encoding";
|
import { decodeBase64 } from "./utils/encoding";
|
||||||
|
import { relativeAssetsPath } from "./utils/relativePathCalculator";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This client manages the recorder life cycle and interacts with the proxy-tool to do the recording,
|
* This client manages the recorder life cycle and interacts with the proxy-tool to do the recording,
|
||||||
|
@ -60,6 +61,7 @@ export class Recorder {
|
||||||
private stateManager = new RecordingStateManager();
|
private stateManager = new RecordingStateManager();
|
||||||
private httpClient?: HttpClient;
|
private httpClient?: HttpClient;
|
||||||
private sessionFile?: string;
|
private sessionFile?: string;
|
||||||
|
private assetsJson?: string;
|
||||||
private variables: Record<string, string>;
|
private variables: Record<string, string>;
|
||||||
|
|
||||||
constructor(private testContext?: Test | undefined) {
|
constructor(private testContext?: Test | undefined) {
|
||||||
|
@ -67,6 +69,8 @@ export class Recorder {
|
||||||
if (isRecordMode() || isPlaybackMode()) {
|
if (isRecordMode() || isPlaybackMode()) {
|
||||||
if (this.testContext) {
|
if (this.testContext) {
|
||||||
this.sessionFile = sessionFilePath(this.testContext);
|
this.sessionFile = sessionFilePath(this.testContext);
|
||||||
|
this.assetsJson = relativeAssetsPath();
|
||||||
|
|
||||||
logger.info(`[Recorder#constructor] Using a session file located at ${this.sessionFile}`);
|
logger.info(`[Recorder#constructor] Using a session file located at ${this.sessionFile}`);
|
||||||
this.httpClient = createDefaultHttpClient();
|
this.httpClient = createDefaultHttpClient();
|
||||||
} else {
|
} else {
|
||||||
|
@ -214,7 +218,14 @@ export class Recorder {
|
||||||
const startUri = `${Recorder.url}${isPlaybackMode() ? paths.playback : paths.record}${
|
const startUri = `${Recorder.url}${isPlaybackMode() ? paths.playback : paths.record}${
|
||||||
paths.start
|
paths.start
|
||||||
}`;
|
}`;
|
||||||
const req = createRecordingRequest(startUri, this.sessionFile, this.recordingId);
|
|
||||||
|
const req = createRecordingRequest(
|
||||||
|
startUri,
|
||||||
|
this.sessionFile,
|
||||||
|
this.recordingId,
|
||||||
|
"POST",
|
||||||
|
this.assetsJson
|
||||||
|
);
|
||||||
|
|
||||||
if (ensureExistence(this.httpClient, "TestProxyHttpClient.httpClient")) {
|
if (ensureExistence(this.httpClient, "TestProxyHttpClient.httpClient")) {
|
||||||
logger.verbose("[Recorder#start] Setting redirect mode");
|
logger.verbose("[Recorder#start] Setting redirect mode");
|
||||||
|
@ -271,6 +282,7 @@ export class Recorder {
|
||||||
const stopUri = `${Recorder.url}${isPlaybackMode() ? paths.playback : paths.record}${
|
const stopUri = `${Recorder.url}${isPlaybackMode() ? paths.playback : paths.record}${
|
||||||
paths.stop
|
paths.stop
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const req = createRecordingRequest(stopUri, undefined, this.recordingId);
|
const req = createRecordingRequest(stopUri, undefined, this.recordingId);
|
||||||
req.headers.set("x-recording-save", "true");
|
req.headers.set("x-recording-save", "true");
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,26 @@ export function createRecordingRequest(
|
||||||
url: string,
|
url: string,
|
||||||
sessionFile?: string,
|
sessionFile?: string,
|
||||||
recordingId?: string,
|
recordingId?: string,
|
||||||
method: HttpMethods = "POST"
|
method: HttpMethods = "POST",
|
||||||
|
assetsJson?: string
|
||||||
) {
|
) {
|
||||||
const req = createPipelineRequest({ url: url, method });
|
const req = createPipelineRequest({ url: url, method });
|
||||||
|
|
||||||
if (sessionFile !== undefined) {
|
if (sessionFile !== undefined) {
|
||||||
req.body = JSON.stringify({ "x-recording-file": sessionFile });
|
const body: Record<string, string> = { "x-recording-file": sessionFile };
|
||||||
|
|
||||||
|
// during browser tests the non-presence of an assets.json will result in the value "undefined" being set
|
||||||
|
// its easier to just explicitly handle this case rather than ensure that folks update their karma conf properly.
|
||||||
|
if (assetsJson && assetsJson !== "undefined") {
|
||||||
|
body["x-recording-assets-file"] = assetsJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.body = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recordingId !== undefined) {
|
if (recordingId !== undefined) {
|
||||||
req.headers.set("x-recording-id", recordingId);
|
req.headers.set("x-recording-id", recordingId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,42 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
export function relativeRecordingsPath(): never {
|
import { env } from "./env";
|
||||||
throw new Error("Attempted to use the function meant for node in a browser.");
|
import { RecorderError } from "./utils";
|
||||||
|
|
||||||
|
export function relativeRecordingsPath(): string {
|
||||||
|
if (env.RECORDINGS_RELATIVE_PATH) {
|
||||||
|
return env.RECORDINGS_RELATIVE_PATH;
|
||||||
|
} else {
|
||||||
|
throw new RecorderError(
|
||||||
|
"RECORDINGS_RELATIVE_PATH was not set while in browser mode. Ensure that process.env.RELATIVE_RECORDINGS_PATH has been set properly in your Karma configuration."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ONLY WORKS IN THE NODE.JS ENVIRONMENT
|
||||||
|
*
|
||||||
|
* Returns the potential assets.json for the project using `process.cwd()`.
|
||||||
|
*
|
||||||
|
* Note for browser tests:
|
||||||
|
* 1. Supposed to be called from karma.conf.js in the package for which the testing is being done.
|
||||||
|
* 2. Set this `RECORDING_ASSETS_PATH` as an env variable
|
||||||
|
* ```js
|
||||||
|
* const { relativeRecordingsPathForBrowser } = require("@azure-tools/test-recorder-new");
|
||||||
|
* process.env.RECORDING_ASSETS_PATH = relativeRecordingsPathForBrowser();
|
||||||
|
* ```
|
||||||
|
* 3. Add "RECORDING_ASSETS_PATH" in the `envPreprocessor` array to let this be loaded in the browser environment.
|
||||||
|
* ```
|
||||||
|
* envPreprocessor: ["RECORDING_ASSETS_PATH"],
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* `RECORDING_ASSETS_PATH` in the browser environment is used in the recorder to tell the proxy-tool about whether or not to pass additional body argument
|
||||||
|
* `x-recording-assets-file` to playback|record/Start. Doing so enables the proxy to auto-restore files from a remote location.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @returns {string} location of the relative path to discovered assets.json - `sdk/storage/storage-blob/assets.json` for example.
|
||||||
|
*/
|
||||||
|
export function relativeAssetsPath(): string | undefined {
|
||||||
|
return env.RECORDING_ASSETS_PATH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,28 +6,19 @@ import fs from "fs";
|
||||||
import { RecorderError } from "./utils";
|
import { RecorderError } from "./utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ONLY WORKS IN THE NODE.JS ENVIRONMENT
|
* Replace backslashes in a path with forward slashes so they are not treated as escape characters
|
||||||
*
|
* in the browser tests.
|
||||||
* Returns the potential `recordings` folder(relative path) for the project using `process.cwd()`.
|
* @param filePath The path to replace
|
||||||
*
|
* @returns A path without backslashes
|
||||||
* Note for browser tests:
|
|
||||||
* 1. Supposed to be called from karma.conf.js in the package for which the testing is being done.
|
|
||||||
* 2. Set this `RECORDINGS_RELATIVE_PATH` as an env variable
|
|
||||||
* ```js
|
|
||||||
* const { relativeRecordingsPathForBrowser } = require("@azure-tools/test-recorder-new");
|
|
||||||
* process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPathForBrowser();
|
|
||||||
* ```
|
|
||||||
* 3. Add "RECORDINGS_RELATIVE_PATH" in the `envPreprocessor` array to let this be loaded in the browser environment.
|
|
||||||
* ```
|
|
||||||
* envPreprocessor: ["RECORDINGS_RELATIVE_PATH"],
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* `RECORDINGS_RELATIVE_PATH` in the browser environment is used in the recorder to tell the proxy-tool about the location to generate the browser recordings at.
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @returns {string} location of the relative `recordings` folder path - `sdk/storage/storage-blob/recordings/` example
|
|
||||||
*/
|
*/
|
||||||
export function relativeRecordingsPath(): string {
|
function toSafePath(filePath: string): string {
|
||||||
|
return filePath.split(path.sep).join(path.posix.sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the path of the package being tested relative to the repository root.
|
||||||
|
*/
|
||||||
|
function relativePackagePath() {
|
||||||
const currentPath = process.cwd(); // Gives the current working directory
|
const currentPath = process.cwd(); // Gives the current working directory
|
||||||
|
|
||||||
let rootPath = undefined;
|
let rootPath = undefined;
|
||||||
|
@ -53,14 +44,61 @@ export function relativeRecordingsPath(): string {
|
||||||
if (!(rootPath === undefined || expectedProjectPath === undefined)) {
|
if (!(rootPath === undefined || expectedProjectPath === undefined)) {
|
||||||
// <root>/
|
// <root>/
|
||||||
// <root>/sdk/service/project/
|
// <root>/sdk/service/project/
|
||||||
return path
|
// => sdk/service/project
|
||||||
.join(path.relative(rootPath, expectedProjectPath), "recordings")
|
return path.relative(rootPath, expectedProjectPath);
|
||||||
.split(path.sep)
|
|
||||||
.join(path.posix.sep); // Converting "\" to "/" (needed for windows) so that the path.sep("\") is not treated as an escape character in the browsers
|
|
||||||
// => sdk/service/project/recordings
|
|
||||||
} else {
|
} else {
|
||||||
throw new RecorderError(
|
throw new RecorderError(
|
||||||
"rootPath or expectedProjectPath could not be calculated properly from process.cwd()"
|
"rootPath or expectedProjectPath could not be calculated properly from process.cwd()"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the potential `recordings` folder(relative path) for the project using `process.cwd()`.
|
||||||
|
*
|
||||||
|
* Note for browser tests:
|
||||||
|
* 1. Supposed to be called from karma.conf.js in the package for which the testing is being done.
|
||||||
|
* 2. Set this `RECORDINGS_RELATIVE_PATH` as an env variable
|
||||||
|
* ```js
|
||||||
|
* const { relativeRecordingsPathForBrowser } = require("@azure-tools/test-recorder-new");
|
||||||
|
* process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPathForBrowser();
|
||||||
|
* ```
|
||||||
|
* 3. Add "RECORDINGS_RELATIVE_PATH" in the `envPreprocessor` array to let this be loaded in the browser environment.
|
||||||
|
* ```
|
||||||
|
* envPreprocessor: ["RECORDINGS_RELATIVE_PATH"],
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* `RECORDINGS_RELATIVE_PATH` in the browser environment is used in the recorder to tell the proxy-tool about the location to generate the browser recordings at.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @returns {string} location of the relative `recordings` folder path - `sdk/storage/storage-blob/recordings/` example
|
||||||
|
*/
|
||||||
|
export function relativeRecordingsPath(): string {
|
||||||
|
return toSafePath(path.join(relativePackagePath(), "recordings"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the potential assets.json for the project using `process.cwd()`.
|
||||||
|
*
|
||||||
|
* Note for browser tests:
|
||||||
|
* 1. Supposed to be called from karma.conf.js in the package for which the testing is being done.
|
||||||
|
* 2. Set this `RECORDING_ASSETS_PATH` as an env variable
|
||||||
|
* ```js
|
||||||
|
* const { relativeRecordingsPathForBrowser } = require("@azure-tools/test-recorder-new");
|
||||||
|
* process.env.RECORDING_ASSETS_PATH = relativeRecordingsPathForBrowser();
|
||||||
|
* ```
|
||||||
|
* 3. Add "RECORDING_ASSETS_PATH" in the `envPreprocessor` array to let this be loaded in the browser environment.
|
||||||
|
* ```
|
||||||
|
* envPreprocessor: ["RECORDING_ASSETS_PATH"],
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* `RECORDING_ASSETS_PATH` in the browser environment is used in the recorder to tell the proxy-tool about whether or not to pass additional body argument
|
||||||
|
* `x-recording-assets-file` to playback|record/Start. Doing so enables the proxy to auto-restore files from a remote location.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @returns {string} location of the relative path to discovered assets.json - `sdk/storage/storage-blob/assets.json` for example, or undefined if the path does not exist
|
||||||
|
*/
|
||||||
|
export function relativeAssetsPath(): string | undefined {
|
||||||
|
const assetsJsonPath = path.join(relativePackagePath(), "assets.json");
|
||||||
|
return fs.existsSync(assetsJsonPath) ? toSafePath(assetsJsonPath) : undefined;
|
||||||
|
}
|
||||||
|
|
|
@ -2,25 +2,13 @@
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
import { isNode } from "@azure/core-util";
|
import { isNode } from "@azure/core-util";
|
||||||
import { env } from "./env";
|
|
||||||
import { generateTestRecordingFilePath } from "./filePathGenerator";
|
import { generateTestRecordingFilePath } from "./filePathGenerator";
|
||||||
import { relativeRecordingsPath } from "./relativePathCalculator";
|
import { relativeRecordingsPath } from "./relativePathCalculator";
|
||||||
import { RecorderError } from "./utils";
|
import { RecorderError } from "./utils";
|
||||||
|
|
||||||
export function sessionFilePath(testContext: Mocha.Test): string {
|
export function sessionFilePath(testContext: Mocha.Test): string {
|
||||||
let recordingsFolder: string;
|
|
||||||
if (isNode) {
|
|
||||||
recordingsFolder = relativeRecordingsPath(); // sdk/service/project/recordings
|
|
||||||
} else if (env.RECORDINGS_RELATIVE_PATH) {
|
|
||||||
recordingsFolder = env.RECORDINGS_RELATIVE_PATH;
|
|
||||||
} else {
|
|
||||||
throw new RecorderError(
|
|
||||||
"RECORDINGS_RELATIVE_PATH was not set while in browser mode. Ensure that process.env.RELATIVE_RECORDINGS_PATH has been set properly in your Karma configuration."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${recordingsFolder}/${recordingFilePath(testContext)}`;
|
|
||||||
// sdk/service/project/recordings/{node|browsers}/<describe-block-title>/recording_<test-title>.json
|
// sdk/service/project/recordings/{node|browsers}/<describe-block-title>/recording_<test-title>.json
|
||||||
|
return `${relativeRecordingsPath()}/${recordingFilePath(testContext)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
import { env } from "./env";
|
import { env } from "./env";
|
||||||
/**
|
/**
|
||||||
* A custom error type for failed pipeline requests.
|
* A custom error type for failed pipeline requests.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче