generated from coulomb/repo-seed
182 lines
6.4 KiB
Python
182 lines
6.4 KiB
Python
import subprocess
|
|
|
|
from repo_registry.core.service import RegistryService
|
|
from repo_registry.repo_ingestion.git import GitIngestionService
|
|
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
|
|
|
|
|
|
def make_service(tmp_path):
|
|
store = RegistryStore(tmp_path / "registry.sqlite3")
|
|
store.initialize()
|
|
return RegistryService(store, ingestion=GitIngestionService(tmp_path / "checkouts"))
|
|
|
|
|
|
def test_manual_registry_builds_ability_map(tmp_path):
|
|
service = make_service(tmp_path)
|
|
|
|
repository = service.register_repository(
|
|
name="MailRouter",
|
|
url="https://example.com/mail-router.git",
|
|
description="Routes incoming customer email",
|
|
)
|
|
ability_id = service.add_ability(
|
|
repository.id,
|
|
name="Business Email Routing",
|
|
description="Route inbound messages to the right department.",
|
|
confidence=0.92,
|
|
)
|
|
capability_id = service.add_capability(
|
|
repository.id,
|
|
ability_id,
|
|
name="Classify Incoming Email",
|
|
description="Classify messages into intent categories.",
|
|
inputs=["subject", "body"],
|
|
outputs=["intent", "confidence"],
|
|
confidence=0.88,
|
|
)
|
|
service.add_feature(
|
|
repository.id,
|
|
capability_id,
|
|
name="POST /api/classify-email",
|
|
type="REST endpoint",
|
|
location="src/routes/classify_email.py",
|
|
confidence=0.84,
|
|
)
|
|
service.add_evidence(
|
|
repository.id,
|
|
capability_id,
|
|
type="unit_test",
|
|
reference="tests/test_email_classification.py",
|
|
strength="strong",
|
|
)
|
|
|
|
ability_map = service.ability_map(repository.id)
|
|
|
|
assert ability_map.repository.name == "MailRouter"
|
|
assert ability_map.abilities[0].name == "Business Email Routing"
|
|
capability = ability_map.abilities[0].capabilities[0]
|
|
assert capability.name == "Classify Incoming Email"
|
|
assert capability.inputs == ["subject", "body"]
|
|
assert capability.features[0].location == "src/routes/classify_email.py"
|
|
assert capability.evidence[0].strength == "strong"
|
|
|
|
|
|
def test_search_matches_approved_abilities_and_capabilities(tmp_path):
|
|
service = make_service(tmp_path)
|
|
repository = service.register_repository(
|
|
name="MailRouter",
|
|
url="https://example.com/mail-router.git",
|
|
)
|
|
ability_id = service.add_ability(
|
|
repository.id,
|
|
name="Business Email Routing",
|
|
description="Route inbound messages.",
|
|
)
|
|
service.add_capability(
|
|
repository.id,
|
|
ability_id,
|
|
name="Classify Incoming Email",
|
|
description="Classify messages into intent categories.",
|
|
)
|
|
|
|
results = service.search("classify")
|
|
|
|
assert len(results) == 1
|
|
assert results[0].repository_name == "MailRouter"
|
|
assert results[0].match_type == "capability"
|
|
assert results[0].match_name == "Classify Incoming Email"
|
|
|
|
|
|
def test_capability_must_belong_to_repository(tmp_path):
|
|
service = make_service(tmp_path)
|
|
first = service.register_repository(name="First", url="https://example.com/first.git")
|
|
second = service.register_repository(name="Second", url="https://example.com/second.git")
|
|
ability_id = service.add_ability(first.id, name="Document Classification")
|
|
|
|
try:
|
|
service.add_capability(second.id, ability_id, name="Classify Document")
|
|
except NotFoundError as exc:
|
|
assert "ability" in str(exc)
|
|
else:
|
|
raise AssertionError("expected a NotFoundError")
|
|
|
|
|
|
def test_analyze_repository_records_snapshot_and_observed_facts(tmp_path):
|
|
source = tmp_path / "repo"
|
|
source.mkdir()
|
|
(source / "README.md").write_text("# Example\n", encoding="utf-8")
|
|
(source / "requirements.txt").write_text("fastapi\n", encoding="utf-8")
|
|
(source / "app.py").write_text(
|
|
"from fastapi import FastAPI\n"
|
|
"app = FastAPI()\n"
|
|
'@app.get("/health")\n'
|
|
"def health():\n"
|
|
" return {}\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
service = make_service(tmp_path)
|
|
repository = service.register_repository(
|
|
name="Example",
|
|
url=str(source),
|
|
description="A local fixture repository",
|
|
)
|
|
|
|
summary = service.analyze_repository(repository.id)
|
|
|
|
assert summary.analysis_run.status == "completed"
|
|
assert summary.snapshot is not None
|
|
assert summary.snapshot.file_count == 3
|
|
assert service.get_repository(repository.id).status == "analyzed"
|
|
fact_names = {(fact.kind, fact.name, fact.path) for fact in summary.facts}
|
|
assert ("documentation", "README", "README.md") in fact_names
|
|
assert ("framework", "FastAPI", "requirements.txt") in fact_names
|
|
assert ("interface", "python route decorator", "app.py") in fact_names
|
|
|
|
|
|
def test_analyze_repository_failure_is_recorded(tmp_path):
|
|
service = make_service(tmp_path)
|
|
repository = service.register_repository(
|
|
name="Missing",
|
|
url=str(tmp_path / "does-not-exist"),
|
|
)
|
|
|
|
summary = service.analyze_repository(repository.id)
|
|
|
|
assert summary.analysis_run.status == "failed"
|
|
assert summary.snapshot is None
|
|
assert "does not exist" in (summary.analysis_run.error_message or "")
|
|
assert service.get_repository(repository.id).status == "analysis_failed"
|
|
|
|
|
|
def test_analyze_repository_clones_git_url_before_scanning(tmp_path):
|
|
source = tmp_path / "git-source"
|
|
source.mkdir()
|
|
subprocess.run(["git", "init", "-b", "main"], cwd=source, check=True)
|
|
subprocess.run(
|
|
["git", "config", "user.email", "tests@example.com"],
|
|
cwd=source,
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["git", "config", "user.name", "Tests"],
|
|
cwd=source,
|
|
check=True,
|
|
)
|
|
(source / "README.md").write_text("# Git Source\n", encoding="utf-8")
|
|
(source / "requirements.txt").write_text("pytest\n", encoding="utf-8")
|
|
subprocess.run(["git", "add", "."], cwd=source, check=True)
|
|
subprocess.run(["git", "commit", "-m", "initial"], cwd=source, check=True)
|
|
|
|
service = make_service(tmp_path)
|
|
repository = service.register_repository(name="Git Source", url=source.as_uri())
|
|
|
|
summary = service.analyze_repository(repository.id)
|
|
|
|
assert summary.analysis_run.status == "completed"
|
|
assert summary.snapshot is not None
|
|
assert str(tmp_path / "checkouts") in summary.snapshot.source_path
|
|
fact_names = {(fact.kind, fact.name, fact.path) for fact in summary.facts}
|
|
assert ("documentation", "README", "README.md") in fact_names
|
|
assert ("framework", "pytest", "requirements.txt") in fact_names
|