test_scoped_api_client.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import unittest
  2. from unittest.mock import MagicMock
  3. from services.scoped_api_client import ScopedApiClient
  4. class TestScopedApiClient(unittest.TestCase):
  5. def setUp(self):
  6. self.mock_transport = MagicMock()
  7. self.client = ScopedApiClient(
  8. base_url='http://api.example.com',
  9. transport=self.mock_transport,
  10. timeout=15
  11. )
  12. def test_call_tool_success(self):
  13. token = 'MT_valid_token'
  14. tool_code = 'query_order'
  15. route_path = '/mcp/tools/query_order'
  16. payload = {'order_no': 'ABC123'}
  17. request_id = 'rq_test123'
  18. self.mock_transport.post_json.return_value = {
  19. 'code': '0',
  20. 'msg': 'success',
  21. 'data': {'order': 'details'}
  22. }
  23. result = self.client.call_tool(token, tool_code, route_path, payload, request_id)
  24. # Verify transport call
  25. self.mock_transport.post_json.assert_called_once_with(
  26. 'http://api.example.com/mcp/tools/query_order',
  27. payload,
  28. {
  29. 'Authorization': 'Bearer MT_valid_token',
  30. 'X-MCP-Tool-Code': 'query_order',
  31. 'X-Request-Id': 'rq_test123',
  32. },
  33. 15
  34. )
  35. # Verify result
  36. self.assertEqual(result['code'], '0')
  37. self.assertEqual(result['data']['order'], 'details')
  38. def test_call_tool_raises_on_empty_token(self):
  39. with self.assertRaises(RuntimeError) as context:
  40. self.client.call_tool('', 'query_order', '/path', {}, 'rq_1')
  41. self.assertIn('mcp token missing', str(context.exception))
  42. def test_call_tool_raises_on_none_token(self):
  43. with self.assertRaises(RuntimeError) as context:
  44. self.client.call_tool(None, 'query_order', '/path', {}, 'rq_1')
  45. self.assertIn('mcp token missing', str(context.exception))
  46. def test_call_tool_strips_leading_slash_from_route(self):
  47. self.mock_transport.post_json.return_value = {'code': '0'}
  48. self.client.call_tool('MT_token', 'tool', '/api/endpoint', {}, 'rq_1')
  49. call_url = self.mock_transport.post_json.call_args[0][0]
  50. self.assertEqual(call_url, 'http://api.example.com/api/endpoint')
  51. def test_call_tool_handles_route_without_leading_slash(self):
  52. self.mock_transport.post_json.return_value = {'code': '0'}
  53. self.client.call_tool('MT_token', 'tool', 'api/endpoint', {}, 'rq_1')
  54. call_url = self.mock_transport.post_json.call_args[0][0]
  55. self.assertEqual(call_url, 'http://api.example.com/api/endpoint')
  56. def test_call_tool_strips_trailing_slash_from_base_url(self):
  57. client_with_slash = ScopedApiClient(
  58. base_url='http://api.example.com/',
  59. transport=self.mock_transport,
  60. timeout=10
  61. )
  62. self.mock_transport.post_json.return_value = {'code': '0'}
  63. client_with_slash.call_tool('MT_token', 'tool', '/endpoint', {}, 'rq_1')
  64. call_url = self.mock_transport.post_json.call_args[0][0]
  65. # Should not have double slash
  66. self.assertEqual(call_url, 'http://api.example.com/endpoint')
  67. def test_call_tool_timeout_parameter(self):
  68. client_short_timeout = ScopedApiClient(
  69. base_url='http://api.example.com',
  70. transport=self.mock_transport,
  71. timeout=5
  72. )
  73. self.mock_transport.post_json.return_value = {'code': '0'}
  74. client_short_timeout.call_tool('MT_token', 'tool', '/path', {}, 'rq_1')
  75. # Verify timeout is passed correctly
  76. call_timeout = self.mock_transport.post_json.call_args[0][3]
  77. self.assertEqual(call_timeout, 5)
  78. def test_call_tool_with_empty_payload(self):
  79. self.mock_transport.post_json.return_value = {'code': '0'}
  80. self.client.call_tool('MT_token', 'tool', '/path', {}, 'rq_1')
  81. call_payload = self.mock_transport.post_json.call_args[0][1]
  82. self.assertEqual(call_payload, {})
  83. def test_call_tool_headers_format(self):
  84. self.mock_transport.post_json.return_value = {'code': '0'}
  85. self.client.call_tool('MT_abc123', 'query_track', '/track', {'no': '123'}, 'rq_xyz')
  86. call_headers = self.mock_transport.post_json.call_args[0][2]
  87. self.assertEqual(call_headers['Authorization'], 'Bearer MT_abc123')
  88. self.assertEqual(call_headers['X-MCP-Tool-Code'], 'query_track')
  89. self.assertEqual(call_headers['X-Request-Id'], 'rq_xyz')
  90. if __name__ == '__main__':
  91. unittest.main()