mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-07 12:17:50 +00:00
test: make desktop port coverage concurrency-safe (#1263)
This commit is contained in:
parent
45becddee9
commit
60485cd6df
1 changed files with 71 additions and 21 deletions
|
|
@ -3,49 +3,96 @@ import net from 'node:net';
|
|||
|
||||
import { findAvailablePort, isPortAvailable } from '../ports.js';
|
||||
|
||||
async function listenOnEphemeralPort(server: net.Server, host: string): Promise<number> {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const onError = (error: Error) => {
|
||||
server.off('listening', onListening);
|
||||
reject(error);
|
||||
};
|
||||
const onListening = () => {
|
||||
server.off('error', onError);
|
||||
resolve();
|
||||
};
|
||||
|
||||
server.once('error', onError);
|
||||
server.once('listening', onListening);
|
||||
server.listen(0, host);
|
||||
});
|
||||
|
||||
const address = server.address();
|
||||
if (!address || typeof address === 'string') {
|
||||
throw new Error(`Unable to resolve ${host} test listener port`);
|
||||
}
|
||||
return address.port;
|
||||
}
|
||||
|
||||
async function closeServer(server: net.Server): Promise<void> {
|
||||
if (!server.listening) {
|
||||
return;
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => (error ? reject(error) : resolve()));
|
||||
});
|
||||
}
|
||||
|
||||
async function acquireAvailablePort(host = '127.0.0.1'): Promise<number> {
|
||||
const reservation = net.createServer();
|
||||
try {
|
||||
return await listenOnEphemeralPort(reservation, host);
|
||||
} finally {
|
||||
await closeServer(reservation);
|
||||
}
|
||||
}
|
||||
|
||||
describe('port selection', () => {
|
||||
it('returns the preferred port when it is available', async () => {
|
||||
const port = await findAvailablePort(47631, '127.0.0.1', 1);
|
||||
expect(port).toBe(47631);
|
||||
const preferredPort = await acquireAvailablePort();
|
||||
|
||||
const port = await findAvailablePort(preferredPort, '127.0.0.1', 1);
|
||||
|
||||
expect(port).toBe(preferredPort);
|
||||
});
|
||||
|
||||
it('falls forward when the preferred port is busy', async () => {
|
||||
const server = net.createServer();
|
||||
await new Promise<void>((resolve) => server.listen(47632, '127.0.0.1', resolve));
|
||||
const preferredPort = await listenOnEphemeralPort(server, '127.0.0.1');
|
||||
|
||||
try {
|
||||
expect(await isPortAvailable(47632)).toBe(false);
|
||||
const port = await findAvailablePort(47632, '127.0.0.1', 3);
|
||||
expect(port).toBeGreaterThan(47632);
|
||||
expect(await isPortAvailable(preferredPort)).toBe(false);
|
||||
|
||||
const port = await findAvailablePort(preferredPort, '127.0.0.1', 1);
|
||||
|
||||
expect(port).not.toBe(preferredPort);
|
||||
expect(await isPortAvailable(port)).toBe(true);
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps separately selected desktop fallback ports distinct', async () => {
|
||||
const busyServer = net.createServer();
|
||||
await new Promise<void>((resolve) => busyServer.listen(47633, '127.0.0.1', resolve));
|
||||
const preferredPort = await listenOnEphemeralPort(busyServer, '127.0.0.1');
|
||||
|
||||
try {
|
||||
const serverPort = await findAvailablePort(47633, '127.0.0.1', 3);
|
||||
const webPort = await findAvailablePort(47633, '127.0.0.1', 3, new Set([serverPort]));
|
||||
const serverPort = await findAvailablePort(preferredPort, '127.0.0.1', 1);
|
||||
const webPort = await findAvailablePort(preferredPort, '127.0.0.1', 1, new Set([serverPort]));
|
||||
|
||||
expect(serverPort).toBeGreaterThan(47633);
|
||||
expect(webPort).toBeGreaterThan(47633);
|
||||
expect(serverPort).not.toBe(preferredPort);
|
||||
expect(webPort).not.toBe(preferredPort);
|
||||
expect(webPort).not.toBe(serverPort);
|
||||
expect(await isPortAvailable(serverPort)).toBe(true);
|
||||
expect(await isPortAvailable(webPort)).toBe(true);
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => busyServer.close(() => resolve()));
|
||||
await closeServer(busyServer);
|
||||
}
|
||||
});
|
||||
|
||||
it('falls forward when the preferred port is busy on an IPv6 wildcard', async () => {
|
||||
const server = net.createServer();
|
||||
let preferredPort: number;
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.once('error', reject);
|
||||
server.listen(47634, '::', resolve);
|
||||
});
|
||||
preferredPort = await listenOnEphemeralPort(server, '::');
|
||||
} catch (error) {
|
||||
const code = (error as NodeJS.ErrnoException).code;
|
||||
if (code === 'EAFNOSUPPORT' || code === 'EADDRNOTAVAIL') {
|
||||
|
|
@ -55,11 +102,14 @@ describe('port selection', () => {
|
|||
}
|
||||
|
||||
try {
|
||||
expect(await isPortAvailable(47634)).toBe(false);
|
||||
const port = await findAvailablePort(47634, '127.0.0.1', 3);
|
||||
expect(port).toBeGreaterThan(47634);
|
||||
expect(await isPortAvailable(preferredPort)).toBe(false);
|
||||
|
||||
const port = await findAvailablePort(preferredPort, '127.0.0.1', 1);
|
||||
|
||||
expect(port).not.toBe(preferredPort);
|
||||
expect(await isPortAvailable(port)).toBe(true);
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue