Files
odysseus/tests/test_backup_import_skills.py

93 lines
3.0 KiB
Python

"""Backup import must not call the removed skills_manager.save().
Skills migrated from data/skills.json to on-disk SKILL.md files; save() was
removed from SkillsManager. Import still always sees a ``skills`` key in
exported backups (often ``[]``), so calling save() raised AttributeError,
returned a 500 HTML page, and the UI reported a misleading JSON.parse error
from res.json().
"""
import asyncio
from types import SimpleNamespace
from unittest.mock import MagicMock
import routes.backup_routes as br
class _Req:
def __init__(self, body):
self._body = body
async def json(self):
return self._body
def _setup(monkeypatch, skills_manager):
monkeypatch.setattr(br, "require_admin", lambda request: None)
monkeypatch.setattr(br, "get_current_user", lambda request: "alice")
mem = MagicMock()
mem.load_all.return_value = []
mem.save.return_value = None
presets = MagicMock()
presets.get_all.return_value = {}
presets.save.return_value = True
router = br.setup_backup_routes(mem, presets, skills_manager)
endpoint = None
for r in router.routes:
if r.path == "/api/import" and "POST" in getattr(r, "methods", set()):
endpoint = r.endpoint
assert endpoint is not None
return endpoint
def test_import_with_empty_skills_list_does_not_call_save(monkeypatch):
skills = MagicMock(spec=["load_all", "add_skill"])
skills.load_all.return_value = []
endpoint = _setup(monkeypatch, skills)
body = {"settings": {"foo": "bar"}, "skills": []}
with monkeypatch.context() as m:
m.setattr(br, "load_settings", lambda: {})
m.setattr(br, "save_settings", lambda s: None)
result = asyncio.run(endpoint(_Req(body)))
assert result["ok"] is True
skills.add_skill.assert_not_called()
assert not hasattr(skills, "save") or not getattr(skills, "save", MagicMock()).called
def test_import_adds_new_skill_via_add_skill(monkeypatch):
skills = MagicMock(spec=["load_all", "add_skill"])
skills.load_all.return_value = []
skills.add_skill.return_value = {
"id": "buy-milk",
"name": "buy-milk",
"title": "Buy milk",
}
endpoint = _setup(monkeypatch, skills)
body = {
"skills": [{"name": "buy-milk", "title": "Buy milk", "description": "Buy milk"}],
"preferences": {"theme": "dark"},
}
with monkeypatch.context() as m:
m.setattr(br, "load_settings", lambda: {})
m.setattr(br, "save_settings", lambda s: None)
m.setattr(br, "load_features", lambda: {})
m.setattr(br, "save_features", lambda f: None)
m.setattr(
"routes.prefs_routes._load_for_user",
lambda user: {},
)
m.setattr(
"routes.prefs_routes._save_for_user",
lambda user, prefs: None,
)
result = asyncio.run(endpoint(_Req(body)))
assert result["ok"] is True
skills.add_skill.assert_called_once()
assert skills.add_skill.call_args.kwargs.get("source") == "user"