111 lines
4.3 KiB
TypeScript
111 lines
4.3 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
/**
|
|
* Die Installationsanleitung muss ausführbar sein, nicht nur lesbar.
|
|
*
|
|
* Anlass ist eine Fehlersuche vom 31.08.2026. Drei Stellen der Anleitung
|
|
* haben dabei Zeit gekostet — keine davon war falsch formuliert, alle drei
|
|
* waren schlicht nicht durchdacht:
|
|
*
|
|
* 1. `mc alias set` wurde einmalig gesetzt. Der Alias liegt in `/root/.mc`
|
|
* **im Behälter** und ist nach jedem `docker compose up -d minio` weg.
|
|
* `mc ls lokal` liefert dann kommentarlos nichts — man hält seine
|
|
* Dokumente für verschwunden.
|
|
* 2. Der Bucket-Name stand fest im Befehl, die Anwendung liest ihn aus
|
|
* `S3_BUCKET`. Weichen sie ab, zeigen beide aneinander vorbei.
|
|
* 3. `set -a && source .env` exportiert alle Werte in die Shell — und die
|
|
* haben danach Vorrang vor der `.env`-Datei. Wer später etwas ändert
|
|
* und neu startet, sieht keine Wirkung.
|
|
*
|
|
* Diese Prüfungen lesen den Text. Sie können die Anleitung nicht
|
|
* ausführen, aber sie schlagen an, sobald jemand in eine der Fallen
|
|
* zurückfällt.
|
|
*/
|
|
|
|
const anleitung = readFileSync('docs/INSTALLATION.md', 'utf8')
|
|
|
|
/** Alle Zeilen mit einem mc-Aufruf, ohne Fließtext und Zitate. */
|
|
function mcZeilen(): string[] {
|
|
return anleitung
|
|
.split('\n')
|
|
.filter((zeile) => /\bmc (ls|mb|mirror|cp|rm|stat)\b/.test(zeile))
|
|
.filter((zeile) => !zeile.trim().startsWith('>'))
|
|
}
|
|
|
|
describe('Installationsanleitung', () => {
|
|
it('setzt bei jedem mc-Aufruf den Alias selbst', () => {
|
|
// Sonst funktioniert der Befehl nur, solange der Behaelter nicht neu
|
|
// erstellt wurde - und das sagt einem niemand.
|
|
const abschnitte = anleitung.split('```')
|
|
const ohneAlias = abschnitte
|
|
.filter((block) => /\bmc (ls|mb|mirror|cp|rm|stat)\b/.test(block))
|
|
.filter((block) => !block.includes('mc alias set'))
|
|
|
|
expect(
|
|
ohneAlias.length,
|
|
'Ein mc-Befehl ohne "mc alias set" im selben Block läuft nur, solange ' +
|
|
'der MinIO-Behälter nicht neu erstellt wurde.',
|
|
).toBe(0)
|
|
})
|
|
|
|
it('verdrahtet den Namen des Ablagebereichs nicht fest', () => {
|
|
const festVerdrahtet = mcZeilen().filter((zeile) => /lokal\/betreuungs-cockpit/.test(zeile))
|
|
|
|
expect(
|
|
festVerdrahtet,
|
|
'Der Name gehört aus $S3_BUCKET - sonst zeigen Anwendung und ' +
|
|
'Ablagebereich aneinander vorbei, sobald jemand ihn ändert.',
|
|
).toEqual([])
|
|
})
|
|
|
|
it('empfiehlt kein "source .env" mehr', () => {
|
|
// Exportierte Werte ueberstimmen danach jedes "docker compose up".
|
|
const zeilen = anleitung
|
|
.split('\n')
|
|
.filter((zeile) => !zeile.trim().startsWith('>'))
|
|
.filter((zeile) => !zeile.trim().startsWith('#'))
|
|
.filter((zeile) => /source \.env/.test(zeile))
|
|
|
|
expect(zeilen).toEqual([])
|
|
})
|
|
|
|
it('erklärt trotzdem, warum es nicht empfohlen wird', () => {
|
|
// Weglassen allein hilft nicht: Wer den Kniff von woanders kennt,
|
|
// benutzt ihn weiter.
|
|
expect(anleitung).toMatch(/Vorrang vor der/)
|
|
})
|
|
|
|
it('sagt, wo die Daten liegen', () => {
|
|
expect(anleitung).toMatch(/## Wo deine Daten liegen/)
|
|
expect(anleitung).toMatch(/docker volume inspect/)
|
|
expect(anleitung).toMatch(/minio-daten/)
|
|
expect(anleitung).toMatch(/postgres-daten/)
|
|
})
|
|
|
|
it('zeigt, wie man Akte und Speicher abgleicht', () => {
|
|
// Die wichtigste Kontrolle: Zu jedem Akteneintrag muss eine Datei
|
|
// gehoeren, sonst belegt eine Pruefsumme ein Dokument, das es nicht
|
|
// mehr gibt.
|
|
expect(anleitung).toMatch(/objektSchluessel/)
|
|
expect(anleitung).toMatch(/comm -23/)
|
|
})
|
|
|
|
it('nennt die Schlüssel, ohne die nichts mehr lesbar ist', () => {
|
|
const abschnitt = anleitung.slice(anleitung.indexOf('## Wo deine Daten liegen'))
|
|
for (const schluessel of ['ENC_KEY_V1', 'SICHERUNG_PASSWORT', 'MINIO_KMS_SECRET_KEY']) {
|
|
expect(abschnitt, `${schluessel} fehlt in der Aufzählung`).toContain(schluessel)
|
|
}
|
|
})
|
|
|
|
it('weist docker-compose.override.yml als Ort für eigene Anpassungen aus', () => {
|
|
expect(anleitung).toMatch(/docker-compose\.override\.yml/)
|
|
expect(readFileSync('.gitignore', 'utf8')).toMatch(/docker-compose\.override\.yml/)
|
|
})
|
|
|
|
it('behauptet nicht mehr, die Dokumente seien ungesichert', () => {
|
|
// Stand bis v1.12.0 so drin und stimmt seit der Sicherung nicht mehr.
|
|
expect(anleitung).not.toMatch(/Was das Backup nicht enthält:.*Dateien im Objektspeicher/s)
|
|
})
|
|
})
|