feat(verlauf): Filter, Wiederholen und Aufräumen
Verlauf filterbar (URL, API, proxdeploy history); Wiederholen füllt den Assistenten aus einem alten Auftrag; Aufräumen löscht nach Fehlschlag oder Abbruch den halb angelegten Gast – nur, wenn dessen Beschreibung auf den Auftrag verweist. Deshalb setzt das Klonen die Beschreibung jetzt sofort. Auf pve-demo geprüft (CT 109). Closes #014 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
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<string, string>;
|
||||
|
||||
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<string, unknown>) =>
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user