from __future__ import annotations import json import tempfile import unittest from pathlib import Path from unittest.mock import patch from daily_report import scheduled class ScheduledTest(unittest.TestCase): def test_send_summary_builds_today_summary_payload(self) -> None: with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp: root = Path(temp) seed_path = root / "employees.json" seed_path.write_text( json.dumps( [ {"feishu_user_id": "u_1", "name": "Lin", "active": True}, {"feishu_user_id": "u_2", "name": "Chen", "active": True}, ], ensure_ascii=False, ), encoding="utf-8", ) fake_file = root / "daily_report" / "config.py" fake_file.parent.mkdir() fake_file.write_text("", encoding="utf-8") env = { "DATABASE_PATH": "test.sqlite", "EMPLOYEE_SEED_PATH": "employees.json", "BASE_URL": "http://localhost:8787", "FEISHU_WEBHOOK_URL": "https://example.test/webhook", } captured = {} def fake_send(webhook_url: str, payload: dict, secret: str = "") -> dict: captured["webhook_url"] = webhook_url captured["payload"] = payload captured["secret"] = secret return {"ok": True} with patch("daily_report.config.__file__", str(fake_file)), patch.dict("os.environ", env, clear=True), patch( "daily_report.scheduled.send_webhook", fake_send ): result = scheduled.send_summary("2026-05-07") self.assertEqual(result, {"ok": True}) self.assertEqual(captured["webhook_url"], "https://example.test/webhook") self.assertEqual(captured["secret"], "") text = json.dumps(captured["payload"], ensure_ascii=False) self.assertIn("2026-05-07 日报提交汇总", text) self.assertIn("0/2", text) self.assertIn("Chen、Lin", text) def test_send_reminder_private_messages_all_active_employees(self) -> None: with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp: root = Path(temp) seed_path = root / "employees.json" seed_path.write_text( json.dumps( [ {"feishu_user_id": "ou_1", "name": "Lin", "active": True}, {"feishu_user_id": "ou_2", "name": "Chen", "active": True}, ], ensure_ascii=False, ), encoding="utf-8", ) fake_file = root / "daily_report" / "config.py" fake_file.parent.mkdir() fake_file.write_text("", encoding="utf-8") env = { "DATABASE_PATH": "test.sqlite", "EMPLOYEE_SEED_PATH": "employees.json", "BASE_URL": "http://localhost:8787", "FEISHU_APP_ID": "cli_test", "FEISHU_APP_SECRET": "secret", } sent = [] def fake_send(token: str, receive_id: str, payload: dict) -> dict: sent.append((token, receive_id, payload)) return {"ok": True} with patch("daily_report.config.__file__", str(fake_file)), patch.dict("os.environ", env, clear=True), patch( "daily_report.scheduled.get_tenant_access_token", lambda app_id, app_secret: "tenant-token" ), patch("daily_report.scheduled.send_bot_interactive_message", fake_send): result = scheduled.send_reminder() self.assertEqual(result["mode"], "bot_private") self.assertEqual([item[1] for item in sent], ["ou_2", "ou_1"]) def test_send_summary_private_messages_admins_only(self) -> None: with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp: root = Path(temp) seed_path = root / "employees.json" seed_path.write_text( json.dumps( [ {"feishu_user_id": "ou_admin", "name": "Admin", "active": True, "role": "admin"}, {"feishu_user_id": "ou_staff", "name": "Staff", "active": True, "role": "staff"}, ], ensure_ascii=False, ), encoding="utf-8", ) fake_file = root / "daily_report" / "config.py" fake_file.parent.mkdir() fake_file.write_text("", encoding="utf-8") env = { "DATABASE_PATH": "test.sqlite", "EMPLOYEE_SEED_PATH": "employees.json", "BASE_URL": "http://localhost:8787", "FEISHU_APP_ID": "cli_test", "FEISHU_APP_SECRET": "secret", } sent = [] with patch("daily_report.config.__file__", str(fake_file)), patch.dict("os.environ", env, clear=True), patch( "daily_report.scheduled.get_tenant_access_token", lambda app_id, app_secret: "tenant-token" ), patch( "daily_report.scheduled.send_bot_interactive_message", lambda token, receive_id, payload: sent.append(receive_id) or {"ok": True}, ): result = scheduled.send_summary("2026-05-07") self.assertEqual(result["mode"], "bot_private") self.assertEqual(sent, ["ou_admin"]) if __name__ == "__main__": unittest.main()