OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

UpdateGuardTest.php

4 KB
<?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');
    });
};