"""Tests: Plugin-Loader laedt alle Stubs, Lifecycle-Hooks, Entry-Points.""" from __future__ import annotations import pytest from fastapi.testclient import TestClient from redaktionskern.contracts import BasePlugin, NavEntry from redaktionskern.plugin_loader import PluginError, PluginRegistry ERWARTETE_STUBS = { "dedup", "planung", "archiv", "erinnerung", "benachrichtigung", "audit-log", "export", } # Voll implementierte Plugins (keine Stubs mehr): ERWARTETE_PLUGINS = ERWARTETE_STUBS | {"neuheiten", "dedup", "planung"} def test_alle_plugins_werden_geladen(app): namen = {p.name for p in app.state.registry.all()} assert ERWARTETE_PLUGINS <= namen def test_on_load_wurde_aufgerufen(app): for plugin in app.state.registry.all(): if plugin.name in ERWARTETE_PLUGINS: assert plugin.loaded, f"Plugin {plugin.name} ist nicht geladen." assert plugin.context is not None def test_plugins_haben_navigation(app): for name in ERWARTETE_PLUGINS: plugin = app.state.registry.get(name) assert len(plugin.navigation()) == 1 # Voll implementierte Plugins tragen keinen Platzhalter-Text mehr auf ihrer # Seite; die Prüfung läuft weiter für alle übrigen Platzhalter. VOLL_IMPLEMENTIERT = { "audit-log", "neuheiten", "benachrichtigung", "dedup", "planung", "archiv", "erinnerung", } PLATZHALTER_STUBS = ERWARTETE_STUBS - VOLL_IMPLEMENTIERT def test_plugin_seiten_erreichbar(client): from tests.conftest import melde_an melde_an(client) for name in sorted(PLATZHALTER_STUBS): antwort = client.get(f"/{name}") assert antwort.status_code == 200, name assert "ist geladen" in antwort.text def test_audit_log_seite_erreichbar_fuer_admin(client): from tests.conftest import melde_an melde_an(client) antwort = client.get("/audit-log") assert antwort.status_code == 200 assert "Audit-Log" in antwort.text def test_on_unload_beim_herunterfahren(app): plugin = app.state.registry.get("neuheiten") with TestClient(app): assert plugin.loaded assert not plugin.loaded def test_doppelte_plugin_namen_abgelehnt(): class A(BasePlugin): name = "a" registry = PluginRegistry() registry.register(A()) with pytest.raises(PluginError): registry.register(A()) def test_entry_point_plugins_werden_geladen(monkeypatch, settings_ohne_plugins): """Entry-Point-Erkennung via importlib.metadata (hier simuliert).""" import redaktionskern.plugin_loader as loader externes_plugin = loader._als_plugin(ExternesPlugin()) class FakeEntryPoint: name = "extern" def load(self): return externes_plugin monkeypatch.setattr(loader, "entry_points", lambda group: [FakeEntryPoint()]) from redaktionskern.app import create_app app = create_app(settings_ohne_plugins) geladen = app.state.registry.get("extern") assert geladen is externes_plugin assert geladen.loaded class ExternesPlugin(BasePlugin): """Simuliert ein als Paket installiertes Plugin (Entry-Point).""" name = "extern" title = "Externes Plugin" description = "Test-Plugin via Entry-Point." def navigation(self) -> list[NavEntry]: return []