108 lines
3.8 KiB
TypeScript
108 lines
3.8 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test";
|
|
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import { readCompose, resolveComposeFile } from "../../lib/yaml";
|
|
|
|
const temporaryDirectories: string[] = [];
|
|
|
|
async function temporaryDirectory(): Promise<string> {
|
|
const path = await mkdtemp(join(tmpdir(), "kuber-test-"));
|
|
temporaryDirectories.push(path);
|
|
return path;
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
temporaryDirectories
|
|
.splice(0)
|
|
.map((path) => rm(path, { recursive: true, force: true })),
|
|
);
|
|
});
|
|
|
|
describe("Compose file discovery", () => {
|
|
test("finds supported names and chooses lexical precedence", async () => {
|
|
const directory = await temporaryDirectory();
|
|
await Promise.all([
|
|
writeFile(join(directory, "docker-compose.yml"), "services: {}\n"),
|
|
writeFile(join(directory, "compose.yaml"), "services: {}\n"),
|
|
writeFile(join(directory, "ignored.yml"), "services: {}\n"),
|
|
]);
|
|
expect(await resolveComposeFile(directory)).toBe(
|
|
join(directory, "compose.yaml"),
|
|
);
|
|
});
|
|
|
|
test("ignores directories with Compose-looking names", async () => {
|
|
const directory = await temporaryDirectory();
|
|
await mkdir(join(directory, "compose.yml"));
|
|
expect(await resolveComposeFile(directory)).toBeUndefined();
|
|
});
|
|
|
|
test("returns undefined when no supported file exists", async () => {
|
|
const directory = await temporaryDirectory();
|
|
await writeFile(join(directory, "stack.yml"), "services: {}\n");
|
|
expect(await resolveComposeFile(directory)).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("Compose parsing", () => {
|
|
test("accepts the generated marker and preserves x- extensions", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
await writeFile(
|
|
path,
|
|
"managedBy: kuber # See https://npmx.dev/@dmgnr/kuber for documentation.\nname: compose-project\nx-note: retained\nservices:\n app:\n image: nginx:latest\n",
|
|
);
|
|
expect(await readCompose(path)).toMatchObject({
|
|
managedBy: "kuber",
|
|
name: "compose-project",
|
|
"x-note": "retained",
|
|
services: { app: { image: "nginx:latest" } },
|
|
});
|
|
});
|
|
|
|
test("rejects incorrect managedBy values", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
for (const marker of ["other", "42"]) {
|
|
await writeFile(path, `managedBy: ${marker}\nservices: {}\n`);
|
|
await expect(readCompose(path)).rejects.toThrow();
|
|
}
|
|
});
|
|
|
|
test("rejects other unknown top-level properties", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
await writeFile(path, "managedBy: kuber\nunknown: value\nservices: {}\n");
|
|
await expect(readCompose(path)).rejects.toThrow();
|
|
});
|
|
|
|
test("parses and validates a minimal Compose project", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
await writeFile(
|
|
path,
|
|
"name: compose-project\nservices:\n app:\n image: nginx:latest\n",
|
|
);
|
|
expect(await readCompose(path)).toMatchObject({
|
|
name: "compose-project",
|
|
services: { app: { image: "nginx:latest" } },
|
|
});
|
|
});
|
|
|
|
test("rejects malformed YAML", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
await writeFile(path, "services: [\n");
|
|
await expect(readCompose(path)).rejects.toThrow();
|
|
});
|
|
|
|
test("rejects schema-invalid service values", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const path = join(directory, "compose.yml");
|
|
await writeFile(path, "services:\n app: 42\n");
|
|
await expect(readCompose(path)).rejects.toThrow();
|
|
});
|
|
});
|