test_gateway_query_order.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import unittest
  2. from unittest.mock import patch
  3. from app import GatewayApp
  4. from services.api_client import ApiClient, JsonTransport
  5. from services.token_store import InMemoryTokenStore
  6. from tools.query_order import QueryOrderTool
  7. class DummyTransport:
  8. def __init__(self):
  9. self.calls = []
  10. def post_json(self, url, payload, headers, timeout):
  11. self.calls.append(
  12. {
  13. 'url': url,
  14. 'payload': payload,
  15. 'headers': headers,
  16. 'timeout': timeout,
  17. }
  18. )
  19. return {
  20. 'code': 'MCP_0000',
  21. 'msg': 'success',
  22. 'data': {
  23. 'summary': 'ok',
  24. 'records': [],
  25. 'tips': [],
  26. },
  27. 'meta': {
  28. 'request_id': headers['X-Request-Id'],
  29. },
  30. }
  31. class BomHttpResponse:
  32. def __init__(self, body):
  33. self.body = body
  34. def __enter__(self):
  35. return self
  36. def __exit__(self, exc_type, exc_value, traceback):
  37. return False
  38. def read(self):
  39. return self.body
  40. class GatewayQueryOrderTest(unittest.TestCase):
  41. def test_gateway_lists_query_order_tool(self):
  42. app = GatewayApp()
  43. tools = app.list_tools()
  44. by_name = {tool['name']: tool for tool in tools}
  45. self.assertIn('query_order', by_name)
  46. self.assertIn('keyword', by_name['query_order']['input_schema']['required'])
  47. def test_json_transport_accepts_utf8_bom_response(self):
  48. transport = JsonTransport()
  49. body = b'\xef\xbb\xbf{"code":"MCP_0000","data":{"summary":"ok"}}'
  50. with patch('urllib.request.urlopen', return_value=BomHttpResponse(body)):
  51. response = transport.post_json(
  52. 'http://tools.example.test/mcp/tools/queryOrder',
  53. {'keyword': 'SO20260706001'},
  54. {},
  55. 8,
  56. )
  57. self.assertEqual('MCP_0000', response['code'])
  58. self.assertEqual('ok', response['data']['summary'])
  59. def test_api_client_adds_mcp_headers_when_calling_tool(self):
  60. transport = DummyTransport()
  61. store = InMemoryTokenStore(refresh_skew_seconds=60)
  62. store.save('MT_demo', '2099-01-01T00:00:00')
  63. client = ApiClient(
  64. base_url='http://tools.example.test',
  65. token_store=store,
  66. transport=transport,
  67. timeout=8,
  68. )
  69. response = client.call_tool(
  70. tool_code='query_order',
  71. route_path='/mcp/tools/queryOrder',
  72. payload={'keyword': 'SO20260706001', 'page': 1, 'limit': 20},
  73. request_id='rq_demo',
  74. )
  75. self.assertEqual('MCP_0000', response['code'])
  76. self.assertEqual(1, len(transport.calls))
  77. self.assertEqual('Bearer MT_demo', transport.calls[0]['headers']['Authorization'])
  78. self.assertEqual('query_order', transport.calls[0]['headers']['X-MCP-Tool-Code'])
  79. self.assertEqual('rq_demo', transport.calls[0]['headers']['X-Request-Id'])
  80. self.assertEqual('http://tools.example.test/mcp/tools/queryOrder', transport.calls[0]['url'])
  81. def test_query_order_tool_normalizes_input_before_forwarding(self):
  82. transport = DummyTransport()
  83. store = InMemoryTokenStore(refresh_skew_seconds=60)
  84. store.save('MT_demo', '2099-01-01T00:00:00')
  85. client = ApiClient(
  86. base_url='http://tools.example.test',
  87. token_store=store,
  88. transport=transport,
  89. timeout=8,
  90. )
  91. tool = QueryOrderTool(api_client=client)
  92. tool.call(keyword=' SO20260706001 ', page=2, limit=15, request_id='rq_tool')
  93. self.assertEqual(
  94. {
  95. 'keyword': 'SO20260706001',
  96. 'page': 2,
  97. 'limit': 15,
  98. },
  99. transport.calls[0]['payload'],
  100. )
  101. self.assertEqual('http://tools.example.test/mcp/tools/queryOrder', transport.calls[0]['url'])
  102. if __name__ == '__main__':
  103. unittest.main()