Skip to content

Commit 1a51c89

Browse files
committed
test: add tests for Enhance agent_to_a2a with optional services
1 parent 88b50ea commit 1a51c89

File tree

1 file changed

+337
-0
lines changed

1 file changed

+337
-0
lines changed

tests/unittests/a2a/utils/test_agent_to_a2a.py

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@
3434
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
3535
from google.adk.a2a.utils.agent_to_a2a import to_a2a
3636
from google.adk.agents.base_agent import BaseAgent
37+
from google.adk.artifacts.base_artifact_service import BaseArtifactService
3738
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
39+
from google.adk.auth.credential_service.base_credential_service import BaseCredentialService
3840
from google.adk.auth.credential_service.in_memory_credential_service import InMemoryCredentialService
41+
from google.adk.memory.base_memory_service import BaseMemoryService
3942
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
4043
from google.adk.runners import Runner
44+
from google.adk.sessions.base_session_service import BaseSessionService
4145
from google.adk.sessions.in_memory_session_service import InMemorySessionService
4246
from starlette.applications import Starlette
4347
except ImportError as e:
@@ -869,3 +873,336 @@ def test_to_a2a_with_invalid_agent_card_file_path(
869873
# Act & Assert
870874
with pytest.raises(ValueError, match="Failed to load agent card from"):
871875
to_a2a(self.mock_agent, agent_card="/invalid/path.json")
876+
877+
@patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor")
878+
@patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler")
879+
@patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore")
880+
@patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder")
881+
@patch("google.adk.a2a.utils.agent_to_a2a.Starlette")
882+
@patch("google.adk.a2a.utils.agent_to_a2a.Runner")
883+
async def test_to_a2a_with_custom_services(
884+
self,
885+
mock_runner_class,
886+
mock_starlette_class,
887+
mock_card_builder_class,
888+
mock_task_store_class,
889+
mock_request_handler_class,
890+
mock_agent_executor_class,
891+
):
892+
"""Test to_a2a with custom service implementations."""
893+
# Arrange
894+
mock_app = Mock(spec=Starlette)
895+
mock_starlette_class.return_value = mock_app
896+
mock_task_store = Mock(spec=InMemoryTaskStore)
897+
mock_task_store_class.return_value = mock_task_store
898+
mock_agent_executor = Mock(spec=A2aAgentExecutor)
899+
mock_agent_executor_class.return_value = mock_agent_executor
900+
mock_request_handler = Mock(spec=DefaultRequestHandler)
901+
mock_request_handler_class.return_value = mock_request_handler
902+
mock_card_builder = Mock(spec=AgentCardBuilder)
903+
mock_card_builder_class.return_value = mock_card_builder
904+
mock_runner = Mock(spec=Runner)
905+
mock_runner_class.return_value = mock_runner
906+
907+
# Create custom service mocks
908+
custom_artifact_service = Mock(spec=BaseArtifactService)
909+
custom_session_service = Mock(spec=BaseSessionService)
910+
custom_memory_service = Mock(spec=BaseMemoryService)
911+
custom_credential_service = Mock(spec=BaseCredentialService)
912+
913+
# Act
914+
result = to_a2a(
915+
self.mock_agent,
916+
artifact_service=custom_artifact_service,
917+
session_service=custom_session_service,
918+
memory_service=custom_memory_service,
919+
credential_service=custom_credential_service,
920+
)
921+
922+
# Assert
923+
assert result == mock_app
924+
# Get the runner function that was passed to A2aAgentExecutor
925+
call_args = mock_agent_executor_class.call_args
926+
runner_func = call_args[1]["runner"]
927+
928+
# Call the runner function to verify it creates Runner with custom services
929+
await runner_func()
930+
931+
# Verify Runner was created with custom services
932+
mock_runner_class.assert_called_once_with(
933+
app_name="test_agent",
934+
agent=self.mock_agent,
935+
artifact_service=custom_artifact_service,
936+
session_service=custom_session_service,
937+
memory_service=custom_memory_service,
938+
credential_service=custom_credential_service,
939+
)
940+
941+
@patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor")
942+
@patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler")
943+
@patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore")
944+
@patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder")
945+
@patch("google.adk.a2a.utils.agent_to_a2a.Starlette")
946+
@patch("google.adk.a2a.utils.agent_to_a2a.Runner")
947+
async def test_to_a2a_with_none_services_uses_defaults(
948+
self,
949+
mock_runner_class,
950+
mock_starlette_class,
951+
mock_card_builder_class,
952+
mock_task_store_class,
953+
mock_request_handler_class,
954+
mock_agent_executor_class,
955+
):
956+
"""Test to_a2a with None services uses default in-memory services."""
957+
# Arrange
958+
mock_app = Mock(spec=Starlette)
959+
mock_starlette_class.return_value = mock_app
960+
mock_task_store = Mock(spec=InMemoryTaskStore)
961+
mock_task_store_class.return_value = mock_task_store
962+
mock_agent_executor = Mock(spec=A2aAgentExecutor)
963+
mock_agent_executor_class.return_value = mock_agent_executor
964+
mock_request_handler = Mock(spec=DefaultRequestHandler)
965+
mock_request_handler_class.return_value = mock_request_handler
966+
mock_card_builder = Mock(spec=AgentCardBuilder)
967+
mock_card_builder_class.return_value = mock_card_builder
968+
mock_runner = Mock(spec=Runner)
969+
mock_runner_class.return_value = mock_runner
970+
971+
# Act
972+
result = to_a2a(
973+
self.mock_agent,
974+
artifact_service=None,
975+
session_service=None,
976+
memory_service=None,
977+
credential_service=None,
978+
)
979+
980+
# Assert
981+
assert result == mock_app
982+
# Get the runner function that was passed to A2aAgentExecutor
983+
call_args = mock_agent_executor_class.call_args
984+
runner_func = call_args[1]["runner"]
985+
986+
# Call the runner function to verify it creates Runner with default services
987+
await runner_func()
988+
989+
# Verify Runner was created with default services
990+
mock_runner_class.assert_called_once()
991+
call_args = mock_runner_class.call_args[1]
992+
assert call_args["app_name"] == "test_agent"
993+
assert call_args["agent"] == self.mock_agent
994+
# Verify the services are of the correct default types
995+
assert isinstance(call_args["artifact_service"], InMemoryArtifactService)
996+
assert isinstance(call_args["session_service"], InMemorySessionService)
997+
assert isinstance(call_args["memory_service"], InMemoryMemoryService)
998+
assert isinstance(call_args["credential_service"], InMemoryCredentialService)
999+
1000+
@patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor")
1001+
@patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler")
1002+
@patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore")
1003+
@patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder")
1004+
@patch("google.adk.a2a.utils.agent_to_a2a.Starlette")
1005+
@patch("google.adk.a2a.utils.agent_to_a2a.Runner")
1006+
async def test_to_a2a_with_mixed_services(
1007+
self,
1008+
mock_runner_class,
1009+
mock_starlette_class,
1010+
mock_card_builder_class,
1011+
mock_task_store_class,
1012+
mock_request_handler_class,
1013+
mock_agent_executor_class,
1014+
):
1015+
"""Test to_a2a with mix of custom and default services."""
1016+
# Arrange
1017+
mock_app = Mock(spec=Starlette)
1018+
mock_starlette_class.return_value = mock_app
1019+
mock_task_store = Mock(spec=InMemoryTaskStore)
1020+
mock_task_store_class.return_value = mock_task_store
1021+
mock_agent_executor = Mock(spec=A2aAgentExecutor)
1022+
mock_agent_executor_class.return_value = mock_agent_executor
1023+
mock_request_handler = Mock(spec=DefaultRequestHandler)
1024+
mock_request_handler_class.return_value = mock_request_handler
1025+
mock_card_builder = Mock(spec=AgentCardBuilder)
1026+
mock_card_builder_class.return_value = mock_card_builder
1027+
mock_runner = Mock(spec=Runner)
1028+
mock_runner_class.return_value = mock_runner
1029+
1030+
# Create custom service mocks for some services
1031+
custom_artifact_service = Mock(spec=BaseArtifactService)
1032+
custom_memory_service = Mock(spec=BaseMemoryService)
1033+
1034+
# Act - only provide custom services for artifact and memory
1035+
result = to_a2a(
1036+
self.mock_agent,
1037+
artifact_service=custom_artifact_service,
1038+
memory_service=custom_memory_service,
1039+
)
1040+
1041+
# Assert
1042+
assert result == mock_app
1043+
# Get the runner function that was passed to A2aAgentExecutor
1044+
call_args = mock_agent_executor_class.call_args
1045+
runner_func = call_args[1]["runner"]
1046+
1047+
# Call the runner function to verify it creates Runner with mixed services
1048+
await runner_func()
1049+
1050+
# Verify Runner was created with mixed services
1051+
mock_runner_class.assert_called_once()
1052+
call_args = mock_runner_class.call_args[1]
1053+
assert call_args["app_name"] == "test_agent"
1054+
assert call_args["agent"] == self.mock_agent
1055+
# Verify custom services are used
1056+
assert call_args["artifact_service"] == custom_artifact_service
1057+
assert call_args["memory_service"] == custom_memory_service
1058+
# Verify default services are used for the others
1059+
assert isinstance(call_args["session_service"], InMemorySessionService)
1060+
assert isinstance(call_args["credential_service"], InMemoryCredentialService)
1061+
1062+
@patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor")
1063+
@patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler")
1064+
@patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore")
1065+
@patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder")
1066+
@patch("google.adk.a2a.utils.agent_to_a2a.Starlette")
1067+
@patch("google.adk.a2a.utils.agent_to_a2a.Runner")
1068+
async def test_to_a2a_services_parameter_order_independence(
1069+
self,
1070+
mock_runner_class,
1071+
mock_starlette_class,
1072+
mock_card_builder_class,
1073+
mock_task_store_class,
1074+
mock_request_handler_class,
1075+
mock_agent_executor_class,
1076+
):
1077+
"""Test that services can be provided in any order and still work correctly."""
1078+
# Arrange
1079+
mock_app = Mock(spec=Starlette)
1080+
mock_starlette_class.return_value = mock_app
1081+
mock_task_store = Mock(spec=InMemoryTaskStore)
1082+
mock_task_store_class.return_value = mock_task_store
1083+
mock_agent_executor = Mock(spec=A2aAgentExecutor)
1084+
mock_agent_executor_class.return_value = mock_agent_executor
1085+
mock_request_handler = Mock(spec=DefaultRequestHandler)
1086+
mock_request_handler_class.return_value = mock_request_handler
1087+
mock_card_builder = Mock(spec=AgentCardBuilder)
1088+
mock_card_builder_class.return_value = mock_card_builder
1089+
mock_runner = Mock(spec=Runner)
1090+
mock_runner_class.return_value = mock_runner
1091+
1092+
# Create custom service mocks
1093+
custom_artifact_service = Mock(spec=BaseArtifactService)
1094+
custom_session_service = Mock(spec=BaseSessionService)
1095+
custom_memory_service = Mock(spec=BaseMemoryService)
1096+
custom_credential_service = Mock(spec=BaseCredentialService)
1097+
1098+
# Act - provide services in different order
1099+
result = to_a2a(
1100+
self.mock_agent,
1101+
credential_service=custom_credential_service,
1102+
artifact_service=custom_artifact_service,
1103+
session_service=custom_session_service,
1104+
memory_service=custom_memory_service,
1105+
)
1106+
1107+
# Assert
1108+
assert result == mock_app
1109+
# Get the runner function that was passed to A2aAgentExecutor
1110+
call_args = mock_agent_executor_class.call_args
1111+
runner_func = call_args[1]["runner"]
1112+
1113+
# Call the runner function to verify it creates Runner with correct services
1114+
await runner_func()
1115+
1116+
# Verify Runner was created with all custom services regardless of order
1117+
mock_runner_class.assert_called_once()
1118+
call_args = mock_runner_class.call_args[1]
1119+
assert call_args["artifact_service"] == custom_artifact_service
1120+
assert call_args["session_service"] == custom_session_service
1121+
assert call_args["memory_service"] == custom_memory_service
1122+
assert call_args["credential_service"] == custom_credential_service
1123+
1124+
@patch("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor")
1125+
@patch("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler")
1126+
@patch("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore")
1127+
@patch("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder")
1128+
@patch("google.adk.a2a.utils.agent_to_a2a.Starlette")
1129+
@patch("google.adk.a2a.utils.agent_to_a2a.Runner")
1130+
async def test_to_a2a_with_agent_without_name_and_custom_services(
1131+
self,
1132+
mock_runner_class,
1133+
mock_starlette_class,
1134+
mock_card_builder_class,
1135+
mock_task_store_class,
1136+
mock_request_handler_class,
1137+
mock_agent_executor_class,
1138+
):
1139+
"""Test to_a2a with agent that has no name and custom services."""
1140+
# Arrange
1141+
self.mock_agent.name = None
1142+
mock_app = Mock(spec=Starlette)
1143+
mock_starlette_class.return_value = mock_app
1144+
mock_task_store = Mock(spec=InMemoryTaskStore)
1145+
mock_task_store_class.return_value = mock_task_store
1146+
mock_agent_executor = Mock(spec=A2aAgentExecutor)
1147+
mock_agent_executor_class.return_value = mock_agent_executor
1148+
mock_request_handler = Mock(spec=DefaultRequestHandler)
1149+
mock_request_handler_class.return_value = mock_request_handler
1150+
mock_card_builder = Mock(spec=AgentCardBuilder)
1151+
mock_card_builder_class.return_value = mock_card_builder
1152+
mock_runner = Mock(spec=Runner)
1153+
mock_runner_class.return_value = mock_runner
1154+
1155+
# Create custom service mocks
1156+
custom_artifact_service = Mock(spec=BaseArtifactService)
1157+
custom_session_service = Mock(spec=BaseSessionService)
1158+
1159+
# Act
1160+
result = to_a2a(
1161+
self.mock_agent,
1162+
artifact_service=custom_artifact_service,
1163+
session_service=custom_session_service,
1164+
)
1165+
1166+
# Assert
1167+
assert result == mock_app
1168+
# Get the runner function that was passed to A2aAgentExecutor
1169+
call_args = mock_agent_executor_class.call_args
1170+
runner_func = call_args[1]["runner"]
1171+
1172+
# Call the runner function to verify it creates Runner correctly
1173+
await runner_func()
1174+
1175+
# Verify Runner was created with default app_name and custom services
1176+
mock_runner_class.assert_called_once()
1177+
call_args = mock_runner_class.call_args[1]
1178+
assert call_args["app_name"] == "adk_agent" # Default name when agent has no name
1179+
assert call_args["agent"] == self.mock_agent
1180+
assert call_args["artifact_service"] == custom_artifact_service
1181+
assert call_args["session_service"] == custom_session_service
1182+
# Verify default services are used for the others
1183+
assert isinstance(call_args["memory_service"], InMemoryMemoryService)
1184+
assert isinstance(call_args["credential_service"], InMemoryCredentialService)
1185+
1186+
def test_to_a2a_service_parameter_validation(self):
1187+
"""Test that to_a2a accepts valid service types without raising errors."""
1188+
# Arrange
1189+
custom_artifact_service = Mock(spec=BaseArtifactService)
1190+
custom_session_service = Mock(spec=BaseSessionService)
1191+
custom_memory_service = Mock(spec=BaseMemoryService)
1192+
custom_credential_service = Mock(spec=BaseCredentialService)
1193+
1194+
# Act & Assert - should not raise any errors
1195+
with patch("google.adk.a2a.utils.agent_to_a2a.Starlette") as mock_starlette:
1196+
mock_app = Mock(spec=Starlette)
1197+
mock_starlette.return_value = mock_app
1198+
1199+
# This should not raise any validation errors
1200+
result = to_a2a(
1201+
self.mock_agent,
1202+
artifact_service=custom_artifact_service,
1203+
session_service=custom_session_service,
1204+
memory_service=custom_memory_service,
1205+
credential_service=custom_credential_service,
1206+
)
1207+
1208+
assert result == mock_app

0 commit comments

Comments
 (0)