Files
peardock/test/deploy-network-precheck.test.js
T
Raven Scott 254310b495
Release rolling / release (push) Successful in 7m47s
Precheck deploy networking before container create
Validate port mappings for empty host ports, in-form duplicates,
privileged low ports, and peer-side host port conflicts. Runs on
template deploy, deploy view, and add-container before create RPC.
2026-07-16 14:39:19 -04:00

111 lines
3.0 KiB
JavaScript

import test from 'brittle'
import {
parsePortMapping,
validateNetworkingSync,
precheckDeployNetworking,
formatNetworkingPrecheckMessage,
} from '../client/deployNetworkPrecheck.js'
test('parsePortMapping host:container/proto', (t) => {
const p = parsePortMapping('8080:80/tcp', 0)
t.ok(p)
t.is(p.hostPort, 8080)
t.is(p.containerPort, 80)
t.is(p.protocol, 'tcp')
t.is(p.incomplete, false)
})
test('parsePortMapping container-only is incomplete', (t) => {
const p = parsePortMapping('80/tcp', 1)
t.ok(p)
t.is(p.hostPort, null)
t.is(p.containerPort, 80)
t.is(p.incomplete, true)
})
test('parsePortMapping empty host with colon is incomplete', (t) => {
// Unusual but guard against blank host field serialization
const p = parsePortMapping(':443/tcp', 0)
t.ok(p)
t.is(p.containerPort, 443)
t.is(p.incomplete, true)
})
test('validateNetworkingSync rejects empty host ports', (t) => {
const r = validateNetworkingSync({
networkMode: 'bridge',
ports: ['80/tcp', '443/udp'],
})
t.not(r.ok === true && r.errors.length === 0)
t.ok(r.errors.length >= 2)
t.ok(r.errors.some((e) => /host port is empty/i.test(e)))
})
test('validateNetworkingSync accepts full mappings', (t) => {
const r = validateNetworkingSync({
networkMode: 'bridge',
ports: ['8080:80/tcp', '8443:443/tcp'],
})
t.is(r.errors.length, 0)
t.is(r.parsed.length, 2)
})
test('validateNetworkingSync detects duplicate host ports', (t) => {
const r = validateNetworkingSync({
ports: ['8080:80/tcp', '8080:81/tcp'],
})
t.ok(r.errors.some((e) => /more than once/i.test(e)))
})
test('validateNetworkingSync warns on privileged ports', (t) => {
const r = validateNetworkingSync({
ports: ['80:80/tcp'],
})
t.is(r.errors.length, 0)
t.ok(r.warnings.some((e) => /privileged/i.test(e)))
})
test('validateNetworkingSync host mode warns about ignored mappings', (t) => {
const r = validateNetworkingSync({
networkMode: 'host',
ports: ['8080:80/tcp'],
})
t.is(r.errors.length, 0)
t.ok(r.warnings.some((e) => /host/i.test(e) && /ignored/i.test(e)))
})
test('validateNetworkingSync container mode requires peer container', (t) => {
const r = validateNetworkingSync({
networkMode: 'container',
customNetwork: '',
ports: [],
})
t.ok(r.errors.some((e) => /peer container/i.test(e)))
})
test('precheckDeployNetworking flags used host ports', async (t) => {
const r = await precheckDeployNetworking(
{ networkMode: 'bridge', ports: ['8080:80/tcp'] },
{ usedPorts: [8080, 9000] }
)
t.not(r.ok)
t.ok(r.errors.some((e) => /already published/i.test(e)))
})
test('precheckDeployNetworking ok when free', async (t) => {
const r = await precheckDeployNetworking(
{ networkMode: 'bridge', ports: ['8080:80/tcp'] },
{ usedPorts: [9000] }
)
t.ok(r.ok)
})
test('formatNetworkingPrecheckMessage joins errors', (t) => {
const msg = formatNetworkingPrecheckMessage({
errors: ['a', 'b'],
warnings: ['c'],
})
t.ok(msg.includes('a'))
t.ok(msg.includes('b'))
})