You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_http_tool.py 8.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import json
  2. import logging
  3. import httpx
  4. import pytest
  5. from autogen_core import CancellationToken, Component, ComponentModel
  6. from autogen_ext.tools.http import HttpTool
  7. from pydantic import ValidationError
  8. def test_tool_schema_generation(test_config: ComponentModel) -> None:
  9. tool = HttpTool.load_component(test_config)
  10. schema = tool.schema
  11. assert schema["name"] == "TestHttpTool"
  12. assert "description" in schema
  13. assert schema["description"] == "A test HTTP tool"
  14. assert "parameters" in schema
  15. assert schema["parameters"]["type"] == "object"
  16. assert "properties" in schema["parameters"]
  17. assert schema["parameters"]["properties"]["query"]["description"] == "The test query"
  18. assert schema["parameters"]["properties"]["query"]["type"] == "string"
  19. assert schema["parameters"]["properties"]["value"]["description"] == "A test value"
  20. assert schema["parameters"]["properties"]["value"]["type"] == "integer"
  21. assert "required" in schema["parameters"]
  22. assert set(schema["parameters"]["required"]) == {"query", "value"}
  23. def test_tool_properties(test_config: ComponentModel) -> None:
  24. tool = HttpTool.load_component(test_config)
  25. assert tool.name == "TestHttpTool"
  26. assert tool.description == "A test HTTP tool"
  27. assert tool.server_params.host == "localhost"
  28. assert tool.server_params.port == 8000
  29. assert tool.server_params.path == "/test"
  30. assert tool.server_params.scheme == "http"
  31. assert tool.server_params.method == "POST"
  32. def test_component_base_class(test_config: ComponentModel) -> None:
  33. tool = HttpTool.load_component(test_config)
  34. assert tool.dump_component() is not None
  35. assert HttpTool.load_component(tool.dump_component(), HttpTool) is not None
  36. assert isinstance(tool, Component)
  37. @pytest.mark.asyncio
  38. async def test_post_request(test_config: ComponentModel, test_server: None, caplog: pytest.LogCaptureFixture) -> None:
  39. tool = HttpTool.load_component(test_config)
  40. with caplog.at_level(logging.INFO):
  41. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  42. assert isinstance(result, str)
  43. assert json.loads(result)["result"] == "Received: test query with value 42"
  44. assert "Received: test query with value 42" in caplog.text
  45. @pytest.mark.asyncio
  46. async def test_post_request_json_return(test_config: ComponentModel, test_server: None) -> None:
  47. # Modify config to use json return type
  48. config = test_config.model_copy()
  49. config.config["return_type"] = "json"
  50. tool = HttpTool.load_component(config)
  51. result = await tool.run_json({"query": "test query", "value": 45}, CancellationToken())
  52. assert isinstance(result, dict)
  53. assert result["result"] == "Received: test query with value 45"
  54. @pytest.mark.asyncio
  55. async def test_get_request(test_config: ComponentModel, test_server: None) -> None:
  56. # Modify config for GET request
  57. config = test_config.model_copy()
  58. config.config["method"] = "GET"
  59. tool = HttpTool.load_component(config)
  60. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  61. assert isinstance(result, str)
  62. assert json.loads(result)["result"] == "Received: test query with value 42"
  63. @pytest.mark.asyncio
  64. async def test_put_request(test_config: ComponentModel, test_server: None) -> None:
  65. # Modify config for PUT request
  66. config = test_config.model_copy()
  67. config.config["method"] = "PUT"
  68. tool = HttpTool.load_component(config)
  69. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  70. assert isinstance(result, str)
  71. assert json.loads(result)["result"] == "Received: test query with value 42"
  72. @pytest.mark.asyncio
  73. async def test_path_params(test_config: ComponentModel, test_server: None) -> None:
  74. # Modify config to use path parameters
  75. config = test_config.model_copy()
  76. config.config["path"] = "/test/{query}/{value}"
  77. tool = HttpTool.load_component(config)
  78. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  79. assert isinstance(result, str)
  80. assert json.loads(result)["result"] == "Received: test query with value 42"
  81. @pytest.mark.asyncio
  82. async def test_path_params_and_body(test_config: ComponentModel, test_server: None) -> None:
  83. # Modify config to use path parameters and include body parameters
  84. config = test_config.model_copy()
  85. config.config["method"] = "PUT"
  86. config.config["path"] = "/test/{query}/{value}"
  87. config.config["json_schema"] = {
  88. "type": "object",
  89. "properties": {
  90. "query": {"type": "string", "description": "The test query"},
  91. "value": {"type": "integer", "description": "A test value"},
  92. "extra": {"type": "string", "description": "Extra body parameter"},
  93. },
  94. "required": ["query", "value", "extra"],
  95. }
  96. tool = HttpTool.load_component(config)
  97. result = await tool.run_json({"query": "test query", "value": 42, "extra": "extra data"}, CancellationToken())
  98. assert isinstance(result, str)
  99. assert json.loads(result)["result"] == "Received: test query with value 42 and extra extra data"
  100. @pytest.mark.asyncio
  101. async def test_delete_request(test_config: ComponentModel, test_server: None) -> None:
  102. # Modify config for DELETE request
  103. config = test_config.model_copy()
  104. config.config["method"] = "DELETE"
  105. tool = HttpTool.load_component(config)
  106. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  107. assert isinstance(result, str)
  108. assert json.loads(result)["result"] == "Received: test query with value 42"
  109. @pytest.mark.asyncio
  110. async def test_patch_request(test_config: ComponentModel, test_server: None) -> None:
  111. # Modify config for PATCH request
  112. config = test_config.model_copy()
  113. config.config["method"] = "PATCH"
  114. tool = HttpTool.load_component(config)
  115. result = await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  116. assert isinstance(result, str)
  117. assert json.loads(result)["result"] == "Received: test query with value 42"
  118. @pytest.mark.asyncio
  119. async def test_invalid_schema(test_config: ComponentModel, test_server: None) -> None:
  120. # Create an invalid schema missing required properties
  121. config: ComponentModel = test_config.model_copy()
  122. config.config["host"] = True # Incorrect type
  123. with pytest.raises(ValidationError):
  124. # Should fail when trying to create model from invalid schema
  125. HttpTool.load_component(config)
  126. @pytest.mark.asyncio
  127. async def test_invalid_request(test_config: ComponentModel, test_server: None) -> None:
  128. # Use an invalid URL
  129. config = test_config.model_copy()
  130. config.config["host"] = "fake"
  131. tool = HttpTool.load_component(config)
  132. with pytest.raises(httpx.ConnectError):
  133. await tool.run_json({"query": "test query", "value": 42}, CancellationToken())
  134. def test_config_serialization(test_config: ComponentModel) -> None:
  135. tool = HttpTool.load_component(test_config)
  136. config = tool.dump_component()
  137. assert config.config["name"] == test_config.config["name"]
  138. assert config.config["description"] == test_config.config["description"]
  139. assert config.config["host"] == test_config.config["host"]
  140. assert config.config["port"] == test_config.config["port"]
  141. assert config.config["path"] == test_config.config["path"]
  142. assert config.config["scheme"] == test_config.config["scheme"]
  143. assert config.config["method"] == test_config.config["method"]
  144. assert config.config["headers"] == test_config.config["headers"]
  145. def test_config_deserialization(test_config: ComponentModel) -> None:
  146. tool = HttpTool.load_component(test_config)
  147. assert tool.name == test_config.config["name"]
  148. assert tool.description == test_config.config["description"]
  149. assert tool.server_params.host == test_config.config["host"]
  150. assert tool.server_params.port == test_config.config["port"]
  151. assert tool.server_params.path == test_config.config["path"]
  152. assert tool.server_params.scheme == test_config.config["scheme"]
  153. assert tool.server_params.method == test_config.config["method"]
  154. assert tool.server_params.headers == test_config.config["headers"]