test_inbound_receipt_tools.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import unittest
  2. from app import GatewayApp
  3. from public_gateway import PublicGatewayApp
  4. from services.output_presenter import OutputPresenter
  5. from tools.export_inbound_receipt import ExportInboundReceiptTool
  6. from tools.list_inbound_receipt_templates import ListInboundReceiptTemplatesTool
  7. class _Api:
  8. def __init__(self):
  9. self.calls = []
  10. def call_tool(self, tool_name, route_path, payload, request_id):
  11. self.calls.append((tool_name, route_path, payload, request_id))
  12. return {'code': 'MCP_0000', 'data': {}}
  13. class InboundReceiptToolTest(unittest.TestCase):
  14. def test_local_and_public_registries_match(self):
  15. local = set(GatewayApp(api_client=object()).registered_tool_names())
  16. public = set(PublicGatewayApp(object(), object()).registered_tool_names())
  17. self.assertEqual(local, public)
  18. self.assertIn('list_inbound_receipt_templates', local)
  19. self.assertIn('export_inbound_receipt', local)
  20. def test_list_tool_strips_and_dedupes_container_codes(self):
  21. api = _Api()
  22. tool = ListInboundReceiptTemplatesTool(api)
  23. tool.call([' CONT-1 ', 'CONT-1'], request_id='rq_list')
  24. self.assertEqual(
  25. ('list_inbound_receipt_templates', '/mcp/tools/listInboundReceiptTemplates',
  26. {'container_codes': ['CONT-1']}, 'rq_list'),
  27. api.calls[0]
  28. )
  29. self.assertIn('container_codes', tool.metadata()['input_schema']['required'])
  30. def test_export_requires_selected_template_and_does_not_wait(self):
  31. api = _Api()
  32. tool = ExportInboundReceiptTool(api)
  33. description = tool.metadata()['description']
  34. self.assertIn('query_export_task', description)
  35. self.assertIn('不会在本次调用中等待文件生成', description)
  36. tool.call(['CONT-1'], ' FMS-INBOUND-LAX ', request_id='rq_export')
  37. self.assertEqual('FMS-INBOUND-LAX', api.calls[0][2]['template_code'])
  38. with self.assertRaises(ValueError):
  39. tool.call(['CONT-1'], ' ')
  40. def test_presenter_shows_kind_and_passes_container_rejection(self):
  41. presenter = OutputPresenter()
  42. shown = presenter.present('list_inbound_receipt_templates', {
  43. 'code': 'MCP_0000',
  44. 'data': {
  45. 'receipt_kind': '直送入仓单',
  46. 'templates': [
  47. {'name': '直送柜', 'template_code': 'FMS-INBOUND-ZSG'},
  48. ],
  49. },
  50. 'meta': {'request_id': 'rq_ok'},
  51. })
  52. self.assertFalse(shown['is_error'])
  53. self.assertEqual('直送入仓单', shown['structured_content']['receipt_kind'])
  54. self.assertNotIn('id', shown['structured_content']['rows'][0])
  55. rejected = presenter.present('list_inbound_receipt_templates', {
  56. 'code': 'MCP_1601',
  57. 'msg': '这些柜号没有对应的排舱单:NONE-1',
  58. 'data': {},
  59. 'meta': {'request_id': 'rq_missing'},
  60. })
  61. self.assertTrue(rejected['is_error'])
  62. self.assertIn('NONE-1', rejected['text'])
  63. hidden = presenter.present('export_inbound_receipt', {
  64. 'code': 'MCP_1601',
  65. 'msg': 'SQLSTATE select * from fms_outbound',
  66. 'data': {},
  67. 'meta': {'request_id': 'rq_sql'},
  68. })
  69. self.assertNotIn('SQLSTATE', hidden['text'])
  70. self.assertIn('没有可导出的数据', hidden['text'])
  71. if __name__ == '__main__':
  72. unittest.main()