Files
dsh_shenxian/test/instance-port.test.mjs
admin 146c3d25ef feat(overlay): 覆盖网络线序①–⑮ 代码与测试产物入库
覆盖网络线累积产物(此前只在工作区、未入版本库):
- 新增 relay 子系统 src/net/relay/**(wire/duplex/server/client/dialer/switcher/directory/identity/keys/placement/network/addr-override/main/index)
- 新增 src/worker/relay-tunnel.ts、src/web/routes/overlay.ts
- 新增观测/演练脚本 overlay-probe、overlay-failover-drill、overlay-keyring、overlay-holepunch、overlay-jitter、overlay-wan、overlay-relaykey-add、relay-mem-calibrate
- 新增测试 12 个(relay / relay-failover / remote-spawner / instance-port / overlay-{network,auth,bootstrap,identity} / remote-user-fs 等)

验收基线:npm test = 162 pass / 0 fail / 1 skip;--scene all = 12 PASS / 0 SKIP / 0 FAIL;overlay-probe = 12/12
2026-09-17 17:03:27 +08:00

73 lines
2.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 覆盖网络 S3 · 实例端口区间单测(不连外网、只在本机回环上 bind)。
* 运行:node --test test/instance-port.test.mjs(已含在 npm test / npm verify 中)
*
* ## 这个测试防的是什么
* `listen(0)` 让**每台 worker 各自**随机取端口,而跨机实例的隧道落点全挤在 Manager 的
* `127.0.0.1` 上 ⇒ 两台 worker 取到同号就撞号,`ssh -R` 失败还是**静默**的,
* Manager 会按该端口拨到**别人的实例**(2026-09-16 实测)。
*
* 所以这里要钉死两件事:
* ① 取到的端口**必须落在配置区间内**(区间隔离的前提)
* ② 起点被占 ⇒ **跳到下一个**,绝不"回落到 `listen(0)`"
*/
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { createServer } from 'node:net'
import { findFreePortInRange, findInstancePort } from '../lib/supervisor/spawn.js'
/** 占住一个回环端口,返回 `{ port, release }`。 */
function holdPort() {
return new Promise((resolve, reject) => {
const server = createServer()
server.once('error', reject)
server.listen(0, '127.0.0.1', () => {
const address = server.address()
const port = typeof address === 'object' && address !== null ? address.port : 0
resolve({ port, release: () => new Promise((r) => server.close(() => r())) })
})
})
}
test('端口区间:取到的端口必须落在区间内', async () => {
// 用打洞拿到的空闲端口当区间起点 ⇒ 测试不依赖"20000 一定空着"这种环境假设
const { port, release } = await holdPort()
try {
const got = await findFreePortInRange(port, 200)
assert.ok(got >= port && got < port + 200, `越界:${got} 不在 [${port}, ${port + 200})`)
} finally {
await release()
}
})
test('端口区间:起点被占用 ⇒ 跳过它,不回落到 listen(0)', async () => {
const { port, release } = await holdPort()
try {
const got = await findFreePortInRange(port, 200)
assert.notEqual(got, port, '起点被占却仍返回了它 ⇒ 会撞号')
assert.ok(got >= port && got < port + 200)
} finally {
await release()
}
})
test('端口区间:区间耗尽 ⇒ 抛错(禁止静默退回 listen(0))', async () => {
await assert.rejects(() => findFreePortInRange(20000, 0), /区间已耗尽/)
})
test('findInstancePort:未配区间(base<=0)⇒ 退回旧的 listen(0) 行为', async () => {
const got = await findInstancePort(0, 1000)
assert.ok(got > 0 && got < 65536, `应拿到合法端口,实际 ${got}`)
})
test('findInstancePort:配了区间 ⇒ 结果落在区间内', async () => {
const { port, release } = await holdPort()
try {
const got = await findInstancePort(port, 128)
assert.ok(got >= port && got < port + 128, `越界:${got}`)
} finally {
await release()
}
})