from unittest.mock import AsyncMock, MagicMock, patch import pytest from src.server.services.report_service import report_service @pytest.mark.asyncio @patch("src.server.services.projects.task_service.task_service", new_callable=AsyncMock) @patch("src.server.services.agent_service.agent_service", new_callable=AsyncMock) @patch("src.server.repositories.base_repository.get_supabase_client") @patch.object(report_service, "gather_report_context", new_callable=AsyncMock) async def test_run_daily_executive_summary_success(mock_gather, mock_get_supabase, mock_agent_service, mock_task_service): """ Test that daily executive summary creates a task with gathered context and dispatches a star-topology group chat task. """ mock_gather.return_value = "Mocked Context for Daily" mock_supabase = MagicMock() report_service.supabase_client = mock_supabase mock_p_res = MagicMock() mock_p_res.data = [{"id": "test-project-123"}] mock_supabase.table().select().limit().execute.return_value = mock_p_res mock_task_service.create_task.return_value = (True, {"task": {"id": "test-task-123"}}) await report_service.generate_daily_executive_summary() mock_gather.assert_awaited_once_with(1) mock_task_service.create_task.assert_awaited_once() call_kwargs = mock_task_service.create_task.call_args.kwargs assert call_kwargs["project_id"] == "test-project-123" assert "[Daily Report] Executive Summary" in call_kwargs["title"] assert "Mocked Context for Daily" in call_kwargs["description"] mock_supabase.table.assert_any_call("archon_logs") insert_call = [call for call in mock_supabase.table().insert.mock_calls if "report-service" in str(call)] assert len(insert_call) > 0 payload = insert_call[0].args[0] assert "Daily Executive Summary group chat dispatched" in payload["message"] @pytest.mark.asyncio @patch("src.server.services.projects.task_service.task_service", new_callable=AsyncMock) @patch("src.server.repositories.base_repository.get_supabase_client") @patch("src.agents.workflow.engine_beta_graph.beta_graph", new_callable=AsyncMock) @patch.object(report_service, "gather_report_context", new_callable=AsyncMock) async def test_run_weekly_executive_summary_success(mock_gather, mock_beta_graph, mock_get_supabase, mock_task_service): """ Test that weekly executive summary executes Map-Reduce, creates task, and updates status to done. """ mock_gather.return_value = "Mocked Context for Weekly" class MockResult: def __init__(self, output): self.output = output mock_beta_graph.run.return_value = MockResult("Mocked Weekly Map-Reduce Output") mock_supabase = MagicMock() report_service.supabase_client = mock_supabase mock_p_res = MagicMock() mock_p_res.data = [{"id": "test-project-123"}] mock_c_res = MagicMock() mock_c_res.data = [{"id": "test-charlie-id"}] def mock_execute(): return mock_p_res mock_supabase.table().select().limit().execute.return_value = mock_p_res mock_supabase.table().select().eq().execute.return_value = mock_c_res mock_task_service.create_task.return_value = (True, {"task": {"id": "test-task-weekly"}}) mock_task_service.update_task = AsyncMock(return_value=(True, {})) await report_service.generate_weekly_executive_summary() mock_gather.assert_awaited_once_with(7) mock_beta_graph.run.assert_awaited_once() mock_task_service.create_task.assert_awaited_once() mock_task_service.update_task.assert_awaited_once_with("test-task-weekly", {"status": "done"}) call_kwargs = mock_task_service.create_task.call_args.kwargs assert "[Weekly Report] Executive Summary" in call_kwargs["title"] assert "Mocked Weekly Map-Reduce Output" in call_kwargs["description"] @pytest.mark.asyncio @patch("src.server.services.projects.task_service.task_service", new_callable=AsyncMock) @patch("src.server.repositories.base_repository.get_supabase_client") @patch("src.agents.workflow.engine_beta_graph.beta_graph", new_callable=AsyncMock) @patch.object(report_service, "gather_report_context", new_callable=AsyncMock) async def test_run_monthly_executive_summary_success(mock_gather, mock_beta_graph, mock_get_supabase, mock_task_service): """ Test that monthly executive summary executes Map-Reduce, creates task, and updates status to done. """ mock_gather.return_value = "Mocked Context for Monthly" class MockResult: def __init__(self, output): self.output = output mock_beta_graph.run.return_value = MockResult("Mocked Monthly Map-Reduce Output") mock_supabase = MagicMock() report_service.supabase_client = mock_supabase mock_p_res = MagicMock() mock_p_res.data = [{"id": "test-project-123"}] mock_c_res = MagicMock() mock_c_res.data = [{"id": "test-charlie-id"}] mock_supabase.table().select().limit().execute.return_value = mock_p_res mock_supabase.table().select().eq().execute.return_value = mock_c_res mock_task_service.create_task.return_value = (True, {"task": {"id": "test-task-monthly"}}) mock_task_service.update_task = AsyncMock(return_value=(True, {})) await report_service.generate_monthly_executive_summary() mock_gather.assert_awaited_once_with(30) mock_beta_graph.run.assert_awaited_once() mock_task_service.create_task.assert_awaited_once() mock_task_service.update_task.assert_awaited_once_with("test-task-monthly", {"status": "done"}) call_kwargs = mock_task_service.create_task.call_args.kwargs assert "[Monthly Report] Executive Summary" in call_kwargs["title"] assert "Mocked Monthly Map-Reduce Output" in call_kwargs["description"] @pytest.mark.asyncio @patch("src.server.repositories.base_repository.get_supabase_client") async def test_gather_report_context_queries(mock_get_supabase): """ Test that gather_report_context correctly constructs and executes queries on leads, token_usage, archon_logs, and archon_tasks. """ mock_supabase = MagicMock() report_service.supabase_client = mock_supabase mock_res_leads = MagicMock() mock_res_leads.data = [{"company_name": "Google", "job_title": "SWE", "status": "active"}] mock_res_token = MagicMock() mock_res_token.data = [{"input_tokens": 100, "output_tokens": 200, "cost_usd": 0.005}] mock_res_logs = MagicMock() mock_res_logs.data = [{"level": "ERROR", "source": "test-src", "message": "Test error message", "created_at": "2026-05-22"}] mock_res_tasks = MagicMock() mock_res_tasks.data = [{"title": "Task A", "status": "doing", "assignee": "Alice"}] def mock_table(table_name): table_mock = MagicMock() if table_name == "leads": table_mock.select.return_value.gt.return_value.execute.return_value = mock_res_leads elif table_name == "token_usage": table_mock.select.return_value.gt.return_value.execute.return_value = mock_res_token elif table_name == "archon_logs": table_mock.select.return_value.gt.return_value.in_.return_value.execute.return_value = mock_res_logs elif table_name == "archon_tasks": table_mock.select.return_value.gt.return_value.execute.return_value = mock_res_tasks return table_mock mock_supabase.table.side_effect = mock_table result = await report_service.gather_report_context(5) assert "Google (SWE) -> active" in result assert "Input Tokens: 100" in result assert "Output Tokens: 200" in result assert "Total Cost: $0.0050 USD" in result assert "[ERROR] test-src: Test error message" in result assert "Task A (Alice) -> status: doing" in result