molecule-core/workspace-template/tests/test_medo.py
Hongming Wang 24fec62d7f initial commit — Molecule AI platform
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1)
with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo.

Brand: Starfire → Molecule AI.
Slug: starfire / agent-molecule → molecule.
Env vars: STARFIRE_* → MOLECULE_*.
Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform.
Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent.
DB: agentmolecule → molecule.

History truncated; see public repo for prior commits and contributor
attribution. Verified green: go test -race ./... (platform), pytest
(workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:55:37 -07:00

90 lines
3.1 KiB
Python

"""Tests for workspace-template/builtin_tools/medo.py.
All tests exercise the mock backend (no MEDO_API_KEY required).
NOTE: conftest.py mocks builtin_tools with __path__=[] and mocks
langchain_core.tools.tool as a no-op (lambda f: f) so adapters can be
imported without heavy deps. Consequence: direct package import of
builtin_tools.medo is blocked (empty __path__ prevents filesystem
lookup), and @tool returns the raw async function rather than a LangChain
StructuredTool — so .ainvoke() is unavailable.
Fix: load medo.py via importlib (bypasses the mock package root) and
call functions directly, not via .ainvoke().
"""
import importlib.util
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
_MEDO_PATH = ROOT / "builtin_tools" / "medo.py"
def _load_medo():
spec = importlib.util.spec_from_file_location("builtin_tools.medo", _MEDO_PATH)
mod = importlib.util.module_from_spec(spec)
sys.modules["builtin_tools.medo"] = mod # register before exec to handle self-refs
spec.loader.exec_module(mod)
return mod
@pytest.fixture()
def medo(monkeypatch):
monkeypatch.delenv("MEDO_API_KEY", raising=False)
monkeypatch.delenv("MEDO_BASE_URL", raising=False)
return _load_medo()
class TestCreateMedoApp:
@pytest.mark.asyncio
async def test_requires_name(self, medo):
result = await medo.create_medo_app(name="")
assert "error" in result
@pytest.mark.asyncio
async def test_rejects_unknown_template(self, medo):
result = await medo.create_medo_app(name="app", template="unknown")
assert "error" in result and "template" in result["error"]
@pytest.mark.asyncio
async def test_mock_success(self, medo):
result = await medo.create_medo_app(name="my-app", template="chatbot")
assert result.get("mock") is True and result.get("status") == "ok"
class TestUpdateMedoApp:
@pytest.mark.asyncio
async def test_requires_app_id(self, medo):
result = await medo.update_medo_app(app_id="", content={"title": "x"})
assert "error" in result
@pytest.mark.asyncio
async def test_requires_non_empty_content(self, medo):
result = await medo.update_medo_app(app_id="abc", content={})
assert "error" in result
@pytest.mark.asyncio
async def test_mock_success(self, medo):
result = await medo.update_medo_app(app_id="abc", content={"title": "v2"})
assert result.get("mock") is True and "abc" in result.get("path", "")
class TestPublishMedoApp:
@pytest.mark.asyncio
async def test_requires_app_id(self, medo):
result = await medo.publish_medo_app(app_id="")
assert "error" in result
@pytest.mark.asyncio
async def test_rejects_invalid_environment(self, medo):
result = await medo.publish_medo_app(app_id="abc", environment="dev")
assert "error" in result and "environment" in result["error"]
@pytest.mark.asyncio
async def test_mock_success(self, medo):
result = await medo.publish_medo_app(app_id="abc")
assert result.get("mock") is True and result.get("status") == "ok"