99from starlette .routing import Route
1010from starlette .testclient import TestClient
1111
12- from a2a .server .apps .starlette_app import A2AStarletteApplication
12+ from a2a .server .apps .jsonrpc import (
13+ A2AStarletteApplication ,
14+ A2AFastAPIApplication ,
15+ )
1316from a2a .types import (
1417 AgentCapabilities ,
1518 AgentCard ,
@@ -116,13 +119,23 @@ def handler():
116119
117120
118121@pytest .fixture
119- def app (agent_card : AgentCard , handler : mock .AsyncMock ):
122+ def starlette_app (agent_card : AgentCard , handler : mock .AsyncMock ):
120123 return A2AStarletteApplication (agent_card , handler )
121124
122125
123126@pytest .fixture
124- def client (app : A2AStarletteApplication ):
125- """Create a test client with the app."""
127+ def starlette_client (app : A2AStarletteApplication ):
128+ """Create a test client with the Starlette app."""
129+ return TestClient (app .build ())
130+
131+ @pytest .fixture
132+ def fastapi_app (agent_card : AgentCard , handler : mock .AsyncMock ):
133+ return A2AFastAPIApplication (agent_card , handler )
134+
135+
136+ @pytest .fixture
137+ def fastapi_client (app : A2AFastAPIApplication ):
138+ """Create a test client with the FastAPI app."""
126139 return TestClient (app .build ())
127140
128141
@@ -139,7 +152,7 @@ def test_agent_card_endpoint(client: TestClient, agent_card: AgentCard):
139152 assert 'streaming' in data ['capabilities' ]
140153
141154
142- def test_authenticated_extended_agent_card_endpoint_not_supported (
155+ def test_authenticated_extended_agent_card_endpoint_not_supported_starlette (
143156 agent_card : AgentCard , handler : mock .AsyncMock
144157):
145158 """Test extended card endpoint returns 404 if not supported by main card."""
@@ -152,8 +165,21 @@ def test_authenticated_extended_agent_card_endpoint_not_supported(
152165 response = client .get ('/agent/authenticatedExtendedCard' )
153166 assert response .status_code == 404 # Starlette's default for no route
154167
168+ def test_authenticated_extended_agent_card_endpoint_not_supported_fastapi (
169+ agent_card : AgentCard , handler : mock .AsyncMock
170+ ):
171+ """Test extended card endpoint returns 404 if not supported by main card."""
172+ # Ensure supportsAuthenticatedExtendedCard is False or None
173+ agent_card .supportsAuthenticatedExtendedCard = False
174+ app_instance = A2AFastAPIApplication (agent_card , handler )
175+ # The route should not even be added if supportsAuthenticatedExtendedCard is false
176+ # So, building the app and trying to hit it should result in 404 from FastAPI itself
177+ client = TestClient (app_instance .build ())
178+ response = client .get ('/agent/authenticatedExtendedCard' )
179+ assert response .status_code == 404 # FastAPI's default for no route
180+
155181
156- def test_authenticated_extended_agent_card_endpoint_supported_with_specific_extended_card (
182+ def test_authenticated_extended_agent_card_endpoint_supported_with_specific_extended_card_starlette (
157183 agent_card : AgentCard ,
158184 extended_agent_card_fixture : AgentCard ,
159185 handler : mock .AsyncMock ,
@@ -178,6 +204,30 @@ def test_authenticated_extended_agent_card_endpoint_supported_with_specific_exte
178204 'Extended skill not found in served card'
179205 )
180206
207+ def test_authenticated_extended_agent_card_endpoint_supported_with_specific_extended_card_fastapi (
208+ agent_card : AgentCard ,
209+ extended_agent_card_fixture : AgentCard ,
210+ handler : mock .AsyncMock ,
211+ ):
212+ """Test extended card endpoint returns the specific extended card when provided."""
213+ agent_card .supportsAuthenticatedExtendedCard = (
214+ True # Main card must support it
215+ )
216+ app_instance = A2AFastAPIApplication (
217+ agent_card , handler , extended_agent_card = extended_agent_card_fixture
218+ )
219+ client = TestClient (app_instance .build ())
220+
221+ response = client .get ('/agent/authenticatedExtendedCard' )
222+ assert response .status_code == 200
223+ data = response .json ()
224+ # Verify it's the extended card's data
225+ assert data ['name' ] == extended_agent_card_fixture .name
226+ assert data ['version' ] == extended_agent_card_fixture .version
227+ assert len (data ['skills' ]) == len (extended_agent_card_fixture .skills )
228+ assert any (skill ['id' ] == 'skill-extended' for skill in data ['skills' ]), (
229+ 'Extended skill not found in served card'
230+ )
181231
182232def test_agent_card_custom_url (
183233 app : A2AStarletteApplication , agent_card : AgentCard
@@ -190,7 +240,7 @@ def test_agent_card_custom_url(
190240 assert data ['name' ] == agent_card .name
191241
192242
193- def test_rpc_endpoint_custom_url (
243+ def test_starlette_rpc_endpoint_custom_url (
194244 app : A2AStarletteApplication , handler : mock .AsyncMock
195245):
196246 """Test the RPC endpoint with a custom URL."""
@@ -214,8 +264,31 @@ def test_rpc_endpoint_custom_url(
214264 data = response .json ()
215265 assert data ['result' ]['id' ] == 'task1'
216266
267+ def test_fastapi_rpc_endpoint_custom_url (
268+ app : A2AFastAPIApplication , handler : mock .AsyncMock
269+ ):
270+ """Test the RPC endpoint with a custom URL."""
271+ # Provide a valid Task object as the return value
272+ task_status = TaskStatus (** MINIMAL_TASK_STATUS )
273+ task = Task (
274+ id = 'task1' , contextId = 'ctx1' , state = 'completed' , status = task_status
275+ )
276+ handler .on_get_task .return_value = task
277+ client = TestClient (app .build (rpc_url = '/api/rpc' ))
278+ response = client .post (
279+ '/api/rpc' ,
280+ json = {
281+ 'jsonrpc' : '2.0' ,
282+ 'id' : '123' ,
283+ 'method' : 'tasks/get' ,
284+ 'params' : {'id' : 'task1' },
285+ },
286+ )
287+ assert response .status_code == 200
288+ data = response .json ()
289+ assert data ['result' ]['id' ] == 'task1'
217290
218- def test_build_with_extra_routes (
291+ def test_starlette_build_with_extra_routes (
219292 app : A2AStarletteApplication , agent_card : AgentCard
220293):
221294 """Test building the app with additional routes."""
@@ -238,6 +311,29 @@ def custom_handler(request):
238311 data = response .json ()
239312 assert data ['name' ] == agent_card .name
240313
314+ def test_fastapi_build_with_extra_routes (
315+ app : A2AFastAPIApplication , agent_card : AgentCard
316+ ):
317+ """Test building the app with additional routes."""
318+
319+ def custom_handler (request ):
320+ return JSONResponse ({'message' : 'Hello' })
321+
322+ extra_route = Route ('/hello' , custom_handler , methods = ['GET' ])
323+ test_app = app .build (routes = [extra_route ])
324+ client = TestClient (test_app )
325+
326+ # Test the added route
327+ response = client .get ('/hello' )
328+ assert response .status_code == 200
329+ assert response .json () == {'message' : 'Hello' }
330+
331+ # Ensure default routes still work
332+ response = client .get ('/.well-known/agent.json' )
333+ assert response .status_code == 200
334+ data = response .json ()
335+ assert data ['name' ] == agent_card .name
336+
241337
242338# === REQUEST METHODS TESTS ===
243339
0 commit comments