feat: implement knowledge management system (spec complete, all 53 tasks done)
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
"""Tests for the ContextRouter module."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from monorepo.knowledge.ingestion.config import SourceConfig
|
||||
from monorepo.knowledge.ingestion.router import (
|
||||
CATEGORY_FOLDER_MAP,
|
||||
DEFAULT_FOLDER,
|
||||
ContextRouter,
|
||||
RoutingDecision,
|
||||
category_to_folder,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# category_to_folder
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestCategoryToFolder:
|
||||
"""Tests for the category_to_folder helper."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"category,expected",
|
||||
[
|
||||
("meeting", "meetings"),
|
||||
("decision", "decisions"),
|
||||
("project", "projects"),
|
||||
("reference", "references"),
|
||||
("link", "links"),
|
||||
("inbox", "inbox"),
|
||||
],
|
||||
)
|
||||
def test_known_categories(self, category: str, expected: str) -> None:
|
||||
assert category_to_folder(category) == expected
|
||||
|
||||
def test_unknown_category_defaults_to_inbox(self) -> None:
|
||||
assert category_to_folder("unknown") == "inbox"
|
||||
assert category_to_folder("random") == "inbox"
|
||||
|
||||
def test_case_insensitive(self) -> None:
|
||||
assert category_to_folder("Meeting") == "meetings"
|
||||
assert category_to_folder("DECISION") == "decisions"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ContextRouter.determine_context
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestDetermineContext:
|
||||
"""Tests for ContextRouter.determine_context."""
|
||||
|
||||
def setup_method(self) -> None:
|
||||
self.router = ContextRouter(Path("/monorepo"))
|
||||
|
||||
def test_from_source_config_params(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="confluence",
|
||||
name="Test",
|
||||
params={"context": "bahn"},
|
||||
)
|
||||
assert self.router.determine_context(source_config=config) == "bahn"
|
||||
|
||||
def test_from_source_config_dhive(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="file",
|
||||
name="Test",
|
||||
params={"context": "dhive"},
|
||||
)
|
||||
assert self.router.determine_context(source_config=config) == "dhive"
|
||||
|
||||
def test_from_source_config_privat(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="file",
|
||||
name="Test",
|
||||
params={"context": "privat"},
|
||||
)
|
||||
assert self.router.determine_context(source_config=config) == "privat"
|
||||
|
||||
def test_from_cwd_bahn(self) -> None:
|
||||
cwd = Path("/monorepo/bahn/wissensdatenbank")
|
||||
assert self.router.determine_context(cwd=cwd) == "bahn"
|
||||
|
||||
def test_from_cwd_dhive(self) -> None:
|
||||
cwd = Path("/monorepo/dhive/projects/kiq")
|
||||
assert self.router.determine_context(cwd=cwd) == "dhive"
|
||||
|
||||
def test_from_cwd_privat(self) -> None:
|
||||
cwd = Path("/monorepo/privat/knowledge/meetings")
|
||||
assert self.router.determine_context(cwd=cwd) == "privat"
|
||||
|
||||
def test_from_cwd_windows_paths(self) -> None:
|
||||
cwd = Path("C:\\Users\\user\\monorepo\\bahn\\something")
|
||||
assert self.router.determine_context(cwd=cwd) == "bahn"
|
||||
|
||||
def test_source_config_takes_precedence_over_cwd(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="file",
|
||||
name="Test",
|
||||
params={"context": "dhive"},
|
||||
)
|
||||
cwd = Path("/monorepo/bahn/something")
|
||||
assert self.router.determine_context(source_config=config, cwd=cwd) == "dhive"
|
||||
|
||||
def test_falls_back_to_cwd_when_config_has_no_context(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="file",
|
||||
name="Test",
|
||||
params={"url": "http://example.com"},
|
||||
)
|
||||
cwd = Path("/monorepo/privat/notes")
|
||||
assert self.router.determine_context(source_config=config, cwd=cwd) == "privat"
|
||||
|
||||
def test_raises_when_neither_provides_context(self) -> None:
|
||||
with pytest.raises(ValueError, match="Kontext konnte nicht bestimmt werden"):
|
||||
self.router.determine_context()
|
||||
|
||||
def test_raises_when_cwd_has_no_context(self) -> None:
|
||||
cwd = Path("/some/other/directory")
|
||||
with pytest.raises(ValueError, match="Kontext konnte nicht bestimmt werden"):
|
||||
self.router.determine_context(cwd=cwd)
|
||||
|
||||
def test_raises_when_config_has_invalid_context(self) -> None:
|
||||
config = SourceConfig(
|
||||
type="file",
|
||||
name="Test",
|
||||
params={"context": "invalid"},
|
||||
)
|
||||
with pytest.raises(ValueError, match="Kontext konnte nicht bestimmt werden"):
|
||||
self.router.determine_context(source_config=config)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ContextRouter.resolve_target_path
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestResolveTargetPath:
|
||||
"""Tests for ContextRouter.resolve_target_path."""
|
||||
|
||||
def setup_method(self) -> None:
|
||||
self.router = ContextRouter(Path("/monorepo"))
|
||||
|
||||
def test_meeting_path(self) -> None:
|
||||
result = self.router.resolve_target_path("bahn", "meeting", "2024-01-15-standup.md")
|
||||
assert result == Path("/monorepo/bahn/knowledge/meetings/2024-01-15-standup.md")
|
||||
|
||||
def test_decision_path(self) -> None:
|
||||
result = self.router.resolve_target_path("dhive", "decision", "adr-001.md")
|
||||
assert result == Path("/monorepo/dhive/knowledge/decisions/adr-001.md")
|
||||
|
||||
def test_project_path(self) -> None:
|
||||
result = self.router.resolve_target_path("privat", "project", "side-project.md")
|
||||
assert result == Path("/monorepo/privat/knowledge/projects/side-project.md")
|
||||
|
||||
def test_reference_path(self) -> None:
|
||||
result = self.router.resolve_target_path("bahn", "reference", "api-docs.md")
|
||||
assert result == Path("/monorepo/bahn/knowledge/references/api-docs.md")
|
||||
|
||||
def test_link_path(self) -> None:
|
||||
result = self.router.resolve_target_path("dhive", "link", "useful-link.md")
|
||||
assert result == Path("/monorepo/dhive/knowledge/links/useful-link.md")
|
||||
|
||||
def test_unknown_category_goes_to_inbox(self) -> None:
|
||||
result = self.router.resolve_target_path("bahn", "random", "something.md")
|
||||
assert result == Path("/monorepo/bahn/knowledge/inbox/something.md")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ContextRouter.route (convenience method)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRoute:
|
||||
"""Tests for ContextRouter.route convenience method."""
|
||||
|
||||
def setup_method(self) -> None:
|
||||
self.router = ContextRouter(Path("/monorepo"))
|
||||
|
||||
def test_returns_routing_decision(self) -> None:
|
||||
config = SourceConfig(type="file", name="Test", params={"context": "bahn"})
|
||||
decision = self.router.route("meeting", "standup.md", source_config=config)
|
||||
|
||||
assert isinstance(decision, RoutingDecision)
|
||||
assert decision.context == "bahn"
|
||||
assert decision.target_folder == "meetings"
|
||||
assert decision.artifact_path == Path("/monorepo/bahn/knowledge/meetings/standup.md")
|
||||
|
||||
def test_route_with_cwd(self) -> None:
|
||||
cwd = Path("/monorepo/privat/something")
|
||||
decision = self.router.route("link", "bookmark.md", cwd=cwd)
|
||||
|
||||
assert decision.context == "privat"
|
||||
assert decision.target_folder == "links"
|
||||
assert decision.artifact_path == Path("/monorepo/privat/knowledge/links/bookmark.md")
|
||||
Reference in New Issue
Block a user