import { afterAll, beforeEach, describe, expect, it } from "vitest"; import { prisma } from "@/lib/db"; import { vorgangEinreihen, vorgangLesen } from "@/server/vorgaenge/vorgaenge"; import { WARTESCHLANGE, warteschlangeHolen, type VorgangsJob } from "@/server/vorgaenge/warteschlange"; import { VorgangsFehler, vorgangAusfuehren, type HandlerTabelle } from "@/worker/ausfuehren"; import { datenbankLeeren } from "./hilfen/db"; /** Vorgaenge zwischen Web und Worker (#007). */ beforeEach(async () => { await datenbankLeeren(); }); afterAll(async () => { const boss = await warteschlangeHolen(); await boss.stop({ graceful: false }); }); async function anlegen() { return prisma.vorgang.create({ data: { art: "ERREICHBARKEIT" } }); } describe("Vorgang ausfuehren", () => { it("haelt Ergebnis und Status fest", async () => { const vorgang = await anlegen(); const handler: HandlerTabelle = { ERREICHBARKEIT: async () => ({ ergebnis: { erreichbar: true } }) }; await vorgangAusfuehren(vorgang.id, handler); const fertig = await vorgangLesen(vorgang.id); expect(fertig?.status).toBe("ERLEDIGT"); expect(fertig?.ergebnis).toEqual({ erreichbar: true }); expect(fertig?.beendetAm).not.toBeNull(); }); it("zeigt nur Meldungen von VorgangsFehlern, alles andere allgemein", async () => { const a = await anlegen(); await vorgangAusfuehren(a.id, { ERREICHBARKEIT: async () => { throw new VorgangsFehler("Host antwortet nicht."); }, }); expect((await vorgangLesen(a.id))?.fehler).toBe("Host antwortet nicht."); const b = await anlegen(); await vorgangAusfuehren(b.id, { ERREICHBARKEIT: async () => { throw new Error("-----BEGIN OPENSSH PRIVATE KEY----- geheim"); }, }); const fehler = (await vorgangLesen(b.id))?.fehler ?? ""; expect(fehler).not.toContain("PRIVATE KEY"); expect(fehler).toMatch(/Interner Fehler/); }); it("startet einen Vorgang nur einmal", async () => { const vorgang = await anlegen(); let aufrufe = 0; const handler: HandlerTabelle = { ERREICHBARKEIT: async () => { aufrufe += 1; return {}; }, }; await Promise.all([vorgangAusfuehren(vorgang.id, handler), vorgangAusfuehren(vorgang.id, handler)]); expect(aufrufe).toBe(1); }); it("meldet fehlende Handler verstaendlich", async () => { const vorgang = await anlegen(); await vorgangAusfuehren(vorgang.id, {}); expect((await vorgangLesen(vorgang.id))?.fehler).toMatch(/noch keine Ausführung/); }); }); describe("Warteschlange", () => { it("bringt einen eingereihten Vorgang bis in den Worker", async () => { const boss = await warteschlangeHolen(); const id = await vorgangEinreihen({ art: "ERREICHBARKEIT", angefordertVonId: null, eingabe: { probe: 1 }, }); // Die Warteschlange ueberlebt das Leeren der Tabellen; deshalb gezielt den eigenen Job suchen. const jobs = await boss.fetch(WARTESCHLANGE, { batchSize: 100 }); const job = jobs.find((kandidat) => kandidat.data.vorgangId === id); expect(job?.data).toEqual({ vorgangId: id }); await vorgangAusfuehren(job!.data.vorgangId, { ERREICHBARKEIT: async () => ({ ergebnis: "ok" }) }); await boss.complete(WARTESCHLANGE, job!.id); expect((await vorgangLesen(id))?.status).toBe("ERLEDIGT"); }); });