# Copyright 2026 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from unittest.mock import AsyncMock from unittest.mock import Mock from unittest.mock import patch from a2a.server.apps import A2AStarletteApplication from a2a.server.request_handlers import DefaultRequestHandler from a2a.server.tasks import InMemoryTaskStore from a2a.types import AgentCard from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder from google.adk.a2a.utils.agent_to_a2a import to_a2a from google.adk.agents.base_agent import BaseAgent from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService from google.adk.auth.credential_service.in_memory_credential_service import InMemoryCredentialService from google.adk.memory.in_memory_memory_service import InMemoryMemoryService from google.adk.runners import Runner from google.adk.sessions.in_memory_session_service import InMemorySessionService import pytest from starlette.applications import Starlette class TestToA2A: """Test suite for to_a2a function.""" def setup_method(self): """Set up test fixtures.""" self.mock_agent = Mock(spec=BaseAgent) self.mock_agent.name = "test_agent" self.mock_agent.description = "Test agent description" @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_default_parameters( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with default parameters.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app mock_starlette_class.assert_called_once() mock_task_store_class.assert_called_once() mock_agent_executor_class.assert_called_once() mock_request_handler_class.assert_called_once_with( agent_executor=mock_agent_executor, task_store=mock_task_store ) mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://localhost:8000/" ) mock_app.add_event_handler.assert_called_once_with( "startup", mock_app.add_event_handler.call_args[0][1] ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_custom_runner( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with a custom runner.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder custom_runner = Mock(spec=Runner) # Act result = to_a2a(self.mock_agent, runner=custom_runner) # Assert assert result == mock_app mock_starlette_class.assert_called_once() mock_task_store_class.assert_called_once() mock_agent_executor_class.assert_called_once_with(runner=custom_runner) mock_request_handler_class.assert_called_once_with( agent_executor=mock_agent_executor, task_store=mock_task_store ) mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://localhost:8000/" ) mock_app.add_event_handler.assert_called_once_with( "startup", mock_app.add_event_handler.call_args[0][1] ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_custom_host_port( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with custom host and port.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, host="example.com", port=9000) # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://example.com:9000/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_agent_without_name( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with agent that has no name.""" # Arrange self.mock_agent.name = None mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # The create_runner function should use "adk_agent" as default name # We can't directly test the create_runner function, but we can verify # the agent executor was created with the runner function @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_creates_runner_with_correct_services( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test that the create_runner function creates Runner with correct services.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # Verify that the agent executor was created with a runner function mock_agent_executor_class.assert_called_once() call_args = mock_agent_executor_class.call_args assert "runner" in call_args[1] runner_func = call_args[1]["runner"] assert callable(runner_func) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.Runner") async def test_create_runner_function_creates_runner_correctly( self, mock_runner_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test that the create_runner function creates Runner with correct parameters.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_runner = Mock(spec=Runner) mock_runner_class.return_value = mock_runner # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # Get the runner function that was passed to A2aAgentExecutor call_args = mock_agent_executor_class.call_args runner_func = call_args[1]["runner"] # Call the runner function to verify it creates Runner correctly runner_result = await runner_func() # Verify Runner was created with correct parameters mock_runner_class.assert_called_once_with( app_name="test_agent", agent=self.mock_agent, artifact_service=mock_runner_class.call_args[1]["artifact_service"], session_service=mock_runner_class.call_args[1]["session_service"], memory_service=mock_runner_class.call_args[1]["memory_service"], credential_service=mock_runner_class.call_args[1]["credential_service"], ) # Verify the services are of the correct types call_args = mock_runner_class.call_args[1] assert isinstance(call_args["artifact_service"], InMemoryArtifactService) assert isinstance(call_args["session_service"], InMemorySessionService) assert isinstance(call_args["memory_service"], InMemoryMemoryService) assert isinstance( call_args["credential_service"], InMemoryCredentialService ) assert runner_result == mock_runner @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.Runner") async def test_create_runner_function_with_agent_without_name( self, mock_runner_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test create_runner function with agent that has no name.""" # Arrange self.mock_agent.name = None mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_runner = Mock(spec=Runner) mock_runner_class.return_value = mock_runner # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # Get the runner function that was passed to A2aAgentExecutor call_args = mock_agent_executor_class.call_args runner_func = call_args[1]["runner"] # Call the runner function to verify it creates Runner correctly await runner_func() # Verify Runner was created with default app_name when agent has no name mock_runner_class.assert_called_once_with( app_name="adk_agent", agent=self.mock_agent, artifact_service=mock_runner_class.call_args[1]["artifact_service"], session_service=mock_runner_class.call_args[1]["session_service"], memory_service=mock_runner_class.call_args[1]["memory_service"], credential_service=mock_runner_class.call_args[1]["credential_service"], ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication") async def test_setup_a2a_function_builds_agent_card_and_configures_routes( self, mock_a2a_app_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test that the setup_a2a function builds agent card and configures A2A routes.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_agent_card = Mock(spec=AgentCard) mock_card_builder.build = AsyncMock(return_value=mock_agent_card) mock_a2a_app = Mock(spec=A2AStarletteApplication) mock_a2a_app_class.return_value = mock_a2a_app # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # Get the setup_a2a function that was added as startup handler startup_handler = mock_app.add_event_handler.call_args[0][1] # Call the setup_a2a function await startup_handler() # Verify agent card was built mock_card_builder.build.assert_called_once() # Verify A2A Starlette application was created mock_a2a_app_class.assert_called_once_with( agent_card=mock_agent_card, http_handler=mock_request_handler, ) # Verify routes were added to the main app mock_a2a_app.add_routes_to_app.assert_called_once_with(mock_app) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication") async def test_setup_a2a_function_handles_agent_card_build_failure( self, mock_a2a_app_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test that setup_a2a function properly handles agent card build failure.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_card_builder.build = AsyncMock(side_effect=Exception("Build failed")) mock_a2a_app = Mock(spec=A2AStarletteApplication) mock_a2a_app_class.return_value = mock_a2a_app # Act result = to_a2a(self.mock_agent) # Assert assert result == mock_app # Get the setup_a2a function that was added as startup handler startup_handler = mock_app.add_event_handler.call_args[0][1] # Call the setup_a2a function and expect it to raise the exception with pytest.raises(Exception, match="Build failed"): await startup_handler() @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_returns_starlette_app( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test that to_a2a returns a Starlette application.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent) # Assert assert isinstance(result, Mock) # Mock of Starlette assert result == mock_app def test_to_a2a_with_none_agent(self): """Test that to_a2a raises error when agent is None.""" # Act & Assert with pytest.raises(ValueError, match="Agent cannot be None or empty."): to_a2a(None) def test_to_a2a_with_invalid_agent_type(self): """Test that to_a2a raises error when agent is not a BaseAgent.""" # Arrange invalid_agent = "not an agent" # Act & Assert # The error occurs during startup when building the agent card app = to_a2a(invalid_agent) with pytest.raises( AttributeError, match="'str' object has no attribute 'name'" ): import asyncio asyncio.run(app.router.on_startup[0]()) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_custom_port_zero( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with port 0 (dynamic port assignment).""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, port=0) # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://localhost:0/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_empty_string_host( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with empty string host.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, host="") # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://:8000/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_negative_port( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with negative port number.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, port=-1) # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://localhost:-1/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_very_large_port( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with very large port number.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, port=65535) # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://localhost:65535/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_special_characters_in_host( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with special characters in host name.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, host="test-host.example.com") # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://test-host.example.com:8000/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") def test_to_a2a_with_ip_address_host( self, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with IP address as host.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder # Act result = to_a2a(self.mock_agent, host="192.168.1.1") # Assert assert result == mock_app mock_card_builder_class.assert_called_once_with( agent=self.mock_agent, rpc_url="http://192.168.1.1:8000/" ) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication") async def test_to_a2a_with_custom_agent_card_object( self, mock_a2a_app_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with custom AgentCard object.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_a2a_app = Mock(spec=A2AStarletteApplication) mock_a2a_app_class.return_value = mock_a2a_app # Create a custom agent card custom_agent_card = Mock(spec=AgentCard) custom_agent_card.name = "custom_agent" # Act result = to_a2a(self.mock_agent, agent_card=custom_agent_card) # Assert assert result == mock_app # Get the setup_a2a function that was added as startup handler startup_handler = mock_app.add_event_handler.call_args[0][1] # Call the setup_a2a function await startup_handler() # Verify the card builder build method was NOT called since we provided a card mock_card_builder.build.assert_not_called() # Verify A2A Starlette application was created with custom card mock_a2a_app_class.assert_called_once_with( agent_card=custom_agent_card, http_handler=mock_request_handler, ) # Verify routes were added to the main app mock_a2a_app.add_routes_to_app.assert_called_once_with(mock_app) @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication") @patch("json.load") @patch("pathlib.Path.open") @patch("pathlib.Path") async def test_to_a2a_with_agent_card_file_path( self, mock_path_class, mock_open, mock_json_load, mock_a2a_app_class, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with agent card file path.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_a2a_app = Mock(spec=A2AStarletteApplication) mock_a2a_app_class.return_value = mock_a2a_app # Mock file operations mock_path = Mock() mock_path_class.return_value = mock_path mock_file_handle = Mock() # Create a proper context manager mock mock_context_manager = Mock() mock_context_manager.__enter__ = Mock(return_value=mock_file_handle) mock_context_manager.__exit__ = Mock(return_value=None) mock_path.open = Mock(return_value=mock_context_manager) # Mock agent card data from file with all required fields agent_card_data = { "name": "file_agent", "url": "http://example.com", "description": "Test agent from file", "version": "1.0.0", "capabilities": {}, "skills": [], "defaultInputModes": ["text/plain"], "defaultOutputModes": ["text/plain"], "supportsAuthenticatedExtendedCard": False, } mock_json_load.return_value = agent_card_data # Act result = to_a2a(self.mock_agent, agent_card="/path/to/agent_card.json") # Assert assert result == mock_app # Get the setup_a2a function that was added as startup handler startup_handler = mock_app.add_event_handler.call_args[0][1] # Call the setup_a2a function await startup_handler() # Verify file was opened and JSON was loaded mock_path_class.assert_called_once_with("/path/to/agent_card.json") mock_path.open.assert_called_once_with("r", encoding="utf-8") mock_json_load.assert_called_once_with(mock_file_handle) # Verify the card builder build method was NOT called since we provided a card mock_card_builder.build.assert_not_called() # Verify A2A Starlette application was created with loaded card mock_a2a_app_class.assert_called_once() args, kwargs = mock_a2a_app_class.call_args assert kwargs["http_handler"] == mock_request_handler # The agent_card should be an AgentCard object created from loaded data assert hasattr(kwargs["agent_card"], "name") @patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor") @patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler") @patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore") @patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder") @patch("google.adk.a2a.utils.agent_to_a2a.Starlette") @patch("pathlib.Path.open", side_effect=FileNotFoundError("File not found")) @patch("pathlib.Path") def test_to_a2a_with_invalid_agent_card_file_path( self, mock_path_class, mock_open, mock_starlette_class, mock_card_builder_class, mock_task_store_class, mock_request_handler_class, mock_agent_executor_class, ): """Test to_a2a with invalid agent card file path.""" # Arrange mock_app = Mock(spec=Starlette) mock_starlette_class.return_value = mock_app mock_task_store = Mock(spec=InMemoryTaskStore) mock_task_store_class.return_value = mock_task_store mock_agent_executor = Mock(spec=A2aAgentExecutor) mock_agent_executor_class.return_value = mock_agent_executor mock_request_handler = Mock(spec=DefaultRequestHandler) mock_request_handler_class.return_value = mock_request_handler mock_card_builder = Mock(spec=AgentCardBuilder) mock_card_builder_class.return_value = mock_card_builder mock_path = Mock() mock_path_class.return_value = mock_path # Act & Assert with pytest.raises(ValueError, match="Failed to load agent card from"): to_a2a(self.mock_agent, agent_card="/invalid/path.json")