Skip to content

Commit 7442971

Browse files
authored
Update test_push_notification_sender.py
Add comprehensive test coverage for authentication scenarios
1 parent 492f406 commit 7442971

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

tests/server/tasks/test_push_notification_sender.py

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
BasePushNotificationSender,
99
)
1010
from a2a.types import (
11+
PushNotificationAuthenticationInfo,
1112
PushNotificationConfig,
1213
Task,
1314
TaskState,
@@ -29,8 +30,11 @@ def create_sample_push_config(
2930
url: str = 'http://example.com/callback',
3031
config_id: str = 'cfg1',
3132
token: str | None = None,
33+
authentication: PushNotificationAuthenticationInfo | None = None,
3234
) -> PushNotificationConfig:
33-
return PushNotificationConfig(id=config_id, url=url, token=token)
35+
return PushNotificationConfig(
36+
id=config_id, url=url, token=token, authentication=authentication
37+
)
3438

3539

3640
class TestBasePushNotificationSender(unittest.IsolatedAsyncioTestCase):
@@ -92,6 +96,90 @@ async def test_send_notification_with_token_success(self) -> None:
9296
)
9397
mock_response.raise_for_status.assert_called_once()
9498

99+
async def test_send_notification_with_bearer_authentication(self) -> None:
100+
task_id = 'task_send_bearer_auth'
101+
task_data = create_sample_task(task_id=task_id)
102+
auth_info = PushNotificationAuthenticationInfo(
103+
schemes=['Bearer'], credentials='test-jwt-token'
104+
)
105+
config = create_sample_push_config(
106+
url='http://notify.me/here',
107+
token='unique_token',
108+
authentication=auth_info,
109+
)
110+
self.mock_config_store.get_info.return_value = [config]
111+
112+
mock_response = AsyncMock(spec=httpx.Response)
113+
mock_response.status_code = 200
114+
self.mock_httpx_client.post.return_value = mock_response
115+
116+
await self.sender.send_notification(task_data)
117+
118+
self.mock_config_store.get_info.assert_awaited_once_with(task_id)
119+
120+
# assert httpx_client post method got invoked with right parameters
121+
self.mock_httpx_client.post.assert_awaited_once_with(
122+
config.url,
123+
json=task_data.model_dump(mode='json', exclude_none=True),
124+
headers={
125+
'X-A2A-Notification-Token': 'unique_token',
126+
'Authorization': 'Bearer test-jwt-token',
127+
},
128+
)
129+
mock_response.raise_for_status.assert_called_once()
130+
131+
async def test_send_notification_with_bearer_authentication_no_credentials(
132+
self,
133+
) -> None:
134+
task_id = 'task_send_bearer_no_creds'
135+
task_data = create_sample_task(task_id=task_id)
136+
auth_info = PushNotificationAuthenticationInfo(
137+
schemes=['Bearer'], credentials=None
138+
)
139+
config = create_sample_push_config(
140+
url='http://notify.me/here', authentication=auth_info
141+
)
142+
self.mock_config_store.get_info.return_value = [config]
143+
144+
mock_response = AsyncMock(spec=httpx.Response)
145+
mock_response.status_code = 200
146+
self.mock_httpx_client.post.return_value = mock_response
147+
148+
await self.sender.send_notification(task_data)
149+
150+
# Should not add Authorization header when credentials are missing
151+
self.mock_httpx_client.post.assert_awaited_once_with(
152+
config.url,
153+
json=task_data.model_dump(mode='json', exclude_none=True),
154+
headers=None,
155+
)
156+
157+
async def test_send_notification_with_non_bearer_authentication(
158+
self,
159+
) -> None:
160+
task_id = 'task_send_non_bearer'
161+
task_data = create_sample_task(task_id=task_id)
162+
auth_info = PushNotificationAuthenticationInfo(
163+
schemes=['Basic'], credentials='user:pass'
164+
)
165+
config = create_sample_push_config(
166+
url='http://notify.me/here', authentication=auth_info
167+
)
168+
self.mock_config_store.get_info.return_value = [config]
169+
170+
mock_response = AsyncMock(spec=httpx.Response)
171+
mock_response.status_code = 200
172+
self.mock_httpx_client.post.return_value = mock_response
173+
174+
await self.sender.send_notification(task_data)
175+
176+
# Should not add Authorization header for non-Bearer schemes
177+
self.mock_httpx_client.post.assert_awaited_once_with(
178+
config.url,
179+
json=task_data.model_dump(mode='json', exclude_none=True),
180+
headers=None,
181+
)
182+
95183
async def test_send_notification_no_config(self) -> None:
96184
task_id = 'task_send_no_config'
97185
task_data = create_sample_task(task_id=task_id)

0 commit comments

Comments
 (0)