"""Agent schedule-tool adapter tests with an isolated fake scheduler.""" from pathlib import Path import sys import unittest from types import SimpleNamespace BASE = Path(__file__).resolve().parents[1] sys.path[:0] = [str(BASE / "bot-utility"), str(BASE)] from agent import ToolContext, ToolExecutor class FakeScheduler: def __init__(self): self.created = None self.cancelled = None def create_from_params(self, ctx, params): self.created = (ctx, params) return {"id": "abc12345", "message": params["message"], "kind": params["kind"], "next_run_text": "今晚八点"} def list_for_context(self, ctx): return [{"id": "abc12345", "message": "吃饭", "kind": "once", "next_run_text": "今晚八点"}] def cancel_for_context(self, ctx, task_id): self.cancelled = (ctx, task_id) return {"id": "abc12345", "message": "吃饭"} class ScheduleToolTests(unittest.IsolatedAsyncioTestCase): def setUp(self): self.fake = FakeScheduler() module = SimpleNamespace(scheduler=self.fake, format_task=lambda task: f"{task['id']} {task['message']} {task.get('next_run_text', '')}") self.executor = ToolExecutor(modules={"schedule": module}) self.ctx = ToolContext( channel=SimpleNamespace(name="tg"), msg_type="private", user_id=1, target_id=10001, is_admin=False, ) async def test_schema_exposes_schedule_to_normal_users(self): names = [item["name"] for item in self.executor.prompt_schema(self.ctx)] self.assertIn("schedule", names) async def test_create_uses_current_conversation(self): result = await self.executor.execute( "schedule", {"action": "create", "params": {"message": "吃饭", "kind": "once", "run_at": "2026-10-30T20:00:00+08:00"}}, self.ctx, ) self.assertTrue(result.ok) self.assertIs(self.fake.created[0], self.ctx) self.assertEqual(self.fake.created[1]["message"], "吃饭") async def test_list_and_cancel(self): listed = await self.executor.execute("schedule", {"action": "list", "params": {}}, self.ctx) self.assertIn("abc12345", listed.safe_message) cancelled = await self.executor.execute( "schedule", {"action": "cancel", "params": {"id": "abc"}}, self.ctx ) self.assertTrue(cancelled.ok) self.assertEqual(self.fake.cancelled, (self.ctx, "abc")) async def test_cancel_rejects_extra_params(self): result = await self.executor.execute( "schedule", {"action": "cancel", "params": {"id": "abc", "uid": 2}}, self.ctx ) self.assertFalse(result.ok) self.assertEqual(result.code, "invalid_args") if __name__ == "__main__": unittest.main()