Skip to content

Commit

Permalink
feat: generate "X-Request-ID" header for each browser request
Browse files Browse the repository at this point in the history
  • Loading branch information
DudaGod committed Dec 25, 2023
1 parent 2abd043 commit b5a8ae4
Show file tree
Hide file tree
Showing 23 changed files with 248 additions and 98 deletions.
3 changes: 1 addition & 2 deletions src/browser-pool/basic-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ module.exports = class BasicPool extends Pool {
}

async getBrowser(id, opts = {}) {
const { version } = opts;
const browser = Browser.create(this._config, id, version);
const browser = Browser.create(this._config, { ...opts, id });

try {
await browser.init();
Expand Down
22 changes: 16 additions & 6 deletions src/browser/browser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

const crypto = require("crypto");
const _ = require("lodash");
const { SAVE_HISTORY_MODE } = require("../constants/config");
const history = require("./history");
Expand All @@ -19,13 +20,14 @@ const CUSTOM_SESSION_OPTS = [
];

module.exports = class Browser {
static create(config, id, version) {
return new this(config, id, version);
static create(config, opts) {
return new this(config, opts);
}

constructor(config, id, version) {
this.id = id;
this.version = version;
constructor(config, opts) {
this.id = opts.id;
this.version = opts.version;
this.testXReqId = opts.testXReqId;

this._config = config.forBrowser(this.id);
this._debug = config.system.debug;
Expand Down Expand Up @@ -82,7 +84,15 @@ module.exports = class Browser {

_getSessionOptsFromConfig(optNames = CUSTOM_SESSION_OPTS) {
return optNames.reduce((options, optName) => {
if (!_.isNull(this._config[optName])) {
if (optName === "transformRequest") {
options[optName] = req => {
if (!req.headers["X-Request-ID"]) {
req.headers["X-Request-ID"] = `${this.testXReqId}_${crypto.randomUUID()}`;
}

return !_.isNull(this._config[optName]) ? this._config[optName](req) : req;
};
} else if (!_.isNull(this._config[optName])) {
options[optName] = this._config[optName];
}

Expand Down
19 changes: 12 additions & 7 deletions src/browser/existing-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ const { isSupportIsolation } = require("../utils/browser");
const OPTIONAL_SESSION_OPTS = ["transformRequest", "transformResponse"];

module.exports = class ExistingBrowser extends Browser {
static create(config, id, version, emitter) {
return new this(config, id, version, emitter);
static create(config, opts) {
return new this(config, opts);
}

constructor(config, id, version, emitter) {
super(config, id, version);
constructor(config, opts) {
super(config, opts);

this._emitter = emitter;
this._emitter = opts.emitter;
this._camera = Camera.create(this._config.screenshotMode, () => this._takeScreenshot());

this._meta = this._initMeta();
Expand Down Expand Up @@ -166,12 +166,17 @@ module.exports = class ExistingBrowser extends Browser {
}

_initMeta() {
return {
const meta = {
pid: process.pid,
browserVersion: this.version,
"X-Request-ID": this._config.headers["X-Request-ID"],
...this._config.meta,
};

if (!meta.testXReqId && !_.get(this._config.headers, "X-Request-ID")) {
meta.testXReqId = this.testXReqId;
}

return meta;
}

_takeScreenshot() {
Expand Down
4 changes: 2 additions & 2 deletions src/browser/new-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const headlessBrowserOptions = {
};

module.exports = class NewBrowser extends Browser {
constructor(config, id, version) {
super(config, id, version);
constructor(config, opts) {
super(config, opts);

signalHandler.on("exit", () => this.quit());
}
Expand Down
6 changes: 3 additions & 3 deletions src/runner/browser-agent.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use strict";

module.exports = class BrowserAgent {
static create(id, version, pool) {
return new this(id, version, pool);
static create(opts = {}) {
return new this(opts);
}

constructor(id, version, pool) {
constructor({ id, version, pool }) {
this.browserId = id;

this._version = version;
Expand Down
6 changes: 5 additions & 1 deletion src/runner/browser-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ export class BrowserRunner extends Runner {
}

private async _runTest(test: Test): Promise<void> {
const browserAgent = BrowserAgent.create(this._browserId, test.browserVersion, this.browserPool);
const browserAgent = BrowserAgent.create({
id: this._browserId,
version: test.browserVersion,
pool: this.browserPool,
});
const runner = TestRunner.create(test, this.config, browserAgent);

runner.on(MasterEvents.TEST_BEGIN, (test: Test) => this.suiteMonitor.testBegin(test));
Expand Down
4 changes: 3 additions & 1 deletion src/runner/test-runner/regular-test-runner.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

const crypto = require("crypto");
const _ = require("lodash");
const { Runner } = require("../runner");
const logger = require("../../utils/logger");
Expand Down Expand Up @@ -64,6 +65,7 @@ module.exports = class RegularTestRunner extends Runner {
sessionCaps: this._browser.capabilities,
sessionOpts: this._browser.publicAPI.options,
file: this._test.file,
testXReqId: this._browser.testXReqId,
});
}

Expand All @@ -80,7 +82,7 @@ module.exports = class RegularTestRunner extends Runner {

async _getBrowser() {
try {
this._browser = await this._browserAgent.getBrowser();
this._browser = await this._browserAgent.getBrowser({ testXReqId: crypto.randomUUID() });
this._test.sessionId = this._browser.sessionId;

return this._browser;
Expand Down
1 change: 1 addition & 0 deletions src/worker/hermione.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface WorkerRunTestOpts {
sessionId: string;
sessionCaps: WdioBrowser["capabilities"];
sessionOpts: WdioBrowser["options"];
testXReqId: string;
}

export interface AssertViewResultsSuccess {
Expand Down
13 changes: 7 additions & 6 deletions src/worker/runner/browser-agent.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
"use strict";

module.exports = class BrowserAgent {
static create(browserId, browserVersion, pool) {
return new BrowserAgent(browserId, browserVersion, pool);
static create(opts) {
return new this(opts);
}

constructor(browserId, browserVersion, pool) {
this.browserId = browserId;
this.browserVersion = browserVersion;
constructor({ id, version, pool }) {
this.browserId = id;
this.browserVersion = version;

this._pool = pool;
}

getBrowser({ sessionId, sessionCaps, sessionOpts }) {
getBrowser({ sessionId, sessionCaps, sessionOpts, testXReqId }) {
return this._pool.getBrowser({
browserId: this.browserId,
browserVersion: this.browserVersion,
sessionId,
sessionCaps,
sessionOpts,
testXReqId,
});
}

Expand Down
9 changes: 7 additions & 2 deletions src/worker/runner/browser-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ module.exports = class BrowserPool {
this._calibrator = new Calibrator();
}

async getBrowser({ browserId, browserVersion, sessionId, sessionCaps, sessionOpts }) {
const browser = Browser.create(this._config, browserId, browserVersion, this._emitter);
async getBrowser({ browserId, browserVersion, sessionId, sessionCaps, sessionOpts, testXReqId }) {
const browser = Browser.create(this._config, {
id: browserId,
version: browserVersion,
testXReqId,
emitter: this._emitter,
});

try {
await browser.init({ sessionId, sessionCaps, sessionOpts }, this._calibrator);
Expand Down
6 changes: 3 additions & 3 deletions src/worker/runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ module.exports = class Runner extends AsyncEmitter {
]);
}

async runTest(fullTitle, { browserId, browserVersion, file, sessionId, sessionCaps, sessionOpts }) {
async runTest(fullTitle, { browserId, browserVersion, file, sessionId, sessionCaps, sessionOpts, testXReqId }) {
const tests = await this._testParser.parse({ file, browserId });
const test = tests.find(t => t.fullTitle() === fullTitle);
const browserAgent = BrowserAgent.create(browserId, browserVersion, this._browserPool);
const browserAgent = BrowserAgent.create({ id: browserId, version: browserVersion, pool: this._browserPool });
const runner = TestRunner.create(test, this._config.forBrowser(browserId), browserAgent);

return runner.run({ sessionId, sessionCaps, sessionOpts });
return runner.run({ sessionId, sessionCaps, sessionOpts, testXReqId });
}
};
4 changes: 2 additions & 2 deletions src/worker/runner/test-runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ module.exports = class TestRunner {
this._browserAgent = browserAgent;
}

async run({ sessionId, sessionCaps, sessionOpts }) {
async run({ sessionId, sessionCaps, sessionOpts, testXReqId }) {
const test = this._test;
const hermioneCtx = test.hermioneCtx || {};

let browser;

try {
browser = await this._browserAgent.getBrowser({ sessionId, sessionCaps, sessionOpts });
browser = await this._browserAgent.getBrowser({ sessionId, sessionCaps, sessionOpts, testXReqId });
} catch (e) {
throw Object.assign(e, { hermioneCtx });
}
Expand Down
4 changes: 2 additions & 2 deletions test/src/browser-pool/basic-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ describe("browser-pool/basic-pool", () => {

await mkPool_({ config }).getBrowser("broId");

assert.calledWith(Browser.create, config, "broId");
assert.calledWith(Browser.create, config, { id: "broId" });
});

it("should create new browser with specified version when requested", async () => {
await mkPool_().getBrowser("broId", { version: "1.0" });

assert.calledWith(Browser.create, sinon.match.any, "broId", "1.0");
assert.calledWith(Browser.create, sinon.match.any, { id: "broId", version: "1.0" });
});

it("should init browser", async () => {
Expand Down
91 changes: 76 additions & 15 deletions test/src/browser/existing-browser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";

const { EventEmitter } = require("events");
const crypto = require("crypto");
const _ = require("lodash");
const Promise = require("bluebird");
const webdriverio = require("webdriverio");
Expand Down Expand Up @@ -56,7 +57,7 @@ describe("ExistingBrowser", () => {
it("should set emitter", () => {
const emitter = new EventEmitter();

const browser = mkBrowser_({}, "bro", null, emitter);
const browser = mkBrowser_({}, { emitter });

assert.deepEqual(browser.emitter, emitter);
});
Expand All @@ -69,7 +70,7 @@ describe("ExistingBrowser", () => {
});

it("should extend meta-info with browserVersion by default", () => {
const browser = mkBrowser_({}, "bro-id", "10.1");
const browser = mkBrowser_({}, { id: "bro-id", version: "10.1" });

assert.propertyVal(browser.meta, "browserVersion", "10.1");
});
Expand All @@ -79,6 +80,26 @@ describe("ExistingBrowser", () => {

assert.propertyVal(browser.meta, "k1", "v1");
});

describe("testXReqId field", () => {
it("should not override if field is already exists in meta config", () => {
const browser = mkBrowser_({ meta: { testXReqId: "54321" } }, { testXReqId: "12345" });

assert.propertyVal(browser.meta, "testXReqId", "54321");
});

it('should not add if "X-Request-ID" is specified in header config', () => {
const browser = mkBrowser_({ headers: { "X-Request-ID": "54321" } }, { testXReqId: "12345" });

assert.isUndefined(browser.meta.testXReqId);
});

it('should extend meta-info with "testXReqId"', () => {
const browser = mkBrowser_({}, { testXReqId: "12345" });

assert.propertyVal(browser.meta, "testXReqId", "12345");
});
});
});

describe("Camera", () => {
Expand Down Expand Up @@ -136,21 +157,61 @@ describe("ExistingBrowser", () => {
assert.calledWithMatch(webdriverio.attach, { foo: "bar" });
});

it('should attach to browser with "transform*" options from browser config', async () => {
const transformRequestStub = sinon.stub();
const transformResponseStub = sinon.stub();
describe("transformRequest option", () => {
beforeEach(() => {
sandbox.stub(crypto, "randomUUID").returns("00000");
});

it('should not add "X-Request-ID" header if it is already exists in request', async () => {
crypto.randomUUID.returns("67890");
const testXReqId = "12345";
const request = { headers: { "X-Request-ID": "100500" } };

await initBrowser_(
mkBrowser_({
transformRequest: transformRequestStub,
transformResponse: transformResponseStub,
}),
);
await initBrowser_(mkBrowser_({}, { testXReqId }));

assert.calledOnce(webdriverio.attach);
assert.calledWithMatch(webdriverio.attach, {
transformRequest: transformRequestStub,
transformResponse: transformResponseStub,
const { transformRequest } = webdriverio.attach.lastCall.args[0];
transformRequest(request);

assert.equal(request.headers["X-Request-ID"], "100500");
});

it('should add "X-Request-ID" header if it is not exists in request', async () => {
crypto.randomUUID.returns("67890");
const testXReqId = "12345";
const request = { headers: {} };

await initBrowser_(mkBrowser_({}, { testXReqId }));

const { transformRequest } = webdriverio.attach.lastCall.args[0];
transformRequest(request);

assert.equal(request.headers["X-Request-ID"], "12345_67890");
});

it("should call user handler from config", async () => {
const transformRequestStub = sinon.stub();
const request = { headers: {} };

await initBrowser_(mkBrowser_({ transformRequest: transformRequestStub }));

const { transformRequest } = webdriverio.attach.lastCall.args[0];
transformRequest(request);

assert.calledOnceWith(transformRequestStub, request);
});
});

describe("transformResponse option", () => {
it("should call user handler from config", async () => {
const transformResponseStub = sinon.stub();
const response = {};

await initBrowser_(mkBrowser_({ transformResponse: transformResponseStub }));

const { transformResponse } = webdriverio.attach.lastCall.args[0];
transformResponse(response);

assert.calledOnceWith(transformResponseStub, response);
});
});

Expand Down
Loading

0 comments on commit b5a8ae4

Please sign in to comment.