Fünf Distributionen (Debian 12/13, Ubuntu 22.04/24.04/26.04) und drei Profile liegen unter catalog/ und werden beim Start abgeglichen. Die Datei ist maßgeblich für den Inhalt, die Datenbank nur für „aktiv“; verschwundene Einträge werden markiert, nicht gelöscht. Unbekannte Schlüssel sind Fehler, damit Tippfehler nicht still verschwinden; eine kaputte Datei wird mit Pfad gemeldet und übersprungen, statt den Start zu verhindern. Prüfsummen-Parser kennt das Debian-, Ubuntu- und BSD-Format; bei mehreren LXC-Templates gewinnt die höchste Version. Closes #004 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
104 lines
4.4 KiB
TypeScript
104 lines
4.4 KiB
TypeScript
import { cpSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { GET as distributionenGet } from "@/app/api/v1/distributionen/route";
|
|
import { PATCH as distributionPatch } from "@/app/api/v1/distributionen/[id]/route";
|
|
import { GET as profileGet } from "@/app/api/v1/profile/route";
|
|
import { katalogSynchronisieren } from "@/server/services/katalog";
|
|
import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db";
|
|
import { angemeldet, anfrage, kontext } from "./helpers/anfragen";
|
|
|
|
describe.runIf(datenbankVerfuegbar)("Katalog-Abgleich und API", () => {
|
|
let wurzel: string;
|
|
beforeEach(async () => {
|
|
await datenbankLeeren();
|
|
wurzel = mkdtempSync(join(tmpdir(), "pd-sync-"));
|
|
cpSync("catalog", wurzel, { recursive: true });
|
|
});
|
|
|
|
it("legt an, erkennt Änderungen über den Hash und ist idempotent", async () => {
|
|
const erst = await katalogSynchronisieren(wurzel);
|
|
expect(erst.distributionen).toEqual({ neu: 5, geaendert: 0, entfernt: 0 });
|
|
expect(erst.profile).toEqual({ neu: 3, geaendert: 0, entfernt: 0 });
|
|
|
|
const nochmal = await katalogSynchronisieren(wurzel);
|
|
expect(nochmal.distributionen).toEqual({ neu: 0, geaendert: 0, entfernt: 0 });
|
|
|
|
writeFileSync(
|
|
join(wurzel, "distros/debian-12.yaml"),
|
|
(await import("node:fs"))
|
|
.readFileSync(join(wurzel, "distros/debian-12.yaml"), "utf8")
|
|
.replace("Bookworm", "Bookworm (alt)"),
|
|
);
|
|
const geaendert = await katalogSynchronisieren(wurzel);
|
|
expect(geaendert.distributionen.geaendert).toBe(1);
|
|
expect((await testPrisma.distribution.findUniqueOrThrow({ where: { id: "debian-12" } })).name).toContain(
|
|
"(alt)",
|
|
);
|
|
});
|
|
|
|
it("behält „aktiv“ über Änderungen hinweg und markiert entfernte Dateien statt zu löschen", async () => {
|
|
await katalogSynchronisieren(wurzel);
|
|
await testPrisma.distribution.update({ where: { id: "ubuntu-22.04" }, data: { aktiv: false } });
|
|
rmSync(join(wurzel, "distros/ubuntu-22.04.yaml"));
|
|
const ergebnis = await katalogSynchronisieren(wurzel);
|
|
expect(ergebnis.distributionen.entfernt).toBe(1);
|
|
const zeile = await testPrisma.distribution.findUniqueOrThrow({ where: { id: "ubuntu-22.04" } });
|
|
expect(zeile.entferntAm).not.toBeNull();
|
|
expect(zeile.aktiv).toBe(false);
|
|
});
|
|
|
|
it("überschreibt kein eigenes Profil mit gleicher id", async () => {
|
|
await testPrisma.profil.create({
|
|
data: {
|
|
id: "docker",
|
|
name: "Mein Docker",
|
|
familien: ["debian"],
|
|
herkunft: "EIGEN",
|
|
definition: {},
|
|
quelltext: "x",
|
|
},
|
|
});
|
|
const ergebnis = await katalogSynchronisieren(wurzel);
|
|
expect(ergebnis.fehler.map((f) => f.meldung).join()).toMatch(/eigenes Profil „docker“/);
|
|
expect((await testPrisma.profil.findUniqueOrThrow({ where: { id: "docker" } })).name).toBe("Mein Docker");
|
|
});
|
|
|
|
it("API: Operator sieht nur aktive; Admin schaltet ab und sieht mit ?alle=1 alles", async () => {
|
|
await katalogSynchronisieren(wurzel);
|
|
const admin = (await angemeldet("ADMIN")).cookie;
|
|
const operator = (await angemeldet("OPERATOR")).cookie;
|
|
|
|
expect(
|
|
(
|
|
await distributionPatch(
|
|
anfrage("PATCH", "/api/v1/distributionen/debian-12", operator, { aktiv: false }),
|
|
kontext({ id: "debian-12" }),
|
|
)
|
|
).status,
|
|
).toBe(403);
|
|
expect(
|
|
(
|
|
await distributionPatch(
|
|
anfrage("PATCH", "/api/v1/distributionen/debian-12", admin, { aktiv: false }),
|
|
kontext({ id: "debian-12" }),
|
|
)
|
|
).status,
|
|
).toBe(200);
|
|
|
|
const fuerOperator = await (
|
|
await distributionenGet(anfrage("GET", "/api/v1/distributionen?typ=vm&alle=1", operator))
|
|
).json();
|
|
expect(fuerOperator.map((d: { id: string }) => d.id)).not.toContain("debian-12");
|
|
const fuerAdmin = await (
|
|
await distributionenGet(anfrage("GET", "/api/v1/distributionen?alle=1", admin))
|
|
).json();
|
|
expect(fuerAdmin.find((d: { id: string }) => d.id === "debian-12").aktiv).toBe(false);
|
|
|
|
const profile = await (await profileGet(anfrage("GET", "/api/v1/profile", operator))).json();
|
|
expect(profile.map((p: { id: string }) => p.id)).toEqual(["base", "docker", "zabbix-agent"]);
|
|
expect(await testPrisma.protokoll.count({ where: { aktion: "Distribution deaktiviert" } })).toBe(1);
|
|
});
|
|
});
|