From 1dfc7ad1cb7b5fb71230b83f62d00f1206eb62ea Mon Sep 17 00:00:00 2001 From: OhYee Date: Wed, 22 Apr 2026 15:40:33 +0800 Subject: [PATCH] test(api): add unit tests for various control APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive unit tests for the AgentRuntimeControlAPI, CredentialControlAPI, KnowledgeBaseControlAPI, MemoryCollectionControlAPI, ModelControlAPI, SandboxControlAPI, ToolControlAPI, and ToolsetControlAPI. These tests ensure that the API methods correctly match the underlying SDK client method signatures, improving code reliability and maintainability. --- 新增各控制 API 的单元测试 为 AgentRuntimeControlAPI、CredentialControlAPI、KnowledgeBaseControlAPI、MemoryCollectionControlAPI、ModelControlAPI、SandboxControlAPI、ToolControlAPI 和 ToolsetControlAPI 添加了全面的单元测试。这些测试确保 API 方法与底层 SDK 客户端方法签名正确匹配,提高了代码的可靠性和可维护性。 Change-Id: I1d1f89ae1d9bc4c67e5d31bded1864b9790daa25 Signed-off-by: OhYee --- agentrun/agent_runtime/api/control.py | 9 - pyproject.toml | 2 +- .../agent_runtime/api/test_control.py | 201 ++++++++++++++++++ tests/unittests/credential/api/__init__.py | 0 .../unittests/credential/api/test_control.py | 114 ++++++++++ .../knowledgebase/api/test_control.py | 114 ++++++++++ .../memory_collection/api/__init__.py | 0 .../memory_collection/api/test_control.py | 114 ++++++++++ tests/unittests/model/api/test_control.py | 181 ++++++++++++++++ tests/unittests/sandbox/api/test_control.py | 172 +++++++++++++++ tests/unittests/tool/api/__init__.py | 0 tests/unittests/tool/api/test_control.py | 59 +++++ tests/unittests/toolset/api/test_control.py | 74 +++++++ 13 files changed, 1030 insertions(+), 10 deletions(-) create mode 100644 tests/unittests/agent_runtime/api/test_control.py create mode 100644 tests/unittests/credential/api/__init__.py create mode 100644 tests/unittests/credential/api/test_control.py create mode 100644 tests/unittests/knowledgebase/api/test_control.py create mode 100644 tests/unittests/memory_collection/api/__init__.py create mode 100644 tests/unittests/memory_collection/api/test_control.py create mode 100644 tests/unittests/model/api/test_control.py create mode 100644 tests/unittests/sandbox/api/test_control.py create mode 100644 tests/unittests/tool/api/__init__.py create mode 100644 tests/unittests/tool/api/test_control.py create mode 100644 tests/unittests/toolset/api/test_control.py diff --git a/agentrun/agent_runtime/api/control.py b/agentrun/agent_runtime/api/control.py index c3a3847..8b76d45 100644 --- a/agentrun/agent_runtime/api/control.py +++ b/agentrun/agent_runtime/api/control.py @@ -21,9 +21,6 @@ CreateAgentRuntimeEndpointRequest, CreateAgentRuntimeInput, CreateAgentRuntimeRequest, - DeleteAgentRuntimeEndpointRequest, - DeleteAgentRuntimeRequest, - GetAgentRuntimeEndpointRequest, GetAgentRuntimeRequest, ListAgentRuntimeEndpointsOutput, ListAgentRuntimeEndpointsRequest, @@ -196,7 +193,6 @@ def delete_agent_runtime( client = self._get_client(config) response = client.delete_agent_runtime_with_options( agent_id, - DeleteAgentRuntimeRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) @@ -252,7 +248,6 @@ async def delete_agent_runtime_async( client = self._get_client(config) response = await client.delete_agent_runtime_with_options_async( agent_id, - DeleteAgentRuntimeRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) @@ -783,7 +778,6 @@ def delete_agent_runtime_endpoint( response = client.delete_agent_runtime_endpoint_with_options( agent_id, endpoint_id, - DeleteAgentRuntimeEndpointRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) @@ -844,7 +838,6 @@ async def delete_agent_runtime_endpoint_async( await client.delete_agent_runtime_endpoint_with_options_async( agent_id, endpoint_id, - DeleteAgentRuntimeEndpointRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) @@ -1035,7 +1028,6 @@ def get_agent_runtime_endpoint( response = client.get_agent_runtime_endpoint_with_options( agent_id, endpoint_id, - GetAgentRuntimeEndpointRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) @@ -1096,7 +1088,6 @@ async def get_agent_runtime_endpoint_async( await client.get_agent_runtime_endpoint_with_options_async( agent_id, endpoint_id, - GetAgentRuntimeEndpointRequest(), headers=headers or {}, runtime=RuntimeOptions(), ) diff --git a/pyproject.toml b/pyproject.toml index 8ea57d9..126f0df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "litellm>=1.79.3", "alibabacloud-devs20230714>=2.4.1", "pydash>=8.0.5", - "alibabacloud-agentrun20250910>=5.6.1", + "alibabacloud-agentrun20250910>=5.6.3", "alibabacloud_tea_openapi>=0.4.2", "alibabacloud_bailian20231229>=2.6.2", "agentrun-mem0ai>=0.0.10", diff --git a/tests/unittests/agent_runtime/api/test_control.py b/tests/unittests/agent_runtime/api/test_control.py new file mode 100644 index 0000000..6f91335 --- /dev/null +++ b/tests/unittests/agent_runtime/api/test_control.py @@ -0,0 +1,201 @@ +""" +测试 AgentRuntimeControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateAgentRuntimeEndpointInput, + CreateAgentRuntimeInput, + GetAgentRuntimeRequest, + ListAgentRuntimeEndpointsRequest, + ListAgentRuntimesRequest, + ListAgentRuntimeVersionsRequest, + UpdateAgentRuntimeEndpointInput, + UpdateAgentRuntimeInput, +) +import pytest + +from agentrun.agent_runtime.api.control import AgentRuntimeControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = AgentRuntimeControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestAgentRuntimeControlAPISignatures: + + def test_create_agent_runtime(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateAgentRuntimeInput) + api.create_agent_runtime(input_data) + client.create_agent_runtime_with_options.assert_called_once() + + def test_delete_agent_runtime(self, api_and_client): + api, client = api_and_client + api.delete_agent_runtime("agent-123") + client.delete_agent_runtime_with_options.assert_called_once() + + def test_update_agent_runtime(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateAgentRuntimeInput) + api.update_agent_runtime("agent-123", input_data) + client.update_agent_runtime_with_options.assert_called_once() + + def test_get_agent_runtime(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=GetAgentRuntimeRequest) + api.get_agent_runtime("agent-123", input_data) + client.get_agent_runtime_with_options.assert_called_once() + + def test_list_agent_runtimes(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimesRequest) + api.list_agent_runtimes(input_data) + client.list_agent_runtimes_with_options.assert_called_once() + + def test_create_agent_runtime_endpoint(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateAgentRuntimeEndpointInput) + api.create_agent_runtime_endpoint("agent-123", input_data) + client.create_agent_runtime_endpoint_with_options.assert_called_once() + + def test_delete_agent_runtime_endpoint(self, api_and_client): + api, client = api_and_client + api.delete_agent_runtime_endpoint("agent-123", "endpoint-456") + client.delete_agent_runtime_endpoint_with_options.assert_called_once() + + def test_update_agent_runtime_endpoint(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateAgentRuntimeEndpointInput) + api.update_agent_runtime_endpoint( + "agent-123", "endpoint-456", input_data + ) + client.update_agent_runtime_endpoint_with_options.assert_called_once() + + def test_get_agent_runtime_endpoint(self, api_and_client): + api, client = api_and_client + api.get_agent_runtime_endpoint("agent-123", "endpoint-456") + client.get_agent_runtime_endpoint_with_options.assert_called_once() + + def test_list_agent_runtime_endpoints(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimeEndpointsRequest) + api.list_agent_runtime_endpoints("agent-123", input_data) + client.list_agent_runtime_endpoints_with_options.assert_called_once() + + def test_list_agent_runtime_versions(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimeVersionsRequest) + api.list_agent_runtime_versions("agent-123", input_data) + client.list_agent_runtime_versions_with_options.assert_called_once() + + +class TestAgentRuntimeControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_create_agent_runtime_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateAgentRuntimeInput) + await api.create_agent_runtime_async(input_data) + client.create_agent_runtime_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_agent_runtime_async(self, api_and_client): + api, client = api_and_client + await api.delete_agent_runtime_async("agent-123") + client.delete_agent_runtime_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_agent_runtime_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateAgentRuntimeInput) + await api.update_agent_runtime_async("agent-123", input_data) + client.update_agent_runtime_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_agent_runtime_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=GetAgentRuntimeRequest) + await api.get_agent_runtime_async("agent-123", input_data) + client.get_agent_runtime_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_agent_runtimes_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimesRequest) + await api.list_agent_runtimes_async(input_data) + client.list_agent_runtimes_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_create_agent_runtime_endpoint_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateAgentRuntimeEndpointInput) + await api.create_agent_runtime_endpoint_async("agent-123", input_data) + client.create_agent_runtime_endpoint_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_agent_runtime_endpoint_async(self, api_and_client): + api, client = api_and_client + await api.delete_agent_runtime_endpoint_async( + "agent-123", "endpoint-456" + ) + client.delete_agent_runtime_endpoint_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_agent_runtime_endpoint_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateAgentRuntimeEndpointInput) + await api.update_agent_runtime_endpoint_async( + "agent-123", "endpoint-456", input_data + ) + client.update_agent_runtime_endpoint_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_agent_runtime_endpoint_async(self, api_and_client): + api, client = api_and_client + await api.get_agent_runtime_endpoint_async("agent-123", "endpoint-456") + client.get_agent_runtime_endpoint_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_agent_runtime_endpoints_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimeEndpointsRequest) + await api.list_agent_runtime_endpoints_async("agent-123", input_data) + client.list_agent_runtime_endpoints_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_agent_runtime_versions_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListAgentRuntimeVersionsRequest) + await api.list_agent_runtime_versions_async("agent-123", input_data) + client.list_agent_runtime_versions_with_options_async.assert_called_once() diff --git a/tests/unittests/credential/api/__init__.py b/tests/unittests/credential/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unittests/credential/api/test_control.py b/tests/unittests/credential/api/test_control.py new file mode 100644 index 0000000..3b3df19 --- /dev/null +++ b/tests/unittests/credential/api/test_control.py @@ -0,0 +1,114 @@ +""" +测试 CredentialControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateCredentialInput, + ListCredentialsRequest, + UpdateCredentialInput, +) +import pytest + +from agentrun.credential.api.control import CredentialControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = CredentialControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestCredentialControlAPISignatures: + + def test_create_credential(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateCredentialInput) + api.create_credential(input_data) + client.create_credential_with_options.assert_called_once() + + def test_delete_credential(self, api_and_client): + api, client = api_and_client + api.delete_credential("test-cred") + client.delete_credential_with_options.assert_called_once() + + def test_update_credential(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateCredentialInput) + api.update_credential("test-cred", input_data) + client.update_credential_with_options.assert_called_once() + + def test_get_credential(self, api_and_client): + api, client = api_and_client + api.get_credential("test-cred") + client.get_credential_with_options.assert_called_once() + + def test_list_credentials(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListCredentialsRequest) + api.list_credentials(input_data) + client.list_credentials_with_options.assert_called_once() + + +class TestCredentialControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_create_credential_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateCredentialInput) + await api.create_credential_async(input_data) + client.create_credential_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_credential_async(self, api_and_client): + api, client = api_and_client + await api.delete_credential_async("test-cred") + client.delete_credential_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_credential_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateCredentialInput) + await api.update_credential_async("test-cred", input_data) + client.update_credential_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_credential_async(self, api_and_client): + api, client = api_and_client + await api.get_credential_async("test-cred") + client.get_credential_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_credentials_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListCredentialsRequest) + await api.list_credentials_async(input_data) + client.list_credentials_with_options_async.assert_called_once() diff --git a/tests/unittests/knowledgebase/api/test_control.py b/tests/unittests/knowledgebase/api/test_control.py new file mode 100644 index 0000000..d12f713 --- /dev/null +++ b/tests/unittests/knowledgebase/api/test_control.py @@ -0,0 +1,114 @@ +""" +测试 KnowledgeBaseControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateKnowledgeBaseInput, + ListKnowledgeBasesRequest, + UpdateKnowledgeBaseInput, +) +import pytest + +from agentrun.knowledgebase.api.control import KnowledgeBaseControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = KnowledgeBaseControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestKnowledgeBaseControlAPISignatures: + + def test_create_knowledge_base(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateKnowledgeBaseInput) + api.create_knowledge_base(input_data) + client.create_knowledge_base_with_options.assert_called_once() + + def test_delete_knowledge_base(self, api_and_client): + api, client = api_and_client + api.delete_knowledge_base("test-kb") + client.delete_knowledge_base_with_options.assert_called_once() + + def test_update_knowledge_base(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateKnowledgeBaseInput) + api.update_knowledge_base("test-kb", input_data) + client.update_knowledge_base_with_options.assert_called_once() + + def test_get_knowledge_base(self, api_and_client): + api, client = api_and_client + api.get_knowledge_base("test-kb") + client.get_knowledge_base_with_options.assert_called_once() + + def test_list_knowledge_bases(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListKnowledgeBasesRequest) + api.list_knowledge_bases(input_data) + client.list_knowledge_bases_with_options.assert_called_once() + + +class TestKnowledgeBaseControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_create_knowledge_base_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateKnowledgeBaseInput) + await api.create_knowledge_base_async(input_data) + client.create_knowledge_base_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_knowledge_base_async(self, api_and_client): + api, client = api_and_client + await api.delete_knowledge_base_async("test-kb") + client.delete_knowledge_base_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_knowledge_base_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateKnowledgeBaseInput) + await api.update_knowledge_base_async("test-kb", input_data) + client.update_knowledge_base_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_knowledge_base_async(self, api_and_client): + api, client = api_and_client + await api.get_knowledge_base_async("test-kb") + client.get_knowledge_base_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_knowledge_bases_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListKnowledgeBasesRequest) + await api.list_knowledge_bases_async(input_data) + client.list_knowledge_bases_with_options_async.assert_called_once() diff --git a/tests/unittests/memory_collection/api/__init__.py b/tests/unittests/memory_collection/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unittests/memory_collection/api/test_control.py b/tests/unittests/memory_collection/api/test_control.py new file mode 100644 index 0000000..da20f11 --- /dev/null +++ b/tests/unittests/memory_collection/api/test_control.py @@ -0,0 +1,114 @@ +""" +测试 MemoryCollectionControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateMemoryCollectionInput, + ListMemoryCollectionsRequest, + UpdateMemoryCollectionInput, +) +import pytest + +from agentrun.memory_collection.api.control import MemoryCollectionControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = MemoryCollectionControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestMemoryCollectionControlAPISignatures: + + def test_create_memory_collection(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateMemoryCollectionInput) + api.create_memory_collection(input_data) + client.create_memory_collection_with_options.assert_called_once() + + def test_delete_memory_collection(self, api_and_client): + api, client = api_and_client + api.delete_memory_collection("test-collection") + client.delete_memory_collection_with_options.assert_called_once() + + def test_update_memory_collection(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateMemoryCollectionInput) + api.update_memory_collection("test-collection", input_data) + client.update_memory_collection_with_options.assert_called_once() + + def test_get_memory_collection(self, api_and_client): + api, client = api_and_client + api.get_memory_collection("test-collection") + client.get_memory_collection_with_options.assert_called_once() + + def test_list_memory_collections(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListMemoryCollectionsRequest) + api.list_memory_collections(input_data) + client.list_memory_collections_with_options.assert_called_once() + + +class TestMemoryCollectionControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_create_memory_collection_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateMemoryCollectionInput) + await api.create_memory_collection_async(input_data) + client.create_memory_collection_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_memory_collection_async(self, api_and_client): + api, client = api_and_client + await api.delete_memory_collection_async("test-collection") + client.delete_memory_collection_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_memory_collection_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateMemoryCollectionInput) + await api.update_memory_collection_async("test-collection", input_data) + client.update_memory_collection_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_memory_collection_async(self, api_and_client): + api, client = api_and_client + await api.get_memory_collection_async("test-collection") + client.get_memory_collection_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_memory_collections_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListMemoryCollectionsRequest) + await api.list_memory_collections_async(input_data) + client.list_memory_collections_with_options_async.assert_called_once() diff --git a/tests/unittests/model/api/test_control.py b/tests/unittests/model/api/test_control.py new file mode 100644 index 0000000..2dd6423 --- /dev/null +++ b/tests/unittests/model/api/test_control.py @@ -0,0 +1,181 @@ +""" +测试 ModelControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateModelProxyInput, + CreateModelServiceInput, + ListModelProxiesRequest, + ListModelServicesRequest, + UpdateModelProxyInput, + UpdateModelServiceInput, +) +import pytest + +from agentrun.model.api.control import ModelControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = ModelControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestModelServiceControlAPISignatures: + + def test_create_model_service(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateModelServiceInput) + api.create_model_service(input_data) + client.create_model_service_with_options.assert_called_once() + + def test_delete_model_service(self, api_and_client): + api, client = api_and_client + api.delete_model_service("test-service") + client.delete_model_service_with_options.assert_called_once() + + def test_update_model_service(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateModelServiceInput) + api.update_model_service("test-service", input_data) + client.update_model_service_with_options.assert_called_once() + + def test_get_model_service(self, api_and_client): + api, client = api_and_client + api.get_model_service("test-service") + client.get_model_service_with_options.assert_called_once() + + def test_list_model_services(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListModelServicesRequest) + api.list_model_services(input_data) + client.list_model_services_with_options.assert_called_once() + + +class TestModelProxyControlAPISignatures: + + def test_create_model_proxy(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateModelProxyInput) + api.create_model_proxy(input_data) + client.create_model_proxy_with_options.assert_called_once() + + def test_delete_model_proxy(self, api_and_client): + api, client = api_and_client + api.delete_model_proxy("test-proxy") + client.delete_model_proxy_with_options.assert_called_once() + + def test_update_model_proxy(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateModelProxyInput) + api.update_model_proxy("test-proxy", input_data) + client.update_model_proxy_with_options.assert_called_once() + + def test_get_model_proxy(self, api_and_client): + api, client = api_and_client + api.get_model_proxy("test-proxy") + client.get_model_proxy_with_options.assert_called_once() + + def test_list_model_proxies(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListModelProxiesRequest) + api.list_model_proxies(input_data) + client.list_model_proxies_with_options.assert_called_once() + + +class TestModelControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_create_model_service_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateModelServiceInput) + await api.create_model_service_async(input_data) + client.create_model_service_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_model_service_async(self, api_and_client): + api, client = api_and_client + await api.delete_model_service_async("test-service") + client.delete_model_service_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_model_service_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateModelServiceInput) + await api.update_model_service_async("test-service", input_data) + client.update_model_service_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_model_service_async(self, api_and_client): + api, client = api_and_client + await api.get_model_service_async("test-service") + client.get_model_service_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_model_services_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListModelServicesRequest) + await api.list_model_services_async(input_data) + client.list_model_services_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_create_model_proxy_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateModelProxyInput) + await api.create_model_proxy_async(input_data) + client.create_model_proxy_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_model_proxy_async(self, api_and_client): + api, client = api_and_client + await api.delete_model_proxy_async("test-proxy") + client.delete_model_proxy_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_model_proxy_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateModelProxyInput) + await api.update_model_proxy_async("test-proxy", input_data) + client.update_model_proxy_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_model_proxy_async(self, api_and_client): + api, client = api_and_client + await api.get_model_proxy_async("test-proxy") + client.get_model_proxy_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_model_proxies_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListModelProxiesRequest) + await api.list_model_proxies_async(input_data) + client.list_model_proxies_with_options_async.assert_called_once() diff --git a/tests/unittests/sandbox/api/test_control.py b/tests/unittests/sandbox/api/test_control.py new file mode 100644 index 0000000..7d1df7d --- /dev/null +++ b/tests/unittests/sandbox/api/test_control.py @@ -0,0 +1,172 @@ +""" +测试 SandboxControlAPI 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 + +使用 create_autospec(AgentRunClient) 来 mock _get_client 的返回值, +autospec 会强制校验方法签名,确保 SDK 方法签名变更时能及时检测出来。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +from alibabacloud_agentrun20250910.models import ( + CreateSandboxInput, + CreateTemplateInput, + ListSandboxesRequest, + ListTemplatesRequest, + UpdateTemplateInput, +) +import pytest + +from agentrun.sandbox.api.control import SandboxControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + """构造通用的 SDK 响应对象""" + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + """返回 (api, mock_client),mock_client 使用 create_autospec 强制校验方法签名""" + api = SandboxControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + # 为所有 _with_options 方法设置默认返回值 + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestSandboxControlAPISignatures: + """测试 SandboxControlAPI 同步方法调用是否匹配 SDK 签名""" + + def test_create_template(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateTemplateInput) + api.create_template(input_data) + client.create_template_with_options.assert_called_once() + + def test_delete_template(self, api_and_client): + api, client = api_and_client + api.delete_template("test-template") + client.delete_template_with_options.assert_called_once() + + def test_update_template(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateTemplateInput) + api.update_template("test-template", input_data) + client.update_template_with_options.assert_called_once() + + def test_get_template(self, api_and_client): + api, client = api_and_client + api.get_template("test-template") + client.get_template_with_options.assert_called_once() + + def test_list_templates(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListTemplatesRequest) + api.list_templates(input_data) + client.list_templates_with_options.assert_called_once() + + def test_create_sandbox(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateSandboxInput) + api.create_sandbox(input_data) + client.create_sandbox_with_options.assert_called_once() + + def test_stop_sandbox(self, api_and_client): + api, client = api_and_client + api.stop_sandbox("sandbox-123") + client.stop_sandbox_with_options.assert_called_once() + + def test_get_sandbox(self, api_and_client): + api, client = api_and_client + api.get_sandbox("sandbox-123") + client.get_sandbox_with_options.assert_called_once() + + def test_list_sandboxes(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListSandboxesRequest) + api.list_sandboxes(input_data) + client.list_sandboxes_with_options.assert_called_once() + + +class TestSandboxControlAPIAsyncSignatures: + """测试 SandboxControlAPI 异步方法调用是否匹配 SDK 签名""" + + @pytest.mark.asyncio + async def test_create_template_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateTemplateInput) + await api.create_template_async(input_data) + client.create_template_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_template_async(self, api_and_client): + api, client = api_and_client + await api.delete_template_async("test-template") + client.delete_template_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_update_template_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=UpdateTemplateInput) + await api.update_template_async("test-template", input_data) + client.update_template_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_template_async(self, api_and_client): + api, client = api_and_client + await api.get_template_async("test-template") + client.get_template_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_templates_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListTemplatesRequest) + await api.list_templates_async(input_data) + client.list_templates_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_create_sandbox_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=CreateSandboxInput) + await api.create_sandbox_async(input_data) + client.create_sandbox_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_stop_sandbox_async(self, api_and_client): + api, client = api_and_client + await api.stop_sandbox_async("sandbox-123") + client.stop_sandbox_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_get_sandbox_async(self, api_and_client): + api, client = api_and_client + await api.get_sandbox_async("sandbox-123") + client.get_sandbox_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_sandboxes_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListSandboxesRequest) + await api.list_sandboxes_async(input_data) + client.list_sandboxes_with_options_async.assert_called_once() diff --git a/tests/unittests/tool/api/__init__.py b/tests/unittests/tool/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unittests/tool/api/test_control.py b/tests/unittests/tool/api/test_control.py new file mode 100644 index 0000000..1b8c583 --- /dev/null +++ b/tests/unittests/tool/api/test_control.py @@ -0,0 +1,59 @@ +""" +测试 ToolControlAPI (tool) 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_agentrun20250910.client import Client as AgentRunClient +import pytest + +from agentrun.tool.api.control import ToolControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + control_endpoint="https://agentrun.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body.request_id = "test-request-id" + response.body.data = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = ToolControlAPI(config=mock_config) + mock_client = create_autospec(AgentRunClient, instance=True) + + for attr in dir(AgentRunClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_client", return_value=mock_client): + yield api, mock_client + + +class TestToolControlAPISignatures: + + def test_get_tool(self, api_and_client): + api, client = api_and_client + api.get_tool("test-tool") + client.get_tool_with_options.assert_called_once() + + +class TestToolControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_get_tool_async(self, api_and_client): + api, client = api_and_client + await api.get_tool_async("test-tool") + client.get_tool_with_options_async.assert_called_once() diff --git a/tests/unittests/toolset/api/test_control.py b/tests/unittests/toolset/api/test_control.py new file mode 100644 index 0000000..15e1fc8 --- /dev/null +++ b/tests/unittests/toolset/api/test_control.py @@ -0,0 +1,74 @@ +""" +测试 ToolControlAPI (toolset) 对底层 SDK client 的调用是否与 SDK 方法签名匹配。 + +注意:toolset 使用 DevsClient 而非 AgentRunClient。 +""" + +from unittest.mock import create_autospec, MagicMock, patch + +from alibabacloud_devs20230714.client import Client as DevsClient +from alibabacloud_devs20230714.models import ListToolsetsRequest +import pytest + +from agentrun.toolset.api.control import ToolControlAPI +from agentrun.utils.config import Config + + +@pytest.fixture +def mock_config(): + return Config( + access_key_id="test-ak", + access_key_secret="test-sk", + region_id="cn-hangzhou", + devs_endpoint="https://devs.cn-hangzhou.aliyuncs.com", + ) + + +@pytest.fixture +def mock_response(): + response = MagicMock() + response.body = MagicMock() + return response + + +@pytest.fixture +def api_and_client(mock_config, mock_response): + api = ToolControlAPI(config=mock_config) + mock_client = create_autospec(DevsClient, instance=True) + + for attr in dir(DevsClient): + if "with_options" in attr: + getattr(mock_client, attr).return_value = mock_response + + with patch.object(api, "_get_devs_client", return_value=mock_client): + yield api, mock_client + + +class TestToolsetControlAPISignatures: + + def test_get_toolset(self, api_and_client): + api, client = api_and_client + api.get_toolset("test-toolset") + client.get_toolset_with_options.assert_called_once() + + def test_list_toolsets(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListToolsetsRequest) + api.list_toolsets(input_data) + client.list_toolsets_with_options.assert_called_once() + + +class TestToolsetControlAPIAsyncSignatures: + + @pytest.mark.asyncio + async def test_get_toolset_async(self, api_and_client): + api, client = api_and_client + await api.get_toolset_async("test-toolset") + client.get_toolset_with_options_async.assert_called_once() + + @pytest.mark.asyncio + async def test_list_toolsets_async(self, api_and_client): + api, client = api_and_client + input_data = MagicMock(spec=ListToolsetsRequest) + await api.list_toolsets_async(input_data) + client.list_toolsets_with_options_async.assert_called_once()