88 BasePushNotificationSender ,
99)
1010from a2a .types .a2a_pb2 import (
11+ AuthenticationInfo ,
1112 StreamResponse ,
1213 Task ,
1314 TaskArtifactUpdateEvent ,
@@ -34,8 +35,11 @@ def _create_sample_push_config(
3435 url : str = 'http://example.com/callback' ,
3536 config_id : str = 'cfg1' ,
3637 token : str | None = None ,
38+ authentication : AuthenticationInfo | None = None ,
3739) -> TaskPushNotificationConfig :
38- return TaskPushNotificationConfig (id = config_id , url = url , token = token )
40+ return TaskPushNotificationConfig (
41+ id = config_id , url = url , token = token , authentication = authentication
42+ )
3943
4044
4145class TestBasePushNotificationSender (unittest .IsolatedAsyncioTestCase ):
@@ -101,6 +105,61 @@ async def test_send_notification_with_token_success(self) -> None:
101105 )
102106 mock_response .raise_for_status .assert_called_once ()
103107
108+ async def test_send_notification_with_auth_header (self ) -> None :
109+ task_id = 'task_send_auth'
110+ task_data = _create_sample_task (task_id = task_id )
111+ config = _create_sample_push_config (
112+ url = 'http://notify.me/here' ,
113+ token = 'unique_token' ,
114+ authentication = AuthenticationInfo (
115+ scheme = 'Bearer' , credentials = 'token_or_jwt'
116+ ),
117+ )
118+ self .mock_config_store .get_info_for_dispatch .return_value = [config ]
119+
120+ mock_response = AsyncMock (spec = httpx .Response )
121+ mock_response .status_code = 200
122+ self .mock_httpx_client .post .return_value = mock_response
123+
124+ await self .sender .send_notification (task_id , task_data )
125+
126+ self .mock_config_store .get_info_for_dispatch .assert_awaited_once_with (
127+ task_data .id
128+ )
129+ self .mock_httpx_client .post .assert_awaited_once_with (
130+ config .url ,
131+ json = MessageToDict (StreamResponse (task = task_data )),
132+ headers = {
133+ 'X-A2A-Notification-Token' : 'unique_token' ,
134+ 'Authorization' : 'Bearer token_or_jwt' ,
135+ },
136+ )
137+ mock_response .raise_for_status .assert_called_once ()
138+
139+ def test_authorization_header_requires_scheme_and_credentials (self ) -> None :
140+ config = _create_sample_push_config ()
141+ self .assertIsNone (self .sender ._authorization_header (config ))
142+
143+ config = _create_sample_push_config (
144+ authentication = AuthenticationInfo (credentials = 'token_or_jwt' )
145+ )
146+ self .assertIsNone (self .sender ._authorization_header (config ))
147+
148+ config = _create_sample_push_config (
149+ authentication = AuthenticationInfo (scheme = 'Bearer' )
150+ )
151+ self .assertIsNone (self .sender ._authorization_header (config ))
152+
153+ config = _create_sample_push_config (
154+ authentication = AuthenticationInfo (
155+ scheme = 'Basic' , credentials = 'token_or_jwt'
156+ )
157+ )
158+ self .assertEqual (
159+ self .sender ._authorization_header (config ),
160+ 'Basic token_or_jwt' ,
161+ )
162+
104163 async def test_send_notification_no_config (self ) -> None :
105164 task_id = 'task_send_no_config'
106165 task_data = _create_sample_task (task_id = task_id )
0 commit comments