Files
leocrm/tests/test_phase_h_wiki.py
T

278 lines
10 KiB
Python

"""Tests for Phase H — Wiki plugin: models, schemas, plugin manifest.
All tests use mocks — no real DB needed.
"""
from __future__ import annotations
import uuid
from unittest.mock import MagicMock
import pytest
class TestWikiPluginManifest:
"""Test the Wiki plugin manifest."""
def test_plugin_manifest_valid(self):
"""Wiki plugin manifest is valid."""
from app.plugins.builtins.wiki.plugin import WikiPlugin
assert WikiPlugin.manifest.name == "wiki"
assert WikiPlugin.manifest.version == "1.0.0"
assert WikiPlugin.manifest.display_name == "Wiki"
assert "wiki:read" in WikiPlugin.manifest.permissions
assert "wiki:write" in WikiPlugin.manifest.permissions
assert "wiki:delete" in WikiPlugin.manifest.permissions
assert "wiki:admin" in WikiPlugin.manifest.permissions
def test_plugin_has_routes(self):
"""Wiki plugin has routes defined."""
from app.plugins.builtins.wiki.plugin import WikiPlugin
assert len(WikiPlugin.manifest.routes) > 0
assert WikiPlugin.manifest.routes[0].path == "/api/v1/wiki"
def test_plugin_has_menu_item(self):
"""Wiki plugin has a menu item."""
from app.plugins.builtins.wiki.plugin import WikiPlugin
assert len(WikiPlugin.manifest.menu_items) > 0
assert WikiPlugin.manifest.menu_items[0].path == "/wiki"
def test_plugin_has_dependencies(self):
"""Wiki plugin depends on permissions plugin."""
from app.plugins.builtins.wiki.plugin import WikiPlugin
assert "permissions" in WikiPlugin.manifest.dependencies
class TestWikiRoutes:
"""Test the Wiki routes are properly defined."""
def test_routes_count(self):
"""Wiki plugin has 9 routes."""
from app.plugins.builtins.wiki.routes import router
assert len(router.routes) == 9
def test_routes_have_correct_paths(self):
"""Wiki routes have correct API paths."""
from app.plugins.builtins.wiki.routes import router
paths = {r.path for r in router.routes}
assert "/api/v1/wiki/articles" in paths
assert "/api/v1/wiki/articles/{article_id}" in paths
assert "/api/v1/wiki/articles/{article_id}/versions" in paths
assert "/api/v1/wiki/articles/{article_id}/versions/{version}/restore" in paths
assert "/api/v1/wiki/categories" in paths
class TestWikiSchemas:
"""Test the Wiki Pydantic schemas."""
def test_article_create_valid(self):
"""ArticleCreate accepts valid data."""
from app.plugins.builtins.wiki.schemas import ArticleCreate
article = ArticleCreate(title="Test Article", slug="test-article")
assert article.title == "Test Article"
assert article.slug == "test-article"
assert article.status == "draft"
assert article.tags == []
def test_article_create_invalid_status(self):
"""ArticleCreate rejects invalid status."""
from app.plugins.builtins.wiki.schemas import ArticleCreate
from pydantic import ValidationError
with pytest.raises(ValidationError):
ArticleCreate(title="Test", slug="test", status="invalid")
def test_article_update_partial(self):
"""ArticleUpdate allows partial updates."""
from app.plugins.builtins.wiki.schemas import ArticleUpdate
update = ArticleUpdate(title="Updated Title")
assert update.title == "Updated Title"
assert update.content is None
def test_category_create_valid(self):
"""CategoryCreate accepts valid data."""
from app.plugins.builtins.wiki.schemas import CategoryCreate
cat = CategoryCreate(name="Test Category", slug="test-category")
assert cat.name == "Test Category"
assert cat.slug == "test-category"
assert cat.sort_order == 0
class TestWikiModels:
"""Test the Wiki SQLAlchemy models."""
def test_wiki_article_model_fields(self):
"""WikiArticle model has all required fields."""
from app.plugins.builtins.wiki.models import WikiArticle
assert hasattr(WikiArticle, "title")
assert hasattr(WikiArticle, "slug")
assert hasattr(WikiArticle, "content")
assert hasattr(WikiArticle, "content_html")
assert hasattr(WikiArticle, "summary")
assert hasattr(WikiArticle, "category_id")
assert hasattr(WikiArticle, "tags")
assert hasattr(WikiArticle, "status")
assert hasattr(WikiArticle, "entity_links")
assert hasattr(WikiArticle, "version")
assert hasattr(WikiArticle, "published_at")
assert hasattr(WikiArticle, "tenant_id")
assert hasattr(WikiArticle, "owner_id")
def test_wiki_category_model_fields(self):
"""WikiCategory model has all required fields."""
from app.plugins.builtins.wiki.models import WikiCategory
assert hasattr(WikiCategory, "name")
assert hasattr(WikiCategory, "slug")
assert hasattr(WikiCategory, "description")
assert hasattr(WikiCategory, "parent_id")
assert hasattr(WikiCategory, "sort_order")
assert hasattr(WikiCategory, "tenant_id")
def test_wiki_article_version_model_fields(self):
"""WikiArticleVersion model has all required fields."""
from app.plugins.builtins.wiki.models import WikiArticleVersion
assert hasattr(WikiArticleVersion, "article_id")
assert hasattr(WikiArticleVersion, "version")
assert hasattr(WikiArticleVersion, "title")
assert hasattr(WikiArticleVersion, "content")
assert hasattr(WikiArticleVersion, "edited_by")
assert hasattr(WikiArticleVersion, "edit_comment")
assert hasattr(WikiArticleVersion, "tenant_id")
def test_models_have_tenant_mixin(self):
"""All Wiki models have tenant_id (TenantMixin)."""
from app.plugins.builtins.wiki.models import WikiArticle, WikiCategory, WikiArticleVersion
for model in [WikiArticle, WikiCategory, WikiArticleVersion]:
assert hasattr(model, "tenant_id")
class TestWikiServices:
"""Test the Wiki service helper functions."""
def test_slugify(self):
"""_slugify converts text to URL-safe slug."""
from app.plugins.builtins.wiki.services import _slugify
assert _slugify("Hello World") == "hello-world"
assert _slugify("Überblick") == "ueberblick"
assert _slugify("Test Article 123") == "test-article-123"
# ─── H-SRC: Knowledge Source Adapter ─────────────────────────────────────────
class TestKnowledgeSourceAdapter:
"""Test the knowledge source adapter (H-SRC)."""
def test_available_sources(self):
"""All 4 knowledge source types are registered."""
from app.ai.knowledge_sources import get_available_sources
sources = get_available_sources()
types = {s["type"] for s in sources}
assert types == {"wiki", "dms", "mail", "communication"}
def test_get_source_config_wiki(self):
"""Wiki source config is correct."""
from app.ai.knowledge_sources import get_source_config
config = get_source_config("wiki")
assert config is not None
assert config["text_field"] == "content"
assert config["title_field"] == "title"
assert config["status_filter"] == {"status": "published"}
def test_get_source_config_unknown(self):
"""Unknown source type returns None."""
from app.ai.knowledge_sources import get_source_config
assert get_source_config("nonexistent") is None
# ─── H-CITE: Evidence References ─────────────────────────────────────────────
class TestEvidenceReferences:
"""Test the evidence reference builder (H-CITE)."""
def test_evidence_reference_to_dict(self):
"""EvidenceReference serializes to dict correctly."""
from app.ai.knowledge_sources import EvidenceReference
ref = EvidenceReference(
source_type="wiki",
source_id="abc-123",
title="Test Article",
url="/wiki/articles/abc-123",
snippet="This is a test snippet",
confidence=0.95,
)
d = ref.to_dict()
assert d["source_type"] == "wiki"
assert d["source_id"] == "abc-123"
assert d["title"] == "Test Article"
assert d["confidence"] == 0.95
def test_evidence_reference_to_workstream_block(self):
"""EvidenceReference converts to workstream block."""
from app.ai.knowledge_sources import EvidenceReference
ref = EvidenceReference(
source_type="dms",
source_id="file-123",
title="Document.pdf",
url="/dms/files/file-123",
snippet="Important content here",
)
block = ref.to_workstream_block()
assert block["type"] == "evidence_card"
assert block["source_type"] == "dms"
assert block["title"] == "Document.pdf"
def test_build_evidence_references_from_results(self):
"""build_evidence_references creates refs from search results."""
from app.ai.knowledge_sources import build_evidence_references
results = [
{"source_type": "wiki", "source_id": str(uuid.uuid4()), "title": "Article 1", "score": 0.9, "snippet": "Snippet 1"},
{"source_type": "dms", "source_id": str(uuid.uuid4()), "title": "Doc 2", "score": 0.7, "snippet": "Snippet 2"},
{"source_type": "mail", "source_id": str(uuid.uuid4()), "title": "Mail 3", "score": 0.95, "snippet": "Snippet 3"},
]
refs = build_evidence_references(results)
assert len(refs) == 3
# Sorted by confidence descending
assert refs[0].confidence == 0.95
assert refs[1].confidence == 0.9
assert refs[2].confidence == 0.7
def test_build_evidence_references_max_results(self):
"""build_evidence_references respects max_results."""
from app.ai.knowledge_sources import build_evidence_references
results = [
{"source_type": "wiki", "source_id": str(uuid.uuid4()), "title": f"Article {i}", "score": 0.5}
for i in range(10)
]
refs = build_evidence_references(results, max_results=3)
assert len(refs) == 3
def test_build_evidence_references_empty(self):
"""build_evidence_references handles empty results."""
from app.ai.knowledge_sources import build_evidence_references
refs = build_evidence_references([])
assert refs == []