test_bind_auth_code_tool.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import unittest
  2. from app import GatewayApp
  3. from mcp_protocol import McpProtocolHandler
  4. from services.token_store import InMemoryTokenStore
  5. class DummyAuthClient:
  6. def __init__(self, token_store):
  7. self.token_store = token_store
  8. self.exchange_calls = []
  9. def exchange(self, auth_code):
  10. self.exchange_calls.append(auth_code)
  11. self.token_store.save('MT_bound_secret', '2099-01-01T00:00:00')
  12. return {
  13. 'code': 'MCP_0000',
  14. 'msg': 'success',
  15. 'data': {
  16. 'mcp_token': 'MT_bound_secret',
  17. 'expire_time': '2099-01-01T00:00:00',
  18. },
  19. }
  20. class DummyApiClient:
  21. def call_tool(self, tool_code, route_path, payload, request_id):
  22. return {
  23. 'code': 'MCP_0000',
  24. 'msg': 'success',
  25. 'data': {
  26. 'summary': 'ok',
  27. 'records': [],
  28. 'tips': [],
  29. },
  30. 'meta': {
  31. 'request_id': request_id,
  32. },
  33. }
  34. class BindAuthCodeToolTest(unittest.TestCase):
  35. def build_handler(self, with_token=False):
  36. store = InMemoryTokenStore(refresh_skew_seconds=60)
  37. if with_token:
  38. store.save('MT_ready', '2099-01-01T00:00:00')
  39. auth_client = DummyAuthClient(store)
  40. app = GatewayApp(
  41. auth_client=auth_client,
  42. api_client=DummyApiClient(),
  43. token_store=store,
  44. )
  45. return McpProtocolHandler(app), auth_client, store
  46. def test_tools_list_includes_bind_auth_code(self):
  47. handler, _, _ = self.build_handler()
  48. response = handler.handle_request(
  49. {
  50. 'jsonrpc': '2.0',
  51. 'id': 1,
  52. 'method': 'tools/list',
  53. 'params': {},
  54. }
  55. )
  56. names = [tool['name'] for tool in response['result']['tools']]
  57. self.assertIn('bind_auth_code', names)
  58. bind_tool = [tool for tool in response['result']['tools'] if tool['name'] == 'bind_auth_code'][0]
  59. self.assertEqual(['auth_code'], bind_tool['inputSchema']['required'])
  60. def test_bind_auth_code_exchanges_code_and_hides_token(self):
  61. handler, auth_client, store = self.build_handler()
  62. response = handler.handle_request(
  63. {
  64. 'jsonrpc': '2.0',
  65. 'id': 2,
  66. 'method': 'tools/call',
  67. 'params': {
  68. 'name': 'bind_auth_code',
  69. 'arguments': {
  70. 'auth_code': ' AUTH123 ',
  71. },
  72. },
  73. }
  74. )
  75. self.assertFalse(response['result']['isError'])
  76. self.assertEqual(['AUTH123'], auth_client.exchange_calls)
  77. self.assertEqual('MT_bound_secret', store.get()['token'])
  78. text = response['result']['content'][0]['text']
  79. structured = response['result']['structuredContent']
  80. self.assertIn('绑定成功', text)
  81. self.assertNotIn('MT_bound_secret', text)
  82. self.assertNotIn('mcp_token', structured)
  83. self.assertEqual('bound', structured['status'])
  84. def test_query_order_without_token_returns_employee_binding_hint(self):
  85. handler, _, _ = self.build_handler(with_token=False)
  86. response = handler.handle_request(
  87. {
  88. 'jsonrpc': '2.0',
  89. 'id': 3,
  90. 'method': 'tools/call',
  91. 'params': {
  92. 'name': 'query_order',
  93. 'arguments': {
  94. 'keyword': 'SO20260706001',
  95. },
  96. },
  97. }
  98. )
  99. self.assertTrue(response['result']['isError'])
  100. self.assertIn('请先登录后台获取 Workbuddy 授权码', response['result']['content'][0]['text'])
  101. if __name__ == '__main__':
  102. unittest.main()