Ein Laufzeit-Paket (scripts/paket-bauen.sh) für beide Wege: Next standalone, worker als Bundle mit nur den nötigen Paketen, Migrationen ohne Prisma-CLI. Compose lokal komplett hochgefahren; der Installer auf pve-demo in einem echten Debian-13-LXC durchgelaufen. Closes #019 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
||
import pg from "pg";
|
||
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||
import { migrieren } from "@/betrieb/migrieren";
|
||
import { datenbankVerfuegbar } from "./helpers/db";
|
||
|
||
const NAME = "proxdeploy_migtest";
|
||
|
||
describe.runIf(datenbankVerfuegbar)("Migrationen im Betrieb (ohne Prisma-CLI)", () => {
|
||
const basis = new URL(process.env["TEST_DATABASE_URL"]!);
|
||
const ziel = new URL(basis);
|
||
ziel.pathname = `/${NAME}`;
|
||
const verwaltung = async (sql: string) => {
|
||
const c = new pg.Client({ connectionString: basis.href });
|
||
await c.connect();
|
||
try {
|
||
await c.query(sql);
|
||
} finally {
|
||
await c.end();
|
||
}
|
||
};
|
||
|
||
beforeAll(async () => {
|
||
await verwaltung(`DROP DATABASE IF EXISTS ${NAME} WITH (FORCE)`);
|
||
await verwaltung(`CREATE DATABASE ${NAME}`);
|
||
});
|
||
afterAll(async () => {
|
||
await verwaltung(`DROP DATABASE IF EXISTS ${NAME} WITH (FORCE)`);
|
||
});
|
||
|
||
it("spielt alle ein, beim zweiten Mal nichts – und Prisma hält den Stand für aktuell", async () => {
|
||
const erstes = await migrieren(ziel.href, "prisma/migrations");
|
||
expect(erstes.eingespielt.length).toBeGreaterThan(5);
|
||
expect(erstes.eingespielt[0]).toMatch(/_grundgeruest$/);
|
||
expect(await migrieren(ziel.href, "prisma/migrations")).toEqual({
|
||
eingespielt: [],
|
||
vorhanden: erstes.eingespielt.length,
|
||
});
|
||
|
||
const status = execFileSync("pnpm", ["exec", "prisma", "migrate", "status"], {
|
||
env: { ...process.env, DATABASE_URL: ziel.href },
|
||
encoding: "utf8",
|
||
});
|
||
expect(status).toMatch(/Database schema is up to date/);
|
||
|
||
// Auch die Regeln aus den Migrationen (Trigger) sind da: das Audit-Log ist nur anhängbar.
|
||
const c = new pg.Client({ connectionString: ziel.href });
|
||
await c.connect();
|
||
try {
|
||
await c.query(`INSERT INTO "Protokoll" (quelle, aktion) VALUES ('SYSTEM', 'Test')`);
|
||
await expect(c.query(`DELETE FROM "Protokoll"`)).rejects.toThrow();
|
||
} finally {
|
||
await c.end();
|
||
}
|
||
});
|
||
|
||
it("verweigert, wenn eine eingespielte Migration verändert wurde", async () => {
|
||
const c = new pg.Client({ connectionString: ziel.href });
|
||
await c.connect();
|
||
await c.query(`UPDATE "_prisma_migrations" SET checksum = 'x' WHERE migration_name LIKE '%_server'`);
|
||
await c.end();
|
||
await expect(migrieren(ziel.href, "prisma/migrations")).rejects.toThrow(/verändert/);
|
||
});
|
||
});
|