import { beforeEach, describe, expect, it } from "vitest"; import * as liste from "@/app/api/v1/auftraege/route"; import * as aufraeumenRoute from "@/app/api/v1/auftraege/[id]/aufraeumen/route"; import { verschluesseln } from "@/lib/geheimnisse"; import { auftragHolen, verlaufFilterAus, VERLAUF_PRO_SEITE } from "@/server/services/auftraege"; import { katalogSynchronisieren } from "@/server/services/katalog"; import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db"; import { angemeldet, anfrage, kontext } from "./helpers/anfragen"; describe("Verlaufsfilter aus der URL", () => { it("übernimmt Gültiges und lässt Unsinn still fallen", () => { expect(verlaufFilterAus({ typ: "lxc", status: "FEHLGESCHLAGEN", seite: "3", server: "rz1" })).toEqual({ typ: "lxc", status: "FEHLGESCHLAGEN", seite: 3, server: "rz1", }); expect(verlaufFilterAus({ typ: "quatsch", status: "x", seite: "-4", distribution: "" })).toEqual({ seite: 1, }); }); }); describe.runIf(datenbankVerfuegbar)("Verlauf und Aufräumen", () => { let cookie: string; let benutzerId: string; let serverIds: Record; beforeEach(async () => { await datenbankLeeren(); await katalogSynchronisieren(); const op = await angemeldet("OPERATOR"); cookie = op.cookie; benutzerId = op.benutzer.id; serverIds = {}; for (const name of ["rz1", "rz2"]) { serverIds[name] = ( await testPrisma.server.create({ data: { name, titel: name, url: "https://127.0.0.1:8006", tokenId: "a@pve!b", tokenGeheimnis: verschluesseln("x"), fingerabdruck: "AA", }, }) ).id; } }); let nr = 0; const auftrag = async (daten: Record) => await testPrisma.auftrag.create({ data: { kurzId: `d-t${String(nr++).padStart(4, "0")}`, art: "AUSROLLEN", status: "ERFOLGREICH", quelle: "WEB", serverId: serverIds["rz1"]!, erstelltVonId: benutzerId, anfrage: {}, ...daten, } as never, }); it("filtert nach Server, Typ, Distribution und Status und blättert", async () => { await auftrag({ gastTyp: "VM", distributionId: "debian-13" }); await auftrag({ gastTyp: "LXC", distributionId: "ubuntu-24.04", status: "FEHLGESCHLAGEN" }); await auftrag({ gastTyp: "LXC", distributionId: "debian-13", serverId: serverIds["rz2"] }); await auftrag({ art: "TEMPLATE_BAUEN", gastTyp: "VM", distributionId: "debian-13" }); const holen = async (abfrage: string) => (await (await liste.GET(anfrage("GET", `/api/v1/auftraege?${abfrage}`, cookie))).json()) as { eintraege: Array<{ kurzId: string; art: string; gastTyp: string }>; gesamt: number; seiten: number; }; expect((await holen("")).gesamt).toBe(4); expect((await holen("typ=lxc")).gesamt).toBe(2); expect((await holen("typ=vm")).gesamt).toBe(1); expect((await holen("typ=template")).eintraege[0]!.art).toBe("TEMPLATE_BAUEN"); expect((await holen("server=rz2")).gesamt).toBe(1); expect((await holen("distribution=debian-13&typ=lxc")).gesamt).toBe(1); expect((await holen("status=FEHLGESCHLAGEN")).gesamt).toBe(1); for (let i = 0; i < VERLAUF_PRO_SEITE; i++) await auftrag({ gastTyp: "VM" }); const erste = await holen(""); const zweite = await holen("seite=2"); expect(erste.seiten).toBe(2); expect(erste.eintraege).toHaveLength(VERLAUF_PRO_SEITE); expect(zweite.eintraege).toHaveLength(4); expect(new Set([...erste.eintraege, ...zweite.eintraege].map((e) => e.kurzId)).size).toBe( VERLAUF_PRO_SEITE + 4, ); }); const starten = async (kurzId: string) => await aufraeumenRoute.POST( anfrage("POST", `/api/v1/auftraege/${kurzId}/aufraeumen`, cookie), kontext({ id: kurzId }), ); it("Aufräumen nur bei Fehlschlag/Abbruch mit angelegtem Gast, nie doppelt", async () => { const ok = await auftrag({ gastTyp: "VM", angelegt: { vmid: 120, knoten: "pve01", typ: "VM" } }); const nichts = await auftrag({ gastTyp: "VM", status: "FEHLGESCHLAGEN", angelegt: { knoten: "pve01" } }); const kaputt = await auftrag({ gastTyp: "LXC", name: "ct01", status: "ABGEBROCHEN", angelegt: { vmid: 121, knoten: "pve01", typ: "LXC" }, }); expect((await auftragHolen(ok.kurzId)).aufraeumbar).toBeNull(); expect((await auftragHolen(nichts.kurzId)).aufraeumbar).toBeNull(); expect((await auftragHolen(kaputt.kurzId)).aufraeumbar).toEqual({ typ: "LXC", vmid: 121, knoten: "pve01", }); expect((await starten(ok.kurzId)).status).toBe(409); expect((await starten(nichts.kurzId)).status).toBe(409); const gestartet = await starten(kaputt.kurzId); expect(gestartet.status).toBe(202); const { kurzId } = (await gestartet.json()) as { kurzId: string }; expect(kurzId).toMatch(/^c-/); const neu = await testPrisma.auftrag.findUniqueOrThrow({ where: { kurzId } }); expect(neu).toMatchObject({ art: "AUFRAEUMEN", bezugId: kaputt.id, gastTyp: "LXC", name: "ct01" }); expect(neu.anfrage).toEqual({ auftrag: kaputt.kurzId, typ: "LXC", vmid: 121, knoten: "pve01" }); const doppelt = await starten(kaputt.kurzId); expect(doppelt.status).toBe(409); expect((await doppelt.json()).fehler.nachricht).toContain(kurzId); expect(await testPrisma.protokoll.count({ where: { aktion: "Aufräumen gestartet" } })).toBe(1); }); });