Files
leocrm/tests/test_contacts_entity_registry.py
Agent Zero 4a25ac1379
Check Cross-Plugin Imports / check (push) Has been cancelled
fix(arch): externes Audit — 13 Backend-Fixes (Workspace-Modules, Tenant-Manifeste, Lifecycle, Contracts, Permissions)
Verifikation: Alle 17 Audit-Findings gegen den Code geprueft — alle bestaetigt.
Backend-Lifecycle-Fixes umgesetzt; 4 Frontend-Plugin-Architektur-Punkte
als Phase Q in die Roadmap eingeplant.

- P1 list_workspaces: Module + User-Counts gebuendelt laden (Editor-Overwrite-Bug)
- P1 active-manifests: Tenant-Deaktivierung (tenant_plugin_activation) filtern
- P1 uninstall: volle Service-Deactivation VOR registry.uninstall()
- P1 ContractRegistry: DB-Aktivstatus-Guard (Restart-Edge-Case) + Re-Activate
- P1/P2 Field-Definitions: voller Lifecycle (register/unregister) im Service
- P1/P2 Contact-Felddefinitionen (39) ins ContactsPlugin-Manifest verschoben
- P1 12 fehlende Permission-Keys registriert (AST-Scan: 0 fehlend)
- P2 contact_folder -> ContactsPlugin; ENTITY_PLUGIN_OWNERS wird befuellt
- P2 Entity-Permission-Fallback fail-closed statt contacts:read
- P2 forgejo_error_reporter is_core=False; DMS is_core=True (ADR-020)
- P2 Worker: Contacts-Trash-Cleanup ins Plugin (get_job_modules-Discovery)
- P1/P2 DSGVO-Export delegiert an DSAR-Collector (kein Core->Contacts)
- P2 False-green Tests korrigiert (or True, veraltete Route-Count-Assertion)

Verifikation: tests/test_audit_architecture_fixes.py 17/17; Regressionen
gruen (contacts_lifecycle, entity_registry, workspace_scopes, rbac,
lifecycle_service); Combo-Order-Test 35/35; Cross-Plugin-Checker 497/0;
compileall sauber; ruff auf 7-Error-Baseline.

Doku: PROGRESS.md Audit-Section, PLATFORM_ROADMAP.md Phase Q (Q1-Q4),
plugin-development-guide.md Lifecycle, permissions.md Katalog.
2026-09-13 02:25:01 +02:00

62 lines
2.7 KiB
Python

"""Contacts-Entity-Registry: single source of truth (Kritikpunkt 11).
Beweist, dass die Contacts-Entities (contact/contacts/company) NICHT mehr
statisch im Core-Registry stehen, sondern ausschliesslich vom ContactsPlugin
ueber get_entity_models() + register_entity_model() kommen — wie jedes
andere Plugin auch. is_core=True heisst Pflichtplugin, nicht Core-Verdrahtung.
"""
from __future__ import annotations
from app.models.contact import Contact
from app.plugins.builtins.contacts.plugin import ContactsPlugin
from app.services.entity_permission_service import ENTITY_MODELS
def test_core_registry_source_has_no_static_contacts_entries():
"""The core registry SOURCE must not hardcode contacts entities anymore.
(After bootstrap ENTITY_MODELS legitimately contains them — registered
via the plugin. This test proves the duplicate static source is gone.)
"""
from pathlib import Path
module_path = Path(__file__).parent.parent / "app" / "services" / "entity_permission_service.py"
text = module_path.read_text(encoding="utf-8")
assert '"contact": Contact' not in text, "statischer contact-Eintrag noch im Core!"
assert '"contacts": Contact' not in text, "statischer contacts-Eintrag noch im Core!"
assert '"company": Contact' not in text, "statischer company-Eintrag noch im Core!"
def test_contacts_plugin_is_single_source_for_its_entities():
"""ContactsPlugin.get_entity_models() defines contact/contacts/company/contact_folder.
Audit P2: contact_folder moved from the static core ENTITY_MODELS map to
the plugin (it is contacts-owned domain data) — the plugin is the single
source for ALL its entities.
"""
from app.models.contact_folder import ContactFolder
plugin_models = ContactsPlugin().get_entity_models()
assert plugin_models == {
"contact": Contact,
"contacts": Contact,
"company": Contact,
"contact_folder": ContactFolder,
}
# The core registry must NOT carry contact_folder statically anymore —
# it appears there only through the plugin bootstrap (conftest mirrors
# main.py: every discovered plugin's entities get registered).
from app.services import entity_permission_service as eps
core_static_types = set(eps.ENTITY_MODELS.keys()) - set(plugin_models.keys())
assert "contact_folder" not in core_static_types
def test_bootstrap_registers_contacts_entities_via_plugin():
"""After the real bootstrap path (conftest mirrors main.py lifespan:
every plugin's get_entity_models() is registered), contacts entities
are present — via the plugin, not via the core registry."""
assert ENTITY_MODELS["contact"] is Contact
assert ENTITY_MODELS["contacts"] is Contact
assert ENTITY_MODELS["company"] is Contact