69 lines
3.6 KiB
TypeScript
69 lines
3.6 KiB
TypeScript
// @ts-expect-error -- bun:test is a runtime built-in with no types installed
|
|
import { describe, expect, test } from 'bun:test';
|
|
import { deriveContextFromLists } from '../../src/lib/server/compose-validate/context-core';
|
|
|
|
describe('deriveContextFromLists', () => {
|
|
const containers = [
|
|
{ name: 'other-web-1', ports: [{ PublicPort: 8080 }, { PublicPort: 443 }] },
|
|
{ name: 'mystack-db-1', ports: [{ PublicPort: 5432 }] } // self
|
|
];
|
|
|
|
test('collects used host ports and container names', () => {
|
|
const ctx = deriveContextFromLists(containers, ['proxy'], ['data']);
|
|
expect([...ctx.usedHostPorts!].sort()).toEqual([443, 5432, 8080]);
|
|
expect(ctx.existingContainerNames!.has('other-web-1')).toBe(true);
|
|
expect(ctx.existingNetworks!.has('proxy')).toBe(true);
|
|
expect(ctx.existingVolumes!.has('data')).toBe(true);
|
|
});
|
|
|
|
test('excludes THIS stack own containers (self)', () => {
|
|
const ctx = deriveContextFromLists(containers, [], [], 'mystack');
|
|
expect(ctx.usedHostPorts!.has(5432)).toBe(false); // self db port not counted
|
|
expect(ctx.usedHostPorts!.has(8080)).toBe(true); // other stack still counted
|
|
expect(ctx.existingContainerNames!.has('mystack-db-1')).toBe(false);
|
|
});
|
|
|
|
test('excludes self by compose project LABEL even with a custom container_name', () => {
|
|
// A service with `container_name: wzml` runs as a container literally named "wzml"
|
|
// (no `<stack>-` prefix), so name-prefix matching misses it. The compose project
|
|
// label is authoritative and must still exclude it - otherwise editing the running
|
|
// stack falsely reports a container_name collision against itself.
|
|
const withCustomNames = [
|
|
{ name: 'wzml', ports: [{ PublicPort: 8080 }], labels: { 'com.docker.compose.project': 'wzml' } },
|
|
{ name: 'wzml_tunnel', labels: { 'com.docker.compose.project': 'wzml' } },
|
|
{ name: 'unrelated', ports: [{ PublicPort: 9090 }], labels: { 'com.docker.compose.project': 'other' } }
|
|
];
|
|
const ctx = deriveContextFromLists(withCustomNames, [], [], 'wzml');
|
|
expect(ctx.existingContainerNames!.has('wzml')).toBe(false); // self, excluded
|
|
expect(ctx.existingContainerNames!.has('wzml_tunnel')).toBe(false); // self, excluded
|
|
expect(ctx.existingContainerNames!.has('unrelated')).toBe(true); // other stack kept
|
|
// Ports follow the same exclusion: the self stack's published port is NOT counted
|
|
// (so re-editing it isn't flagged as a cross-stack port collision), but another
|
|
// stack's port still is.
|
|
expect(ctx.usedHostPorts!.has(8080)).toBe(false); // self port, excluded
|
|
expect(ctx.usedHostPorts!.has(9090)).toBe(true); // other stack port kept
|
|
});
|
|
|
|
test('create mode (no selfStackName) excludes nothing - a name clash must be flagged', () => {
|
|
// A NEW stack named "wzml" has no own containers yet; a running "wzml" must still
|
|
// be reported as a collision, so with selfStackName null/undefined nothing is excluded.
|
|
const running = [
|
|
{ name: 'wzml', ports: [{ PublicPort: 8080 }], labels: { 'com.docker.compose.project': 'wzml' } }
|
|
];
|
|
const ctx = deriveContextFromLists(running, [], [], null);
|
|
expect(ctx.existingContainerNames!.has('wzml')).toBe(true); // clash surfaced
|
|
expect(ctx.usedHostPorts!.has(8080)).toBe(true);
|
|
});
|
|
|
|
test('ignores containers with no published ports', () => {
|
|
const ctx = deriveContextFromLists([{ name: 'x-1', ports: [] }], [], []);
|
|
expect(ctx.usedHostPorts!.size).toBe(0);
|
|
});
|
|
|
|
test('maps each used port to the container that publishes it', () => {
|
|
const ctx = deriveContextFromLists(containers, [], []);
|
|
expect(ctx.hostPortOwners!.get(8080)).toBe('other-web-1');
|
|
expect(ctx.hostPortOwners!.get(443)).toBe('other-web-1');
|
|
});
|
|
});
|