UNPKG

pick-port

Version:

Get a free TCP or UDP port for the given IP address

131 lines (130 loc) 4.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const os = require("node:os"); const net = require("node:net"); const matchers = require("jest-extended"); const __1 = require("../"); const Logger_1 = require("../Logger"); // Add all jest-extended matchers. expect.extend(matchers); const logger = new Logger_1.Logger('tests'); const allTypes = ['tcp', 'udp']; const ctx = { bindableIps: [], nonBindableIps: ['8.8.8.8', 'fe80::1:12345', 'WRONG IP'], }; beforeAll(async () => { const ips = new Set(); for (const iface of Object.values(os.networkInterfaces())) { for (const { address } of iface ?? []) { if (ips.has(address)) { continue; } ips.add(address); if (await isBindableIp(address)) { ctx.bindableIps.push(address); } } } logger.debug('beforeAll() | ctx.bindableIps:', ctx.bindableIps); }); test('pick port in default IP 0.0.0.0 succeeds', async () => { for (const type of allTypes) { await expect((0, __1.pickPort)({ type, reserveTimeout: 0 })).resolves.toBeNumber(); } }, 2000); test('pick port in bindable IPs succeeds', async () => { for (const type of allTypes) { for (const ip of ctx.bindableIps) { await expect((0, __1.pickPort)({ type, ip, reserveTimeout: 0 })).resolves.toBeNumber(); } } }, 2000); test('pick port in non bindable IPs fails', async () => { for (const type of allTypes) { for (const ip of ctx.nonBindableIps) { await expect((0, __1.pickPort)({ type, ip, reserveTimeout: 0 })).rejects.toThrow(); } } }, 2000); test('pick port with minPort and maxPort IPs succeeds', async () => { const ip = '127.0.0.1'; const minPort = 2001; const maxPort = 2002; const reserveTimeout = 1; for (const type of allTypes) { const port1 = await (0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout, }); const port2 = await (0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout, }); expect([port1, port2]).toEqual(expect.arrayContaining([2001, 2002])); // No more ports available during reserve time second so this should // reject. await expect((0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout })).rejects.toThrow(); // However it should work if a separate range is given. await expect((0, __1.pickPort)({ type, ip, minPort: 3001, maxPort: 3002, reserveTimeout })).resolves.toBeNumber(); // After reserve time, ports should be available again. await new Promise(resolve => setTimeout(resolve, reserveTimeout * 1000)); await expect((0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout })).resolves.toBeNumber(); } }, 4000); test('pick N ports at the same time succeeds', async () => { for (const type of allTypes) { const ip = '127.0.0.1'; const minPort = 3001; const maxPort = 3003; const reserveTimeout = 1; await expect(Promise.all([ (0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout, }), (0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout, }), (0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout, }), ])).resolves.toEqual(expect.arrayContaining([3001, 3002, 3003])); } }, 2000); /** * Not all reported IPs are bindable. Verify it by binding on them in a random * TCP port. */ async function isBindableIp(ip) { const server = net.createServer(); try { await new Promise((resolve, reject) => { server.unref(); server.on('error', reject); server.listen({ host: ip, port: 0, exclusive: true }, () => server.close(() => resolve())); }); return true; } catch (error) { logger.debug(`isBindableIp() | discarding not bindable IP '${ip}': ${error}`); return false; } }