| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- """端到端测试:CodingAgent 自主完成图片拼接工具的编写、测试和注册
- 运行方式:
- uv run python -m tests.test_e2e_stitcher
- 前置条件:
- - ANTHROPIC_API_KEY 已设置
- - uv 已安装
- """
- import asyncio
- import json
- import logging
- import sys
- from pathlib import Path
- # 确保项目根目录在 sys.path 中
- ROOT = Path(__file__).resolve().parent.parent
- sys.path.insert(0, str(ROOT / "src"))
- from tool_agent.config import settings
- from tool_agent.tool.agent import CodingAgent
- from tool_agent.registry.registry import ToolRegistry
- logging.basicConfig(
- level=logging.INFO,
- format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
- )
- logger = logging.getLogger("e2e_test")
- TOOL_ID = "image_stitcher"
- TASK_SPEC = f"""\
- 请创建一个「图片拼接工具」,使用本地 uv 环境。
- ## 功能需求
- 将多张图片按指定方式拼接成一张大图。
- ## 输入参数(POST /stitch,JSON Body)
- - images: list[str] — Base64 编码的图片列表(至少 2 张)
- - direction: str — 拼接方向,可选 "horizontal" | "vertical" | "grid",默认 "horizontal"
- - columns: int — grid 模式下每行列数,默认 2
- - spacing: int — 图片间距(像素),默认 0
- - background_color: str — 间距填充色,默认 "#FFFFFF"
- - resize_mode: str — "none" 不缩放 | "fit_width" 统一宽度 | "fit_height" 统一高度,默认 "none"
- ## 输出(JSON)
- - image: str — 拼接结果,Base64 编码的 PNG
- - width: int — 结果图宽度
- - height: int — 结果图高度
- ## 技术要求
- 1. 使用 uv 环境,项目名 {TOOL_ID}
- 2. 核心依赖:Pillow
- 3. HTTP 接口:FastAPI + uvicorn,端口自选
- 4. 路由:POST /stitch(拼接)、GET /health(健康检查,返回 {{"status":"ok"}})
- 5. 编写一个自测脚本 test_stitch.py:生成几张纯色小图 → 调用拼接函数 → 验证输出尺寸正确
- 6. 自测通过后,使用 register_tool 注册,tool_id = "{TOOL_ID}"
- ## 注意
- - 这是 uv 本地项目,不需要 Docker
- - 先跑通自测脚本再注册,确保核心逻辑正确
- """
- async def run_test() -> bool:
- """执行端到端测试,返回是否通过"""
- logger.info("=" * 60)
- logger.info("E2E Test: Image Stitcher Tool")
- logger.info("=" * 60)
- # ---- 1. 执行任务 ----
- agent = CodingAgent()
- logger.info("Sending task to CodingAgent...")
- result = await agent.execute(TASK_SPEC)
- logger.info("Agent finished. Result:")
- logger.info(result)
- # ---- 2. 验证注册 ----
- logger.info("-" * 60)
- logger.info("Verifying registration...")
- registry = ToolRegistry()
- tool = registry.get(TOOL_ID)
- if not tool:
- logger.error(f"FAIL: tool '{TOOL_ID}' not found in registry")
- return False
- logger.info(f"OK: tool registered — {tool.tool_id} ({tool.name})")
- logger.info(f" runtime: {tool.runtime.type.value}")
- logger.info(f" status: {tool.status.value}")
- endpoint = registry.get_endpoint(TOOL_ID)
- if endpoint:
- logger.info(f" endpoint: {json.dumps(endpoint, ensure_ascii=False)}")
- else:
- logger.warning(" endpoint: None (may be expected for local stdio tool)")
- # ---- 3. 验证项目文件 ----
- logger.info("-" * 60)
- logger.info("Verifying project files...")
- project_dir = settings.tools_dir / "local" / TOOL_ID
- checks = {
- "project dir exists": project_dir.is_dir(),
- "pyproject.toml": (project_dir / "pyproject.toml").exists(),
- }
- all_pass = True
- for label, ok in checks.items():
- status = "OK" if ok else "FAIL"
- logger.info(f" {status}: {label}")
- if not ok:
- all_pass = False
- # 列出项目内文件
- if project_dir.is_dir():
- files = sorted(p.relative_to(project_dir) for p in project_dir.rglob("*") if p.is_file())
- logger.info(f" project files ({len(files)}):")
- for f in files:
- logger.info(f" {f}")
- # ---- 4. 汇总 ----
- logger.info("=" * 60)
- if all_pass and tool:
- logger.info("E2E TEST PASSED")
- else:
- logger.error("E2E TEST FAILED")
- return all_pass and tool is not None
- if __name__ == "__main__":
- ok = asyncio.run(run_test())
- sys.exit(0 if ok else 1)
|