@@ -689,3 +689,183 @@ def test_to_a2a_with_ip_address_host(
689689 mock_card_builder_class .assert_called_once_with (
690690 agent = self .mock_agent , rpc_url = "http://192.168.1.1:8000/"
691691 )
692+
693+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
694+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
695+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
696+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
697+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
698+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication" )
699+ async def test_to_a2a_with_custom_agent_card_object (
700+ self ,
701+ mock_a2a_app_class ,
702+ mock_starlette_class ,
703+ mock_card_builder_class ,
704+ mock_task_store_class ,
705+ mock_request_handler_class ,
706+ mock_agent_executor_class ,
707+ ):
708+ """Test to_a2a with custom AgentCard object."""
709+ # Arrange
710+ mock_app = Mock (spec = Starlette )
711+ mock_starlette_class .return_value = mock_app
712+ mock_task_store = Mock (spec = InMemoryTaskStore )
713+ mock_task_store_class .return_value = mock_task_store
714+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
715+ mock_agent_executor_class .return_value = mock_agent_executor
716+ mock_request_handler = Mock (spec = DefaultRequestHandler )
717+ mock_request_handler_class .return_value = mock_request_handler
718+ mock_card_builder = Mock (spec = AgentCardBuilder )
719+ mock_card_builder_class .return_value = mock_card_builder
720+ mock_a2a_app = Mock (spec = A2AStarletteApplication )
721+ mock_a2a_app_class .return_value = mock_a2a_app
722+
723+ # Create a custom agent card
724+ custom_agent_card = Mock (spec = AgentCard )
725+ custom_agent_card .name = "custom_agent"
726+
727+ # Act
728+ result = to_a2a (self .mock_agent , agent_card = custom_agent_card )
729+
730+ # Assert
731+ assert result == mock_app
732+ # Get the setup_a2a function that was added as startup handler
733+ startup_handler = mock_app .add_event_handler .call_args [0 ][1 ]
734+
735+ # Call the setup_a2a function
736+ await startup_handler ()
737+
738+ # Verify the card builder build method was NOT called since we provided a card
739+ mock_card_builder .build .assert_not_called ()
740+
741+ # Verify A2A Starlette application was created with custom card
742+ mock_a2a_app_class .assert_called_once_with (
743+ agent_card = custom_agent_card ,
744+ http_handler = mock_request_handler ,
745+ )
746+
747+ # Verify routes were added to the main app
748+ mock_a2a_app .add_routes_to_app .assert_called_once_with (mock_app )
749+
750+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
751+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
752+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
753+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
754+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
755+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2AStarletteApplication" )
756+ @patch ("json.load" )
757+ @patch ("pathlib.Path.open" )
758+ @patch ("pathlib.Path" )
759+ async def test_to_a2a_with_agent_card_file_path (
760+ self ,
761+ mock_path_class ,
762+ mock_open ,
763+ mock_json_load ,
764+ mock_a2a_app_class ,
765+ mock_starlette_class ,
766+ mock_card_builder_class ,
767+ mock_task_store_class ,
768+ mock_request_handler_class ,
769+ mock_agent_executor_class ,
770+ ):
771+ """Test to_a2a with agent card file path."""
772+ # Arrange
773+ mock_app = Mock (spec = Starlette )
774+ mock_starlette_class .return_value = mock_app
775+ mock_task_store = Mock (spec = InMemoryTaskStore )
776+ mock_task_store_class .return_value = mock_task_store
777+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
778+ mock_agent_executor_class .return_value = mock_agent_executor
779+ mock_request_handler = Mock (spec = DefaultRequestHandler )
780+ mock_request_handler_class .return_value = mock_request_handler
781+ mock_card_builder = Mock (spec = AgentCardBuilder )
782+ mock_card_builder_class .return_value = mock_card_builder
783+ mock_a2a_app = Mock (spec = A2AStarletteApplication )
784+ mock_a2a_app_class .return_value = mock_a2a_app
785+
786+ # Mock file operations
787+ mock_path = Mock ()
788+ mock_path_class .return_value = mock_path
789+ mock_file_handle = Mock ()
790+ # Create a proper context manager mock
791+ mock_context_manager = Mock ()
792+ mock_context_manager .__enter__ = Mock (return_value = mock_file_handle )
793+ mock_context_manager .__exit__ = Mock (return_value = None )
794+ mock_path .open = Mock (return_value = mock_context_manager )
795+
796+ # Mock agent card data from file with all required fields
797+ agent_card_data = {
798+ "name" : "file_agent" ,
799+ "url" : "http://example.com" ,
800+ "description" : "Test agent from file" ,
801+ "version" : "1.0.0" ,
802+ "capabilities" : {},
803+ "skills" : [],
804+ "defaultInputModes" : ["text/plain" ],
805+ "defaultOutputModes" : ["text/plain" ],
806+ "supportsAuthenticatedExtendedCard" : False ,
807+ }
808+ mock_json_load .return_value = agent_card_data
809+
810+ # Act
811+ result = to_a2a (self .mock_agent , agent_card = "/path/to/agent_card.json" )
812+
813+ # Assert
814+ assert result == mock_app
815+ # Get the setup_a2a function that was added as startup handler
816+ startup_handler = mock_app .add_event_handler .call_args [0 ][1 ]
817+
818+ # Call the setup_a2a function
819+ await startup_handler ()
820+
821+ # Verify file was opened and JSON was loaded
822+ mock_path_class .assert_called_once_with ("/path/to/agent_card.json" )
823+ mock_path .open .assert_called_once_with ("r" , encoding = "utf-8" )
824+ mock_json_load .assert_called_once_with (mock_file_handle )
825+
826+ # Verify the card builder build method was NOT called since we provided a card
827+ mock_card_builder .build .assert_not_called ()
828+
829+ # Verify A2A Starlette application was created with loaded card
830+ mock_a2a_app_class .assert_called_once ()
831+ args , kwargs = mock_a2a_app_class .call_args
832+ assert kwargs ["http_handler" ] == mock_request_handler
833+ # The agent_card should be an AgentCard object created from loaded data
834+ assert hasattr (kwargs ["agent_card" ], "name" )
835+
836+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
837+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
838+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
839+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
840+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
841+ @patch ("pathlib.Path.open" , side_effect = FileNotFoundError ("File not found" ))
842+ @patch ("pathlib.Path" )
843+ def test_to_a2a_with_invalid_agent_card_file_path (
844+ self ,
845+ mock_path_class ,
846+ mock_open ,
847+ mock_starlette_class ,
848+ mock_card_builder_class ,
849+ mock_task_store_class ,
850+ mock_request_handler_class ,
851+ mock_agent_executor_class ,
852+ ):
853+ """Test to_a2a with invalid agent card file path."""
854+ # Arrange
855+ mock_app = Mock (spec = Starlette )
856+ mock_starlette_class .return_value = mock_app
857+ mock_task_store = Mock (spec = InMemoryTaskStore )
858+ mock_task_store_class .return_value = mock_task_store
859+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
860+ mock_agent_executor_class .return_value = mock_agent_executor
861+ mock_request_handler = Mock (spec = DefaultRequestHandler )
862+ mock_request_handler_class .return_value = mock_request_handler
863+ mock_card_builder = Mock (spec = AgentCardBuilder )
864+ mock_card_builder_class .return_value = mock_card_builder
865+
866+ mock_path = Mock ()
867+ mock_path_class .return_value = mock_path
868+
869+ # Act & Assert
870+ with pytest .raises (ValueError , match = "Failed to load agent card from" ):
871+ to_a2a (self .mock_agent , agent_card = "/invalid/path.json" )
0 commit comments