Files
2026-05-25 17:14:26 -04:00

105 lines
3.1 KiB
TypeScript

import { Client } from "undici";
import { afterAll, beforeAll, describe, expect, test } from "vitest";
import DockerIntegration from "~/server/config/integration/docker";
import { type HeadscaleEnv, startHeadscale } from "../setup/start-headscale";
const TEST_LABEL_KEY = "me.tale.headplane.integration-test";
const TEST_LABEL_VALUE = `docker-${Date.now()}`;
describe("DockerIntegration", () => {
let env: HeadscaleEnv;
let dockerSocket: string;
beforeAll(async () => {
dockerSocket = process.env.DOCKER_HOST ?? "unix:///var/run/docker.sock";
env = await startHeadscale("0.25.1", {
labels: { [TEST_LABEL_KEY]: TEST_LABEL_VALUE },
});
}, 60_000);
afterAll(async () => {
await env?.container.stop({ remove: true, removeVolumes: true });
});
test("isAvailable finds the headscale container by label", async () => {
const integration = new DockerIntegration({
enabled: true,
container_label: `${TEST_LABEL_KEY}=${TEST_LABEL_VALUE}`,
socket: dockerSocket,
});
expect(await integration.isAvailable()).toBe(true);
});
test("isAvailable finds the headscale container by name", async () => {
const name = env.container.getName().replace(/^\//, "");
const integration = new DockerIntegration({
enabled: true,
container_name: name,
container_label: "unused=unused",
socket: dockerSocket,
});
expect(await integration.isAvailable()).toBe(true);
});
test("isAvailable returns false for a non-existent label", async () => {
const integration = new DockerIntegration({
enabled: true,
container_label: "me.tale.headplane.nonexistent=true",
socket: dockerSocket,
});
expect(await integration.isAvailable()).toBe(false);
});
test("isAvailable returns false for an invalid socket", async () => {
const integration = new DockerIntegration({
enabled: true,
container_label: `${TEST_LABEL_KEY}=${TEST_LABEL_VALUE}`,
socket: "unix:///tmp/nonexistent-docker.sock",
});
expect(await integration.isAvailable()).toBe(false);
});
test("onConfigChange restarts the container", async () => {
const integration = new DockerIntegration({
enabled: true,
container_label: `${TEST_LABEL_KEY}=${TEST_LABEL_VALUE}`,
socket: dockerSocket,
});
expect(await integration.isAvailable()).toBe(true);
// Health check goes through the Docker socket to avoid stale port
// mappings after container restart.
const containerId = env.container.getId();
const dockerClient = new Client("http://localhost", {
socketPath: "/var/run/docker.sock",
});
const mockHeadscale = {
health: async () => {
try {
const res = await dockerClient.request({
method: "GET",
path: `/v1.44/containers/${containerId}/json`,
});
const info = (await res.body.json()) as any;
return info.State?.Running === true;
} catch {
return false;
}
},
} as any;
await integration.onConfigChange(mockHeadscale);
const healthy = await mockHeadscale.health();
expect(healthy).toBe(true);
}, 60_000);
});