Skip to content

Commit 9524443

Browse files
authored
Merge pull request #823 from gemini-testing/HERMIONE-1276.fix_x_req_id_hermione7
feat: generate "X-Request-ID" header for each browser request (backport to v7)
2 parents 6117a36 + 0c87eb4 commit 9524443

26 files changed

+260
-102
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,20 @@ Allows to intercept [HTTP request options](https://github.com/sindresorhus/got#o
10871087
(RequestOptions) => RequestOptions
10881088
```
10891089

1090+
In runtime a unique `X-Request-ID` header is generated for each browser request which consists of `${FIRST_X_REQ_ID}__${LAST_X_REQ_ID}`, where:
1091+
- `FIRST_X_REQ_ID` - unique uuid for each test (different for each retry), allows to find all requests related to a single test run;
1092+
- `LAST_X_REQ_ID` - unique uuid for each browser request, allows to find one unique request in one test (together with `FIRST_X_REQ_ID`).
1093+
1094+
Header `X-Request-ID` can be useful if you manage the cloud with browsers yourself and collect logs with requests. Real-world example: `2f31ffb7-369d-41f4-bbb8-77744615d2eb__e8d011d8-bb76-42b9-b80e-02f03b8d6fe1`.
1095+
1096+
To override generated `X-Request-ID` to your own value you need specify it in `transformRequest` handler. Example:
1097+
1098+
```javascript
1099+
transformRequest: (req) => {
1100+
req.handler["X-Request-ID"] = "my_x_req_id";
1101+
}
1102+
```
1103+
10901104
#### transformResponse
10911105
Allows to intercept [HTTP response object](https://github.com/sindresorhus/got#response) after a WebDriver response has arrived. Default value is `null`. If function is passed then it takes `Response` (original response object) as the first and `RequestOptions` as the second argument. Should return modified `Response`. Example:
10921106

src/browser-pool/basic-pool.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ module.exports = class BasicPool extends Pool {
2323
}
2424

2525
async getBrowser(id, opts = {}) {
26-
const { version } = opts;
27-
const browser = Browser.create(this._config, id, version);
26+
const browser = Browser.create(this._config, { ...opts, id });
2827

2928
try {
3029
await browser.init();

src/browser/browser.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"use strict";
22

3+
const crypto = require("crypto");
34
const _ = require("lodash");
45
const { SAVE_HISTORY_MODE } = require("../constants/config");
6+
const { X_REQUEST_ID_DELIMITER } = require("../constants/browser");
57
const history = require("./history");
68
const addRunStepCommand = require("./commands/runStep");
79

@@ -19,13 +21,14 @@ const CUSTOM_SESSION_OPTS = [
1921
];
2022

2123
module.exports = class Browser {
22-
static create(config, id, version) {
23-
return new this(config, id, version);
24+
static create(config, opts) {
25+
return new this(config, opts);
2426
}
2527

26-
constructor(config, id, version) {
27-
this.id = id;
28-
this.version = version;
28+
constructor(config, opts) {
29+
this.id = opts.id;
30+
this.version = opts.version;
31+
this.testXReqId = opts.testXReqId;
2932

3033
this._config = config.forBrowser(this.id);
3134
this._debug = config.system.debug;
@@ -82,7 +85,21 @@ module.exports = class Browser {
8285

8386
_getSessionOptsFromConfig(optNames = CUSTOM_SESSION_OPTS) {
8487
return optNames.reduce((options, optName) => {
85-
if (!_.isNull(this._config[optName])) {
88+
if (optName === "transformRequest") {
89+
options[optName] = req => {
90+
if (!_.isNull(this._config[optName])) {
91+
req = this._config[optName](req);
92+
}
93+
94+
if (!req.headers["X-Request-ID"]) {
95+
req.headers["X-Request-ID"] = `${
96+
this.testXReqId
97+
}${X_REQUEST_ID_DELIMITER}${crypto.randomUUID()}`;
98+
}
99+
100+
return req;
101+
};
102+
} else if (!_.isNull(this._config[optName])) {
86103
options[optName] = this._config[optName];
87104
}
88105

src/browser/existing-browser.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ const { isSupportIsolation } = require("../utils/browser");
1919
const OPTIONAL_SESSION_OPTS = ["transformRequest", "transformResponse"];
2020

2121
module.exports = class ExistingBrowser extends Browser {
22-
static create(config, id, version, emitter) {
23-
return new this(config, id, version, emitter);
22+
static create(config, opts) {
23+
return new this(config, opts);
2424
}
2525

26-
constructor(config, id, version, emitter) {
27-
super(config, id, version);
26+
constructor(config, opts) {
27+
super(config, opts);
2828

29-
this._emitter = emitter;
29+
this._emitter = opts.emitter;
3030
this._camera = Camera.create(this._config.screenshotMode, () => this._takeScreenshot());
3131

3232
this._meta = this._initMeta();
@@ -165,6 +165,7 @@ module.exports = class ExistingBrowser extends Browser {
165165
return {
166166
pid: process.pid,
167167
browserVersion: this.version,
168+
testXReqId: this.testXReqId,
168169
...this._config.meta,
169170
};
170171
}

src/browser/new-browser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ const headlessBrowserOptions = {
3131
};
3232

3333
module.exports = class NewBrowser extends Browser {
34-
constructor(config, id, version) {
35-
super(config, id, version);
34+
constructor(config, opts) {
35+
super(config, opts);
3636

3737
signalHandler.on("exit", () => this.quit());
3838
}

src/constants/browser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export const MIN_CHROME_VERSION_SUPPORT_ISOLATION = 93;
2+
export const X_REQUEST_ID_DELIMITER = "__";

src/runner/browser-agent.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"use strict";
22

33
module.exports = class BrowserAgent {
4-
static create(id, version, pool) {
5-
return new this(id, version, pool);
4+
static create(opts = {}) {
5+
return new this(opts);
66
}
77

8-
constructor(id, version, pool) {
8+
constructor({ id, version, pool }) {
99
this.browserId = id;
1010

1111
this._version = version;

src/runner/browser-runner.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ module.exports = class BrowserRunner extends Runner {
4848
}
4949

5050
async _runTest(test) {
51-
const browserAgent = BrowserAgent.create(this._browserId, test.browserVersion, this._browserPool);
51+
const browserAgent = BrowserAgent.create({
52+
id: this._browserId,
53+
version: test.browserVersion,
54+
pool: this._browserPool,
55+
});
5256
const runner = TestRunner.create(test, this._config, browserAgent);
5357

5458
runner.on(Events.TEST_BEGIN, test => this._suiteMonitor.testBegin(test));

src/runner/test-runner/high-priority-browser-agent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ module.exports = class HighPriorityBrowserAgent {
99
this._browserAgent = browserAgent;
1010
}
1111

12-
getBrowser() {
13-
return this._browserAgent.getBrowser({ highPriority: true });
12+
getBrowser(opts = {}) {
13+
return this._browserAgent.getBrowser({ ...opts, highPriority: true });
1414
}
1515

1616
freeBrowser(...args) {

src/runner/test-runner/regular-test-runner.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use strict";
22

3+
const crypto = require("crypto");
34
const _ = require("lodash");
45
const Runner = require("../runner");
56
const logger = require("../../utils/logger");
@@ -64,6 +65,7 @@ module.exports = class RegularTestRunner extends Runner {
6465
sessionCaps: this._browser.capabilities,
6566
sessionOpts: this._browser.publicAPI.options,
6667
file: this._test.file,
68+
testXReqId: this._browser.testXReqId,
6769
});
6870
}
6971

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

8183
async _getBrowser() {
8284
try {
83-
this._browser = await this._browserAgent.getBrowser();
85+
this._browser = await this._browserAgent.getBrowser({ testXReqId: crypto.randomUUID() });
8486
this._test.sessionId = this._browser.sessionId;
8587

8688
return this._browser;

0 commit comments

Comments
 (0)