2026-08-27 18:53:12 +02:00
|
|
|
"""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():
|
2026-09-13 02:25:01 +02:00
|
|
|
"""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
|
2026-08-27 18:53:12 +02:00
|
|
|
plugin_models = ContactsPlugin().get_entity_models()
|
|
|
|
|
assert plugin_models == {
|
|
|
|
|
"contact": Contact,
|
|
|
|
|
"contacts": Contact,
|
|
|
|
|
"company": Contact,
|
2026-09-13 02:25:01 +02:00
|
|
|
"contact_folder": ContactFolder,
|
2026-08-27 18:53:12 +02:00
|
|
|
}
|
|
|
|
|
|
2026-09-13 02:25:01 +02:00
|
|
|
# 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
|
|
|
|
|
|
2026-08-27 18:53:12 +02:00
|
|
|
|
|
|
|
|
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
|