OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

SettingsConfigModulesTest.php

3 KB
<?php

declare(strict_types=1);

use OpenNIT\Controllers\Admin\SettingsController;
use OpenNIT\Core\Application;

/**
 * Regressionstest für den Modul-Reset-Bug: Das Speichern einer beliebigen
 * Settings-Seite (z. B. /admin/contracts/settings) lud die Konfiguration über
 * loadConfig(), dessen Defaults ALLE Module auf false setzten. Bei Instanzen
 * ohne modules-Block in der runtime.php wurde dieser All-false-Zustand beim
 * Speichern persistiert und legte die gesamte Instanz lahm.
 *
 * Erwartung seit dem Fix: loadConfig() nimmt als Modul-Default den EFFEKTIVEN
 * Zustand aus der laufenden App-Konfiguration – Laden + Speichern ohne
 * Modul-Änderung ist damit für die Module ein No-Op.
 */
return static function (): void {

    // Hinweis: Der Test läuft ohne config/runtime.php (im Repo nicht vorhanden),
    // exakt das Szenario der betroffenen Bestandsinstanzen.
    $runtimeFile = dirname(__DIR__) . '/config/runtime.php';
    if (file_exists($runtimeFile)) {
        echo "  (übersprungen: config/runtime.php vorhanden – Szenario nicht reproduzierbar)\n";
        return;
    }

    // App mit effektiver Konfiguration simulieren (wie von public/index.php gebaut).
    $effectiveModules = [
        'contracts' => true,
        'vault'     => true,
        'tickets'   => true,
        'cve'       => true,   // fehlte in der alten hartkodierten Default-Liste komplett
        'ai_chat'   => false,
    ];
    $appRef = new ReflectionClass(Application::class);
    $app    = $appRef->newInstanceWithoutConstructor();
    setPrivate($app, 'config', ['modules' => $effectiveModules]);

    $ctrlRef = new ReflectionClass(SettingsController::class);
    /** @var SettingsController $ctrl */
    $ctrl = $ctrlRef->newInstanceWithoutConstructor();
    // $app liegt auf BaseController (parent) – Reflection dorthin.
    $appProp = new ReflectionProperty(\OpenNIT\Controllers\BaseController::class, 'app');
    $appProp->setAccessible(true);
    $appProp->setValue($ctrl, $app);

    $config = callPrivate($ctrl, 'loadConfig');

    test('loadConfig übernimmt den effektiven Modul-Zustand (kein All-false-Default)', function () use ($config, $effectiveModules) {
        assertSame($effectiveModules, $config['modules'],
            'modules muss dem effektiven Zustand entsprechen – sonst schaltet jedes Settings-Speichern Module ab');
    });

    test('loadConfig: aktives Modul bleibt aktiv (contracts)', function () use ($config) {
        assertTrue((bool)$config['modules']['contracts']);
    });

    test('loadConfig: Module außerhalb der alten Default-Liste gehen nicht verloren (cve)', function () use ($config) {
        assertTrue(array_key_exists('cve', $config['modules']));
        assertTrue((bool)$config['modules']['cve']);
    });
};