Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
108 lines
3.8 KiB
JavaScript
108 lines
3.8 KiB
JavaScript
import { execFileSync } from 'node:child_process'
|
|
import { createRequire } from 'node:module'
|
|
import { fileURLToPath } from 'node:url'
|
|
import pg from 'pg'
|
|
import { loadEnvFromRepoRoot } from '../dist/loadEnv.js'
|
|
import { resolveTestDatabaseUrl } from '../dist/testDatabase.js'
|
|
|
|
/**
|
|
* Setzt die Testdatenbank neu auf und bringt sie auf den Migrationsstand.
|
|
* Wird von `pnpm test` vorgeschaltet.
|
|
*
|
|
* **Neu aufsetzen, nicht nur anlegen.** Verlaufseinträge, Akten und
|
|
* Protokollzeilen sind nach Zusicherung 2 der README nicht löschbar - was
|
|
* ein Testlauf anlegt, bleibt für immer stehen. Nach einigen Dutzend Läufen
|
|
* standen 2487 Akten in der Datenbank, und Tests, die eine auf zehn Einträge
|
|
* begrenzte Liste prüfen, fanden ihre eigene Akte nicht mehr darin. Solche
|
|
* Fehlschläge sehen aus wie ein Fehler im Code und sind keiner; das kostet mehr
|
|
* Zeit als das Neuaufsetzen.
|
|
*
|
|
* `KEEP_TEST_DB=1` behält den Bestand. Für das schnelle Nacheinander beim
|
|
* Arbeiten an einer einzelnen Testdatei.
|
|
*
|
|
* Läuft nur in der Entwicklung und in der CI, nie im Betrieb.
|
|
*/
|
|
loadEnvFromRepoRoot()
|
|
|
|
const testUrl = resolveTestDatabaseUrl()
|
|
const dbName = new URL(testUrl).pathname.replace(/^\//, '')
|
|
|
|
const maintenance = new URL(testUrl)
|
|
maintenance.pathname = '/postgres'
|
|
|
|
const client = new pg.Client({ connectionString: maintenance.toString() })
|
|
await client.connect()
|
|
// Bezeichner lassen sich nicht als Parameter binden, deshalb quotiert. Der Name
|
|
// kommt aus resolveTestDatabaseUrl und endet immer auf _test.
|
|
const quoted = `"${dbName.replace(/"/g, '""')}"`
|
|
|
|
if (!dbName.endsWith('_test')) {
|
|
throw new Error(`Sicherung: ${dbName} endet nicht auf _test, wird nicht angefasst`)
|
|
}
|
|
|
|
try {
|
|
const { rowCount } = await client.query('SELECT 1 FROM pg_database WHERE datname = $1', [dbName])
|
|
const behalten = process.env.KEEP_TEST_DB === '1'
|
|
|
|
if (rowCount > 0 && !behalten) {
|
|
// Offene Verbindungen verhindern das Verwerfen - etwa ein Prisma Studio
|
|
// oder ein abgebrochener Testlauf.
|
|
await client.query(
|
|
`SELECT pg_terminate_backend(pid) FROM pg_stat_activity
|
|
WHERE datname = $1 AND pid <> pg_backend_pid()`,
|
|
[dbName],
|
|
)
|
|
await client.query(`DROP DATABASE ${quoted}`)
|
|
console.log(`[test-db] ${dbName} verworfen`)
|
|
}
|
|
|
|
if (rowCount === 0 || !behalten) {
|
|
await client.query(`CREATE DATABASE ${quoted}`)
|
|
console.log(`[test-db] ${dbName} angelegt`)
|
|
} else {
|
|
console.log(`[test-db] ${dbName} behalten (KEEP_TEST_DB=1)`)
|
|
}
|
|
} finally {
|
|
await client.end()
|
|
}
|
|
|
|
const require = createRequire(import.meta.url)
|
|
const prismaCli = require.resolve('prisma/build/index.js')
|
|
|
|
const testEnv = { ...process.env, DATABASE_URL: testUrl, DIRECT_DATABASE_URL: testUrl }
|
|
|
|
execFileSync(process.execPath, [prismaCli, 'migrate', 'deploy'], {
|
|
stdio: 'inherit',
|
|
env: testEnv,
|
|
})
|
|
|
|
// Der Auslieferungszustand gehört auch in die Testdatenbank: Freigabestufen und
|
|
// Änderungsrichtlinie werden von Tests vorausgesetzt. Der Seed ist idempotent.
|
|
const tsxCli = require.resolve('tsx/cli')
|
|
execFileSync(process.execPath, [tsxCli, 'prisma/seed.ts'], {
|
|
stdio: 'inherit',
|
|
cwd: fileURLToPath(new URL('..', import.meta.url)),
|
|
env: testEnv,
|
|
})
|
|
|
|
// Die Änderungsrichtlinie ist eine einzige Zeile für die ganze Anwendung. Der
|
|
// Seed lässt sie bewusst in Ruhe, damit er die Einstellung des Leiters nicht
|
|
// überschreibt - in der Testdatenbank soll sie aber bei jedem Lauf im
|
|
// Auslieferungszustand starten, sonst hängt das Ergebnis davon ab, was der
|
|
// vorige Lauf hinterlassen hat.
|
|
const reset = new pg.Client({ connectionString: testUrl })
|
|
await reset.connect()
|
|
try {
|
|
await reset.query(
|
|
`UPDATE "AppSetting"
|
|
SET "entryEditPolicy" = 'GRACE_WINDOW',
|
|
"entryEditGraceMinutes" = 15,
|
|
"entryEditMarkGrace" = false
|
|
WHERE id = 1`,
|
|
)
|
|
} finally {
|
|
await reset.end()
|
|
}
|
|
|
|
console.log(`[test-db] ${dbName} ist auf Stand`)
|