From ff478f368c9cb8831df1effa3e46b8997181bb11 Mon Sep 17 00:00:00 2001 From: Adil Rakhaliyev <67043367+Bayheck@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:25:09 +0500 Subject: [PATCH] remove endpoint-utils package (#8217) ## Purpose _Describe the problem you want to address or the feature you want to implement._ ## Approach _Describe how your changes address the issue or implement the desired functionality in as much detail as possible._ ## References closes https://github.com/DevExpress/testcafe/issues/8207 ## Pre-Merge TODO - [ ] Write tests for your proposed changes - [ ] Make sure that existing tests do not fail --------- Co-authored-by: Bayheck Co-authored-by: Popov Aleksey --- @types/endpoint-utils/index.d.ts | 6 - package-lock.json | 127 ++++++------------ package.json | 4 +- .../built-in/dedicated/chrome/runtime-info.ts | 2 +- .../dedicated/firefox/runtime-info.js | 2 +- src/configuration/utils.ts | 21 ++- src/runner/tested-app.ts | 2 +- src/utils/endpoint-utils.ts | 91 +++++++++++++ test/functional/fixtures/app-command/test.js | 2 +- .../fixtures/regression/gh-5239/test.js | 2 +- .../regression/hammerhead/gh-863/test.js | 2 +- 11 files changed, 155 insertions(+), 106 deletions(-) delete mode 100644 @types/endpoint-utils/index.d.ts create mode 100644 src/utils/endpoint-utils.ts diff --git a/@types/endpoint-utils/index.d.ts b/@types/endpoint-utils/index.d.ts deleted file mode 100644 index c466c40635d..00000000000 --- a/@types/endpoint-utils/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'endpoint-utils' { - export function getFreePort(): Promise; - export function isFreePort(port: number): Promise; - export function getIPAddress(): string; - export function isMyHostname(hostname: string): Promise; -} diff --git a/package-lock.json b/package-lock.json index 6787f1e954e..e768af1c99e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,8 @@ "@babel/runtime": "^7.23.2", "@devexpress/bin-v8-flags-filter": "^1.3.0", "@devexpress/callsite-record": "^4.1.6", - "@types/node": "^12.20.10", + "@types/node": "^20.14.5", + "address": "^2.0.2", "async-exit-hook": "^1.1.2", "babel-plugin-module-resolver": "5.0.0", "babel-plugin-syntax-trailing-function-commas": "^6.22.0", @@ -46,7 +47,6 @@ "elegant-spinner": "^1.0.1", "email-validator": "^2.0.4", "emittery": "^0.4.1", - "endpoint-utils": "^1.0.2", "error-stack-parser": "^2.1.4", "execa": "^4.0.3", "get-os-info": "^1.0.2", @@ -2905,9 +2905,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + "version": "20.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", + "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/prompts": { "version": "2.4.9", @@ -3330,9 +3333,9 @@ } }, "node_modules/@wdio/types/node_modules/@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", + "version": "18.19.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.36.tgz", + "integrity": "sha512-tX1BNmYSWEvViftB26VLNxT6mEr37M7+ldUtq7rlKnv4/2fKYsJIOmqJAjT6h1DNuwQjIKgw3VJ/Dtw3yiTIQw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -3405,6 +3408,14 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/address": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/address/-/address-2.0.2.tgz", + "integrity": "sha512-u6nFssvaX9RHQmjMSqgT7b7QJbf/5/U8+ntbTL8vgABfIiEmm02ZSM5MwljKjCrIrm7iIbgYEya2YW6AaRccVA==", + "engines": { + "node": ">= 16.0.0" + } + }, "node_modules/adm-zip": { "version": "0.5.12", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", @@ -5919,34 +5930,6 @@ "once": "^1.4.0" } }, - "node_modules/endpoint-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/endpoint-utils/-/endpoint-utils-1.0.2.tgz", - "integrity": "sha512-s5IrlLvx7qVXPOjcxjF00CRBlybiQWOoGCNiIZ/Vin2WeJ3SHtfkWHRsyu7C1+6QAwYXf0ULoweylxUa19Khjg==", - "dependencies": { - "ip": "^1.1.3", - "pinkie-promise": "^1.0.0" - } - }, - "node_modules/endpoint-utils/node_modules/pinkie": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz", - "integrity": "sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/endpoint-utils/node_modules/pinkie-promise": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", - "integrity": "sha512-5mvtVNse2Ml9zpFKkWBpGsTPwm3DKhs+c95prO/F6E7d6DN0FPqxs6LONpLNpyD7Iheb7QN4BbUoKJgo+DnkQA==", - "dependencies": { - "pinkie": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -9586,11 +9569,6 @@ "node": ">=0.10.0" } }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -16361,8 +16339,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -16767,9 +16744,9 @@ } }, "node_modules/webdriver/node_modules/@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", + "version": "18.19.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.36.tgz", + "integrity": "sha512-tX1BNmYSWEvViftB26VLNxT6mEr37M7+ldUtq7rlKnv4/2fKYsJIOmqJAjT6h1DNuwQjIKgw3VJ/Dtw3yiTIQw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -19078,9 +19055,12 @@ "dev": true }, "@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + "version": "20.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", + "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", + "requires": { + "undici-types": "~5.26.4" + } }, "@types/prompts": { "version": "2.4.9", @@ -19365,9 +19345,9 @@ }, "dependencies": { "@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", + "version": "18.19.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.36.tgz", + "integrity": "sha512-tX1BNmYSWEvViftB26VLNxT6mEr37M7+ldUtq7rlKnv4/2fKYsJIOmqJAjT6h1DNuwQjIKgw3VJ/Dtw3yiTIQw==", "dev": true, "requires": { "undici-types": "~5.26.4" @@ -19430,6 +19410,11 @@ "dev": true, "requires": {} }, + "address": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/address/-/address-2.0.2.tgz", + "integrity": "sha512-u6nFssvaX9RHQmjMSqgT7b7QJbf/5/U8+ntbTL8vgABfIiEmm02ZSM5MwljKjCrIrm7iIbgYEya2YW6AaRccVA==" + }, "adm-zip": { "version": "0.5.12", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", @@ -21401,30 +21386,6 @@ "once": "^1.4.0" } }, - "endpoint-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/endpoint-utils/-/endpoint-utils-1.0.2.tgz", - "integrity": "sha512-s5IrlLvx7qVXPOjcxjF00CRBlybiQWOoGCNiIZ/Vin2WeJ3SHtfkWHRsyu7C1+6QAwYXf0ULoweylxUa19Khjg==", - "requires": { - "ip": "^1.1.3", - "pinkie-promise": "^1.0.0" - }, - "dependencies": { - "pinkie": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz", - "integrity": "sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q==" - }, - "pinkie-promise": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", - "integrity": "sha512-5mvtVNse2Ml9zpFKkWBpGsTPwm3DKhs+c95prO/F6E7d6DN0FPqxs6LONpLNpyD7Iheb7QN4BbUoKJgo+DnkQA==", - "requires": { - "pinkie": "^1.0.0" - } - } - } - }, "enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -24276,11 +24237,6 @@ "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true }, - "ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" - }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -29585,8 +29541,7 @@ "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -29905,9 +29860,9 @@ }, "dependencies": { "@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", + "version": "18.19.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.36.tgz", + "integrity": "sha512-tX1BNmYSWEvViftB26VLNxT6mEr37M7+ldUtq7rlKnv4/2fKYsJIOmqJAjT6h1DNuwQjIKgw3VJ/Dtw3yiTIQw==", "dev": true, "requires": { "undici-types": "~5.26.4" diff --git a/package.json b/package.json index 7210baa6d61..aaec9b86a15 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,8 @@ "@babel/runtime": "^7.23.2", "@devexpress/bin-v8-flags-filter": "^1.3.0", "@devexpress/callsite-record": "^4.1.6", - "@types/node": "^12.20.10", + "@types/node": "^20.14.5", + "address": "^2.0.2", "async-exit-hook": "^1.1.2", "babel-plugin-module-resolver": "5.0.0", "babel-plugin-syntax-trailing-function-commas": "^6.22.0", @@ -98,7 +99,6 @@ "elegant-spinner": "^1.0.1", "email-validator": "^2.0.4", "emittery": "^0.4.1", - "endpoint-utils": "^1.0.2", "error-stack-parser": "^2.1.4", "execa": "^4.0.3", "get-os-info": "^1.0.2", diff --git a/src/browser/provider/built-in/dedicated/chrome/runtime-info.ts b/src/browser/provider/built-in/dedicated/chrome/runtime-info.ts index 3a27809a354..748ce0fc59c 100644 --- a/src/browser/provider/built-in/dedicated/chrome/runtime-info.ts +++ b/src/browser/provider/built-in/dedicated/chrome/runtime-info.ts @@ -1,4 +1,4 @@ -import { getFreePort } from 'endpoint-utils'; +import { getFreePort } from '../../../../../utils/endpoint-utils'; import createTempProfile from './create-temp-profile'; import isDocker from 'is-docker'; import isPodman from 'is-podman'; diff --git a/src/browser/provider/built-in/dedicated/firefox/runtime-info.js b/src/browser/provider/built-in/dedicated/firefox/runtime-info.js index 9bf9d75ee5e..2e9312f8594 100644 --- a/src/browser/provider/built-in/dedicated/firefox/runtime-info.js +++ b/src/browser/provider/built-in/dedicated/firefox/runtime-info.js @@ -1,4 +1,4 @@ -import { getFreePort } from 'endpoint-utils'; +import { getFreePort } from '../../../../../utils/endpoint-utils'; import createTempProfile from './create-temp-profile'; diff --git a/src/configuration/utils.ts b/src/configuration/utils.ts index d6743e4d06c..2588872ba20 100644 --- a/src/configuration/utils.ts +++ b/src/configuration/utils.ts @@ -1,29 +1,38 @@ import { GeneralError } from '../errors/runtime'; import { RUNTIME_ERRORS } from '../errors/types'; -import endpointUtils from 'endpoint-utils'; +import { + isMyHostname, + getIPAddress, + isFreePort, + getFreePort, +} from '../utils/endpoint-utils'; export async function getValidHostname (hostname: string): Promise { if (hostname) { - const valid = await endpointUtils.isMyHostname(hostname); + const valid = await isMyHostname(hostname); if (!valid) throw new GeneralError(RUNTIME_ERRORS.invalidHostname, hostname); } - else - hostname = endpointUtils.getIPAddress(); + else { + hostname = getIPAddress() ?? ''; + + if (!hostname) + throw new GeneralError(RUNTIME_ERRORS.invalidHostname, hostname); + } return hostname; } export async function getValidPort (port: number): Promise { if (port) { - const isFree = await endpointUtils.isFreePort(port); + const isFree = await isFreePort(port); if (!isFree) throw new GeneralError(RUNTIME_ERRORS.portIsNotFree, port); } else - port = await endpointUtils.getFreePort(); + port = await getFreePort(); return port; } diff --git a/src/runner/tested-app.ts b/src/runner/tested-app.ts index 46a352499bb..a869bfb1b09 100644 --- a/src/runner/tested-app.ts +++ b/src/runner/tested-app.ts @@ -90,7 +90,7 @@ export default class TestedApp { public async kill (): Promise { this._killed = true; - const killPromise = new Promise(resolve => kill((this._process as ChildProcess).pid, 'SIGTERM', resolve)); + const killPromise = new Promise(resolve => kill((this._process as ChildProcess).pid ?? 0, 'SIGTERM', resolve)); await killPromise; } diff --git a/src/utils/endpoint-utils.ts b/src/utils/endpoint-utils.ts new file mode 100644 index 00000000000..b5e59823230 --- /dev/null +++ b/src/utils/endpoint-utils.ts @@ -0,0 +1,91 @@ +import { + AddressInfo, + createServer, + Server, +} from 'net'; +import { ip, ipv6 } from 'address'; + +function createServerOnFreePort (): Promise { + return new Promise(resolve => { + const server = createServer(); + + server.once('listening', () => { + resolve(server); + }); + + server.listen(0); + }); +} + +function closeServers (servers: Server[]): Promise { + return Promise.all(servers.map((server: Server) => { + return new Promise(resolve => { + server.once('close', resolve); + server.close(); + }); + })); +} + +function checkAvailability (port: number, hostname?: string): Promise { + return new Promise(resolve => { + const server = createServer(); + + server.once('error', () => { + resolve(false); + }); + + server.once('listening', () => { + server.once('close', () => { + resolve(true); + }); + + server.close(); + }); + + server.listen(port, hostname); + }); +} + +export function isFreePort (port: number): Promise { + return checkAvailability(port); +} + +export function getFreePort (): Promise { + return getFreePorts(1).then(ports => { + return ports[0]; + }); +} + +function getFreePorts (count: number): Promise { + const serverPromises = []; + let ports: number[] = []; + + // NOTE: Sequentially collect listening + // servers to avoid interference. + for (let i = 0; i < count; i++) + serverPromises.push(createServerOnFreePort()); + + return Promise.all(serverPromises) + .then(servers => { + ports = servers.map((server: Server) => { + return (server.address() as AddressInfo).port; + }); + + return servers; + }) + .then(closeServers) + .then(() => { + return ports; + }); +} + +export function isMyHostname (hostname: string): Promise { + return getFreePort() + .then(port => { + return checkAvailability(port, hostname); + }); +} + +export function getIPAddress (): string | undefined { + return ip() || ipv6(); +} diff --git a/test/functional/fixtures/app-command/test.js b/test/functional/fixtures/app-command/test.js index 5bdbef3a612..07dff6661b8 100644 --- a/test/functional/fixtures/app-command/test.js +++ b/test/functional/fixtures/app-command/test.js @@ -1,5 +1,5 @@ const { expect } = require('chai'); -const { isFreePort } = require('endpoint-utils'); +const { isFreePort } = require('../../../../lib/utils/endpoint-utils'); const delay = require('../../../../lib/utils/delay'); describe('App command', function () { diff --git a/test/functional/fixtures/regression/gh-5239/test.js b/test/functional/fixtures/regression/gh-5239/test.js index 563ababb977..9fff27bde91 100644 --- a/test/functional/fixtures/regression/gh-5239/test.js +++ b/test/functional/fixtures/regression/gh-5239/test.js @@ -2,7 +2,7 @@ const http = require('http'); const path = require('path'); const config = require('../../../config'); const createTestCafe = require('../../../../../lib'); -const { getFreePort } = require('endpoint-utils'); +const { getFreePort } = require('../../../../../lib/utils/endpoint-utils'); const { skipInNativeAutomation } = require('../../../utils/skip-in'); const ERROR_RESPONSE_COUNT = 8; diff --git a/test/functional/fixtures/regression/hammerhead/gh-863/test.js b/test/functional/fixtures/regression/hammerhead/gh-863/test.js index 006988ee671..18038c55de3 100644 --- a/test/functional/fixtures/regression/hammerhead/gh-863/test.js +++ b/test/functional/fixtures/regression/hammerhead/gh-863/test.js @@ -4,7 +4,7 @@ const fs = require('fs'); const createTestCafe = require('../../../../../../lib'); const config = require('../../../../config'); const { expect } = require('chai'); -const { getFreePort } = require('endpoint-utils'); +const { getFreePort } = require('../../../../../../lib/utils/endpoint-utils'); const resourceRequestCounter = { script1: 0,