OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

AiActionAuditTest.php

4 KB
<?php

declare(strict_types=1);

use OpenNIT\AI\Actions\ActionRegistry;
use OpenNIT\Controllers\AIChatController;

/**
 * Deckt ab, welchen Datensatz eine Chat-Aktion im Protokoll benennt.
 *
 * Fuehrt der KI-Chat eine Aktion aus, wird das protokolliert. Ohne den
 * betroffenen Datensatz steht dort nur, *dass* etwas geschah – aus dem
 * Protokoll fuehrt kein Weg zum Vertrag oder Ticket, und im Verlauf des
 * Datensatzes selbst taucht die Aenderung gar nicht auf.
 */
return static function (): void {

    /** Ruft die private Zuordnung auf. */
    $objekt = static function (array $result): array {
        $m = new ReflectionMethod(AIChatController::class, 'betroffenesObjekt');
        $m->setAccessible(true);
        return $m->invoke(null, $result);
    };

    // ----------------------------------------------------------------
    // Zuordnung
    // ----------------------------------------------------------------

    test('Der angelegte Datensatz wird benannt', function () use ($objekt) {
        assertSame(['ticket', 42], $objekt(['success' => true, 'ticket_id' => 42]));
        assertSame(['contract', 7], $objekt(['success' => true, 'contract_id' => 7]));
        assertSame(['asset', 3], $objekt(['success' => true, 'asset_id' => 3]));
        assertSame(['page', 9], $objekt(['success' => true, 'page_id' => 9]));
    });

    test('Abweichende Namen treffen den Typ des Moduls', function () use ($objekt) {
        // Die Tabellen heissen anders als der Schluessel im Ergebnis; das Protokoll
        // muss denselben Typ fuehren wie die uebrigen Eintraege des Moduls.
        assertSame(['personal_todo', 5], $objekt(['success' => true, 'todo_id' => 5]));
        assertSame(['loan_lending', 5], $objekt(['success' => true, 'lending_id' => 5]));
        assertSame(['kanban_task', 5], $objekt(['success' => true, 'task_id' => 5]));
        assertSame(['stock_item', 5], $objekt(['success' => true, 'item_id' => 5]));
        assertSame(['ip_address', 5], $objekt(['success' => true, 'ip_id' => 5]));
        assertSame(['maintenance_event', 5], $objekt(['success' => true, 'event_id' => 5]));
    });

    test('Die Chat-Sitzung ist nicht der betroffene Datensatz', function () use ($objekt) {
        // Sonst zeigte jeder Eintrag auf den Chat statt auf das, was sich geaendert hat.
        assertSame([null, null], $objekt(['success' => true, 'session_id' => 12]));
        assertSame(['ticket', 8], $objekt(['success' => true, 'session_id' => 12, 'ticket_id' => 8]));
    });

    test('Ohne verwertbare Kennung bleibt es beim Chat', function () use ($objekt) {
        assertSame([null, null], $objekt(['success' => true, 'message' => 'erledigt']));
        assertSame([null, null], $objekt(['success' => true, 'ticket_id' => 0]));
        assertSame([null, null], $objekt(['success' => true, 'ticket_id' => null]));
        assertSame([null, null], $objekt([]));
    });

    test('Nur Kennungen zaehlen, nicht jeder Wert', function () use ($objekt) {
        // 'redirect' oder 'message' duerfen nicht als Datensatz durchgehen.
        assertSame([null, null], $objekt(['success' => true, 'redirect' => '/tickets/5']));
    });

    // ----------------------------------------------------------------
    // Zusammenspiel mit dem Protokolleintrag
    // ----------------------------------------------------------------

    test('Jede bekannte Aktion traegt eine lesbare Bezeichnung', function () {
        // Der Eintrag fuehrt die Bezeichnung als Objektnamen; ein roher
        // Schluessel wie 'create_contract' liest sich im Protokoll schlecht.
        foreach (array_keys(ActionRegistry::all()) as $typ) {
            $label = ActionRegistry::label($typ);
            assertTrue($label !== '' && $label !== $typ, "Aktion {$typ} ohne eigene Bezeichnung");
        }
    });

    test('Der Protokolleintrag benennt den Datensatz statt pauschal den Chat', function () {
        $quelle = (string)file_get_contents(dirname(__DIR__) . '/src/Controllers/AIChatController.php');
        $stelle = strpos($quelle, "'ai_action_executed'");
        assertTrue($stelle !== false, 'Der Protokolleintrag der Aktionen fehlt');

        $block = substr($quelle, $stelle, 400);
        assertTrue(str_contains($block, "\$objektTyp ?? 'ai_chat'"), 'Der Eintrag traegt weiterhin pauschal den Chat');
        assertTrue(str_contains($block, '$objektId'), 'Der Eintrag traegt keine Kennung');
    });
};