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

feat: generate "X-Request-ID" header for each browser request #819

Merged
merged 2 commits into from
Dec 27, 2023

Conversation

DudaGod
Copy link
Member

@DudaGod DudaGod commented Dec 25, 2023

What is done

For each browser request hermione generates uniq X-Request-ID header which consists of ${TEST_X_REQ_ID}${DELIMITER}$BROWSER_X_REQ_ID}, where:

  • TEST_X_REQ_ID - uniq uuid for each test (different from every other test retry), allows you to find all requests related to a single test run using logs
  • DELIMITER - __ separator between test and request uuids
  • BROWSER_X_REQ_ID - uniq uuid for each browser request

Real-world example: 2f31ffb7-369d-41f4-bbb8-77744615d2eb__e8d011d8-bb76-42b9-b80e-02f03b8d6fe1.

Moreover revert previous decision in beta version with generate the same X-Request-ID for each request in whole hermione run.

@@ -19,13 +20,14 @@ const CUSTOM_SESSION_OPTS = [
];

module.exports = class Browser {
static create(config, id, version) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Изменил api, чтобы не докидывать testXReqId отдельным параметром

@@ -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 });
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Изменил api, чтобы не докидывать testXReqId отдельным параметром. Похожий подход присутствует и в других файлах, поэтому их отдельно комментировать не буду.

@@ -1,5 +1,6 @@
"use strict";

const crypto = require("crypto");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Для генерации uuid юзаю crypto. randomUUID, его же предлагают юзать в пакете uuid - https://github.com/uuidjs/uuid если юзается только uuid v4

req.headers["X-Request-ID"] = `${this.testXReqId}_${crypto.randomUUID()}`;
}

return !_.isNull(this._config[optName]) ? this._config[optName](req) : req;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если юзер указал тоже transformRequest, то я его должен вызвать после своих изменений в req

if (!_.isNull(this._config[optName])) {
if (optName === "transformRequest") {
options[optName] = req => {
if (!req.headers["X-Request-ID"]) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Юзер мог самостоятельно указать в конфиге хедер X-Request-ID и в этом случае я ничего делать не должен.

if (optName === "transformRequest") {
options[optName] = req => {
if (!req.headers["X-Request-ID"]) {
req.headers["X-Request-ID"] = `${this.testXReqId}_${crypto.randomUUID()}`;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В качестве разделителя между uuid теста и uuid запроса юзаю _.

...this._config.meta,
};

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Докидываю в мету если пользователь сам не переопределил testXReqId в мете конфига или не указал хедер X-Request_ID в конфиге самостоятельно.

Copy link
Member

@KuznetsovRoman KuznetsovRoman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В остальном /ок

README.md Outdated
@@ -1098,6 +1098,20 @@ Allows to intercept [HTTP request options](https://github.com/sindresorhus/got#o
(RequestOptions) => RequestOptions
```

In runtime a unique `X-Request-ID` header is generated for each browser request which consists of `${TEST_X_REQ_ID}__${BROWSER_X_REQ_ID}`, where:
- `TEST_X_REQ_ID` - unique uuid for each test (different for each retry), allows to find all requests related to a single test run;
- `BROWSER_X_REQ_ID` - unique uuid for each browser request, allows to find one unique request.
Copy link
Member

@KuznetsovRoman KuznetsovRoman Dec 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут нейминг не нравится. Кажется, что это уникальное значение браузера, по аналогии с тестом: у обоих REQ_ID.

Давай напишем, что строим этот requestId из testId (отличный для каждого ретрая, или вообще можно явно указать, из каких частей он строится) и uuidv4(). Так будет понятно, что это и есть та рандомная на каждый запрос часть, и не будет казаться, что оно как то связано с браузером

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поправил, чтобы было понятнее.

@@ -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,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прокидываю x-req-id теста в worker, чтобы затем добросить его до браузера в воркере (existing-browser). По другому данные по нормальному не передать.

@@ -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() });
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот тут генерится x-req-id для теста и прокидывается в браузер (запущенный в мастере, т.е. в new-browser)

README.md Outdated
@@ -1098,6 +1098,20 @@ Allows to intercept [HTTP request options](https://github.com/sindresorhus/got#o
(RequestOptions) => RequestOptions
```

In runtime a unique `X-Request-ID` header is generated for each browser request which consists of `${TEST_X_REQ_ID}__${BROWSER_X_REQ_ID}`, where:
- `TEST_X_REQ_ID` - unique uuid for each test (different for each retry), allows to find all requests related to a single test run;
- `BROWSER_X_REQ_ID` - unique uuid for each browser request, allows to find one unique request.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поправил, чтобы было понятнее.

@KuznetsovRoman
Copy link
Member

@DudaGod А давай явно писать, из чего строится первый хэш.
Как-то так: ${hash(fullName, browserId, retryCount)}__${requestId}

@DudaGod
Copy link
Member Author

DudaGod commented Dec 27, 2023

А давай явно писать, из чего строится первый хэш.
Как-то так: ${hash(fullName, browserId, retryCount)}__${requestId}

Первый кусок хеша это тоже просто uuidv4, так как иначе нужно придумывать какой-то свой алгоритм с учетом данных теста + timestamp + соль, чтобы при параллельных запусках точно не было дубликатов. В итоге я не понял зачем мне тут велосипедить если уже все сделали за меня и нужно просто юзать uuidv4.

getBrowser() {
return this._browserAgent.getBrowser({ highPriority: true });
getBrowser(opts = {}) {
return this._browserAgent.getBrowser({ ...opts, highPriority: true });
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нашел баг, что при ретрае теста в мету не прокидывался testXReqID. Пофиксил.

@DudaGod DudaGod merged commit 22814e5 into master Dec 27, 2023
2 checks passed
@DudaGod DudaGod deleted the HERMIONE-1276.fix_x_req_id branch December 27, 2023 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants