Files
odysseus/tests/test_addons.py

104 lines
3.3 KiB
Python

import asyncio
import json
from types import SimpleNamespace
import pytest
from src import addons
@pytest.fixture
def addon_store(tmp_path, monkeypatch):
monkeypatch.setattr(addons, "ADDONS_DIR", str(tmp_path / "addons"))
monkeypatch.setattr(addons, "ADDONS_FILE", str(tmp_path / "addons.json"))
return tmp_path
def test_addon_template_is_valid(addon_store):
manifest = addons.addon_template("demo-addon")
saved = addons.save_addon_manifest(manifest)
assert saved["id"] == "demo-addon"
assert saved["enabled"] is False
assert saved["contributions"][0]["type"] == "agent_prompt"
assert addons.get_addon("demo-addon")["name"] == "Demo Addon"
def test_enable_addon_exposes_prompt_contribution(addon_store):
addons.save_addon_manifest({
"id": "prompt-addon",
"name": "Prompt Addon",
"contributions": [
{"type": "agent_prompt", "text": "Prefer compact summaries."},
{"type": "unknown", "text": "ignored"},
],
})
assert addons.get_addons_prompt() == ""
addons.set_addon_enabled("prompt-addon", True)
prompt = addons.get_addons_prompt()
assert "Prompt Addon" in prompt
assert "Prefer compact summaries." in prompt
assert "unknown" not in prompt
def test_addon_id_rejects_path_traversal(addon_store):
with pytest.raises(ValueError):
addons.save_addon_manifest({"id": "../bad", "name": "Bad"})
@pytest.fixture
def addon_routes(addon_store):
fastapi = pytest.importorskip("fastapi")
from routes.addon_routes import setup_addon_routes
class _AuthManager:
def get_username_for_token(self, token):
return "admin" if token == "session-token" else None
def is_admin(self, user):
return user == "admin"
router = setup_addon_routes(_AuthManager())
def endpoint(path, method):
for route in router.routes:
if getattr(route, "path", "") == path and method in getattr(route, "methods", set()):
return route.endpoint
raise AssertionError(f"{method} {path} route not registered")
return endpoint, fastapi.HTTPException
class _Request(SimpleNamespace):
def __init__(self, token="session-token"):
super().__init__(cookies={"odysseus_session": token})
def test_addon_routes_require_admin(addon_routes):
endpoint, http_exception = addon_routes
list_all = endpoint("/api/addons", "GET")
with pytest.raises(http_exception) as exc:
asyncio.run(list_all(_Request(token="bad")))
assert exc.value.status_code == 401
def test_addon_routes_create_and_enable(addon_routes):
endpoint, _ = addon_routes
create = endpoint("/api/addons", "POST")
set_enabled = endpoint("/api/addons/{addon_id}/enabled", "POST")
list_all = endpoint("/api/addons", "GET")
body = SimpleNamespace(manifest={"id": "route-addon", "name": "Route Addon"})
result = asyncio.run(create(body, _Request()))
assert result["addon"]["id"] == "route-addon"
enabled_body = SimpleNamespace(enabled=True)
asyncio.run(set_enabled("route-addon", enabled_body, _Request()))
listed = asyncio.run(list_all(_Request()))
assert listed["addons"][0]["enabled"] is True
assert json.loads((addons._addon_dir("route-addon") / "addon.json").read_text())["enabled"] is True