Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
use OpenNIT\Content\UpdateManager;
/**
* Deckt die Schranken vor einem Update ab.
*
* Ein Update tauscht Dateien aus und ändert das Datenbankschema. OpenNIT
* sichert sich nicht selbst und kann den Vorgang nicht zurückrollen – bricht er
* auf halbem Weg ab, bleibt die Installation in einem Zwischenzustand. Deshalb
* müssen die Voraussetzungen vorher stimmen und eine Sicherung bestätigt sein.
*/
return static function (): void {
/** Erzeugt den Manager ohne Konstruktor und setzt die benötigten Pfade. */
$bau = static function (?string $basePath = null): UpdateManager {
$klasse = new ReflectionClass(UpdateManager::class);
$mgr = $klasse->newInstanceWithoutConstructor();
$setze = static function (string $feld, $wert) use ($klasse, $mgr): void {
$p = $klasse->getProperty($feld);
$p->setAccessible(true);
$p->setValue($mgr, $wert);
};
$wurzel = $basePath ?? dirname(__DIR__);
$setze('basePath', $wurzel);
$setze('migrationsDir', $wurzel . '/database/migrations');
return $mgr;
};
// ----------------------------------------------------------------
// Sicherungsbestätigung
// ----------------------------------------------------------------
test('Ohne bestätigte Sicherung startet kein Update', function () use ($bau) {
$mgr = $bau();
foreach (['installUpdate', 'applyStaged'] as $methode) {
$ergebnis = $mgr->$methode(1, false);
assertFalse($ergebnis['success'], $methode . ' läuft ohne Bestätigung an');
assertTrue(
str_contains($ergebnis['message'], 'Sicherung'),
$methode . ' begründet die Ablehnung nicht'
);
}
});
test('Die Bestätigung ist der Voreinstellung nach nicht gesetzt', function () use ($bau) {
// Ein Aufruf ohne das Argument darf nicht als bestätigt gelten – sonst
// ginge die Schranke bei einem übersehenen Aufrufer still verloren.
$ergebnis = $bau()->applyStaged(1);
assertFalse($ergebnis['success']);
assertTrue(str_contains($ergebnis['message'], 'Sicherung'));
});
// ----------------------------------------------------------------
// Voraussetzungen
// ----------------------------------------------------------------
test('Die Prüfung benennt jede Voraussetzung einzeln', function () use ($bau) {
$ergebnis = $bau()->preflight();
assertTrue(is_array($ergebnis['checks']), 'Keine Einzelergebnisse');
$namen = array_column($ergebnis['checks'], 'name');
foreach ([
'Freier Speicherplatz',
'Projektverzeichnis beschreibbar',
'Speicherverzeichnis beschreibbar',
'Datenbank beschreibbar',
'Ausstehende Migrationen lesbar',
] as $erwartet) {
assertTrue(in_array($erwartet, $namen, true), 'Prüfung fehlt: ' . $erwartet);
}
});
test('Ein nicht beschreibbares Verzeichnis lässt die Prüfung durchfallen', function () use ($bau) {
// Ein Pfad, den es nicht gibt, ist weder Verzeichnis noch beschreibbar.
$ergebnis = $bau('/nicht/vorhanden/opennit')->preflight();
assertFalse($ergebnis['ok'], 'Die Prüfung gilt trotz fehlender Schreibrechte als bestanden');
$durchgefallen = array_column(
array_filter($ergebnis['checks'], static fn(array $c): bool => !$c['ok']),
'name'
);
assertTrue(
in_array('Projektverzeichnis beschreibbar', $durchgefallen, true),
'Fehlende Schreibrechte werden nicht benannt'
);
});
test('Eine durchgefallene Prüfung verhindert das Update auch mit Bestätigung', function () use ($bau) {
$ergebnis = $bau('/nicht/vorhanden/opennit')->applyStaged(1, true);
assertFalse($ergebnis['success']);
assertTrue(
str_contains($ergebnis['message'], 'Voraussetzungen'),
'Die Ablehnung nennt die Voraussetzungen nicht'
);
assertTrue(isset($ergebnis['preflight']), 'Das Prüfergebnis wird nicht zurückgegeben');
});
};