diff --git a/tests/e2e/get-random-port.test.js b/tests/e2e/get-random-port.test.js new file mode 100644 index 0000000..30e9a83 --- /dev/null +++ b/tests/e2e/get-random-port.test.js @@ -0,0 +1,37 @@ +const { + getRandomPorts, + releaseRandomPorts, +} = require('../helpers/get-random-port'); + +describe('random port allocation', () => { + let ports = []; + + afterEach(() => { + releaseRandomPorts(ports); + ports = []; + rstest.restoreAllMocks(); + }); + + it('allocates a contiguous block when the random start is at the upper boundary', async () => { + rstest.spyOn(Math, 'random').mockReturnValue(0.99999); + ports = await getRandomPorts(8, '127.0.0.1'); + + expect(ports).toHaveLength(8); + expect(ports[0]).toBeGreaterThanOrEqual(15000); + expect(ports[7]).toBeLessThanOrEqual(45000); + expect(ports).toEqual(Array.from({ length: 8 }, (_, i) => ports[0] + i)); + }); + + it('wraps to lower ports when the upper block is already reserved', async () => { + rstest.spyOn(Math, 'random').mockReturnValue(0.99999); + const first = await getRandomPorts(8, '127.0.0.1'); + ports.push(...first); + const second = await getRandomPorts(8, '127.0.0.1'); + ports.push(...second); + + expect(new Set(ports).size).toBe(16); + expect(second).toEqual(Array.from({ length: 8 }, (_, i) => second[0] + i)); + expect(second[0]).toBeGreaterThanOrEqual(15000); + expect(second[7]).toBeLessThanOrEqual(45000); + }); +}); diff --git a/tests/helpers/get-random-port.js b/tests/helpers/get-random-port.js index bb15cf2..0ea660b 100644 --- a/tests/helpers/get-random-port.js +++ b/tests/helpers/get-random-port.js @@ -32,10 +32,15 @@ function getDefaultPort() { } async function findAvailablePort(startPort, count, host) { - let port = Math.max(startPort, minRandomPort); const maxStartPort = maxRandomPort - count + 1; - - while (port <= maxStartPort) { + let port = Math.min(Math.max(startPort, minRandomPort), maxStartPort); + + // Search every valid start once, including ports below the random start. + for ( + let remaining = maxStartPort - minRandomPort + 1; + remaining > 0; + remaining -= 1 + ) { let isAvailable = true; for (let index = 0; index < count; index += 1) { @@ -54,7 +59,7 @@ async function findAvailablePort(startPort, count, host) { return port; } - port += 1; + port = port === maxStartPort ? minRandomPort : port + 1; } throw new Error('No available ports found');