skill-kanten-generator: Deploy-Skript für automatische Skill-Verknüpfung

This commit is contained in:
2026-07-15 07:48:35 +02:00
parent 960bda6021
commit 7f72b274b5
3 changed files with 1586 additions and 0 deletions
+239
View File
@@ -0,0 +1,239 @@
#!/usr/bin/env python3
"""
test_skill_kanten_generator.py
Unit-Tests für skill-kanten-generator.py
"""
import json
import sys
import tempfile
import unittest
from pathlib import Path
# Füge das aktuelle Verzeichnis zum Python-Pfad hinzu
sys.path.insert(0, str(Path(__file__).parent))
from skill_kanten_generator import (
Edge,
SkillInfo,
deduplicate_edges,
generate_metadata_edges,
build_skill_index,
generate_journey_graph,
)
class TestEdge(unittest.TestCase):
"""Tests für die Edge-Datenklasse."""
def test_key_ungereicht(self):
"""Die key()-Methode sollte ungerichtet sein."""
edge1 = Edge("a", "b", 0.5, "category", "test")
edge2 = Edge("b", "a", 0.5, "category", "test")
self.assertEqual(edge1.key(), edge2.key())
def test_to_dict(self):
"""to_dict() sollte das richtige Format liefern."""
edge = Edge("a", "b", 0.9, "declared", "manual")
result = edge.to_dict()
self.assertEqual(result["skill_a"], "a")
self.assertEqual(result["skill_b"], "b")
self.assertEqual(result["weight"], 0.9)
self.assertEqual(result["type"], "declared")
self.assertEqual(result["source"], "manual")
class TestDeduplicateEdges(unittest.TestCase):
"""Tests für die Deduplizierung."""
def test_keine_doppelt(self):
"""Keine Doppelte: gleiche Anzahl zurück."""
edges = [
Edge("a", "b", 0.5, "category", "test"),
Edge("c", "d", 0.7, "manual", "test"),
]
result = deduplicate_edges(edges)
self.assertEqual(len(result), 2)
def test_doppelt_hoehere_prioritaet(self):
"""Bei Doppelt mit gleichen Skills: höhere Priorität gewinnt."""
edges = [
Edge("a", "b", 0.5, "category", "test"), # category
Edge("a", "b", 0.9, "declared", "test"), # declared (höher)
]
result = deduplicate_edges(edges)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].edge_type, "declared")
def test_doppelt_hoeheres_gewicht(self):
"""Bei gleicher Priorität: höheres Gewicht gewinnt."""
edges = [
Edge("a", "b", 0.5, "category", "test"),
Edge("a", "b", 0.7, "category", "test"),
]
result = deduplicate_edges(edges)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].weight, 0.7)
class TestBuildSkillIndex(unittest.TestCase):
"""Tests für build_skill_index()."""
def test_leere_index(self):
"""Mit leerem usage.json: leerer Index."""
with tempfile.TemporaryDirectory() as tmpdir:
skills_dir = Path(tmpdir) / "skills"
skills_dir.mkdir()
(skills_dir / ".usage.json").write_text("{}")
# Mock-Path
import skill_kanten_generator as sg
original = sg.SKILLS_DIR
sg.SKILLS_DIR = skills_dir
sg.USAGE_FILE = skills_dir / ".usage.json"
try:
index = build_skill_index()
self.assertEqual(len(index), 0)
finally:
sg.SKILLS_DIR = original
sg.USAGE_FILE = original / ".usage.json"
def test_index_erstellt(self):
"""Ein Skill aus .usage.json sollte im Index erscheinen."""
with tempfile.TemporaryDirectory() as tmpdir:
skills_dir = Path(tmpdir) / "skills"
skills_dir.mkdir()
usage = {
"my-skill": {
"use_count": 10,
"state": "active",
}
}
(skills_dir / ".usage.json").write_text(json.dumps(usage))
import skill_kanten_generator as sg
original = sg.SKILLS_DIR
sg.SKILLS_DIR = skills_dir
sg.USAGE_FILE = skills_dir / ".usage.json"
try:
index = build_skill_index()
self.assertIn("my-skill", index)
self.assertEqual(index["my-skill"].use_count, 10)
finally:
sg.SKILLS_DIR = original
sg.USAGE_FILE = original / ".usage.json"
class TestGenerateMetadataEdges(unittest.TestCase):
"""Tests für generate_metadata_edges()."""
def test_gleiche_kategorie(self):
"""Skills mit gleicher Kategorie erhalten eine Kante."""
skills = {
"skill-a": SkillInfo(name="skill-a", category="test"),
"skill-b": SkillInfo(name="skill-b", category="test"),
}
edges = generate_metadata_edges(skills)
self.assertEqual(len(edges), 1)
self.assertEqual(edges[0].edge_type, "category")
self.assertEqual(edges[0].weight, 0.7)
def test_different_categories_no_edge(self):
"""Skills mit verschiedenen Kategorien: keine Kante."""
skills = {
"skill-a": SkillInfo(name="skill-a", category="cat-a"),
"skill-b": SkillInfo(name="skill-b", category="cat-b"),
}
edges = generate_metadata_edges(skills)
self.assertEqual(len(edges), 0)
def test_related_skills(self):
"""Skills mit related_skills-Verbindung erhalten eine Kante."""
skills = {
"skill-a": SkillInfo(
name="skill-a",
related_skills=["skill-b"],
),
"skill-b": SkillInfo(name="skill-b"),
}
edges = generate_metadata_edges(skills)
self.assertEqual(len(edges), 1)
self.assertEqual(edges[0].edge_type, "declared")
self.assertEqual(edges[0].skill_a, "skill-a")
self.assertEqual(edges[0].skill_b, "skill-b")
class TestFullWorkflow(unittest.TestCase):
"""Integrationstest für den kompletten Workflow."""
def test_journey_graph_generated(self):
"""Der komplette Workflow sollte einen Graphen erzeugen."""
with tempfile.TemporaryDirectory() as tmpdir:
hermes_dir = Path(tmpdir) / "hermes" / "profiles" / "werkstatt"
skills_dir = hermes_dir / "skills"
skills_dir.mkdir(parents=True)
# .usage.json
usage = {
"orchestrator": {
"use_count": 10,
"state": "active",
},
"wartung": {
"use_count": 7,
"state": "active",
},
}
(skills_dir / ".usage.json").write_text(json.dumps(usage))
# SKILL.md mit gleicher Kategorie
(skills_dir / "orchestrator").mkdir()
(skills_dir / "orchestrator" / "SKILL.md").write_text(
"---\n"
"name: orchestrator\n"
"category: devops\n"
"---\n"
"# Orchestrator\n"
)
(skills_dir / "wartung").mkdir()
(skills_dir / "wartung" / "SKILL.md").write_text(
"---\n"
"name: wartung\n"
"category: devops\n"
"---\n"
"# Wartung\n"
)
import skill_kanten_generator as sg
original = sg.SKILLS_DIR
sg.SKILLS_DIR = skills_dir
sg.USAGE_FILE = skills_dir / ".usage.json"
try:
graph = generate_journey_graph()
# Prüfe Struktur
self.assertIn("nodes", graph)
self.assertIn("edges", graph)
self.assertIn("generated_at", graph)
# Prüfe Knotenanzahl
self.assertEqual(len(graph["nodes"]), 2)
# Prüfe Kante (beide in gleicher Kategorie)
edge_types = [e["type"] for e in graph["edges"]]
self.assertIn("category", edge_types)
finally:
sg.SKILLS_DIR = original
sg.USAGE_FILE = original / ".usage.json"
if __name__ == "__main__":
unittest.main()