from datetime import datetime from types import SimpleNamespace from unittest.mock import MagicMock, patch from django.test import SimpleTestCase from apps.wpm.models import BatchSt from mcp_server.tools.batch_stats import get_batch_stat, search_batch_stats def batch_stat(**overrides): values = { "id": "500", "batch": "BATCH-001", "version": 1, "zt_batch": "ZT-001", "first_time": datetime(2026, 8, 1, 8, 0), "last_time": datetime(2026, 8, 2, 8, 0), "material_start": SimpleNamespace( id="100", name="原料", model="M-1", specification="S-1", ), "data": {"output": {"count": 10}, "quality": {"ok": 9}}, "update_time": datetime(2026, 8, 10, 8, 0), } values.update(overrides) return SimpleNamespace(**values) class BatchStatToolTests(SimpleTestCase): @patch("mcp_server.tools.batch_stats._base_queryset") @patch("mcp_server.tools.batch_stats.authenticated_factory_user") def test_search_returns_summary_without_full_data( self, _user_mock, queryset_mock, ): queryset = MagicMock() queryset.filter.return_value = queryset queryset.order_by.return_value = queryset queryset.__getitem__.return_value = [batch_stat()] queryset_mock.return_value = queryset result = search_batch_stats(query="BATCH", limit=10) self.assertEqual(result["items"][0]["batch"], "BATCH-001") self.assertEqual(result["items"][0]["data_keys"], ["output", "quality"]) self.assertNotIn("data", result["items"][0]) @patch("mcp_server.tools.batch_stats.BatchLog.objects.filter") @patch("mcp_server.tools.batch_stats._base_queryset") @patch("mcp_server.tools.batch_stats.authenticated_factory_user") def test_get_returns_data_and_direct_relations( self, _user_mock, queryset_mock, relation_filter_mock, ): item = batch_stat() queryset_mock.return_value.get.return_value = item relation_filter_mock.return_value.select_related.return_value.values.return_value = [ { "id": "600", "relation_type": "split", "source_id": "500", "source__batch": "BATCH-001", "source__version": 1, "target_id": "501", "target__batch": "BATCH-001-1", "target__version": 1, "handover_id": "700", "mlog_id": None, } ] result = get_batch_stat("BATCH-001") self.assertEqual(result["data"]["output"]["count"], 10) self.assertEqual(result["relations"][0]["relation_type"], "split") @patch("mcp_server.tools.batch_stats.BatchLog.objects.filter") @patch("mcp_server.tools.batch_stats._base_queryset") @patch("mcp_server.tools.batch_stats.authenticated_factory_user") def test_get_can_omit_relations( self, _user_mock, queryset_mock, relation_filter_mock, ): queryset_mock.return_value.get.return_value = batch_stat() result = get_batch_stat("BATCH-001", include_relations=False) self.assertNotIn("relations", result) relation_filter_mock.assert_not_called() @patch("mcp_server.tools.batch_stats._base_queryset") @patch("mcp_server.tools.batch_stats.authenticated_factory_user") def test_get_reports_missing_batch(self, _user_mock, queryset_mock): queryset_mock.return_value.get.side_effect = BatchSt.DoesNotExist with self.assertRaisesRegex(ValueError, "未找到批次统计"): get_batch_stat("missing")