use super::*;
#[tokio::test]
async fn full_handler_lifecycle_send_get_list_cancel() {
let handler = Arc::new(
RequestHandlerBuilder::new(EchoExecutor)
.build()
.expect("build handler"),
);
let send_result = handler
.on_send_message(make_send_params("lifecycle test"), false, None)
.await
.expect("send message");
let task = match send_result {
SendMessageResult::Response(SendMessageResponse::Task(t)) => t,
_ => panic!("expected Response(Task)"),
};
assert_eq!(
task.status.state,
TaskState::Completed,
"sent task should be Completed"
);
let task_id = task.id.clone();
let fetched = handler
.on_get_task(
a2a_protocol_types::params::TaskQueryParams {
tenant: None,
id: task_id.0.clone(),
history_length: None,
},
None,
)
.await
.expect("get task");
assert_eq!(fetched.id, task_id, "fetched task ID should match");
assert_eq!(
fetched.status.state,
TaskState::Completed,
"fetched task should still be Completed"
);
let list = handler
.on_list_tasks(
ListTasksParams {
tenant: None,
context_id: None,
status: None,
page_size: None,
page_token: None,
status_timestamp_after: None,
include_artifacts: None,
history_length: None,
},
None,
)
.await
.expect("list tasks");
assert!(
list.tasks.iter().any(|t| t.id == task_id),
"listed tasks should include the created task with id {:?}",
task_id
);
let cancel_err = handler
.on_cancel_task(
a2a_protocol_types::params::CancelTaskParams {
tenant: None,
id: task_id.0.clone(),
metadata: None,
},
None,
)
.await
.unwrap_err();
let cancel_err_msg = format!("{cancel_err:?}");
assert!(
matches!(
cancel_err,
a2a_protocol_server::ServerError::TaskNotCancelable(_)
),
"canceling a completed task should fail with TaskNotCancelable, got {cancel_err_msg}"
);
}
#[tokio::test]
async fn full_handler_lifecycle_with_streaming() {
let handler = RequestHandlerBuilder::new(EchoExecutor)
.build()
.expect("build handler");
let result = handler
.on_send_message(make_send_params("stream lifecycle"), true, None)
.await
.expect("send streaming");
let mut reader = match result {
SendMessageResult::Stream(r) => r,
_ => panic!("expected stream"),
};
let mut states = vec![];
let mut artifact_count = 0;
while let Some(event) = reader.read().await {
match event.expect("event ok") {
StreamResponse::StatusUpdate(u) => states.push(u.status.state),
StreamResponse::ArtifactUpdate(_) => artifact_count += 1,
_ => {}
}
}
assert_eq!(
states,
vec![TaskState::Working, TaskState::Completed],
"expected Working -> Completed state sequence, got {states:?}"
);
assert_eq!(
artifact_count, 1,
"expected exactly one artifact event, got {artifact_count}"
);
let list = handler
.on_list_tasks(
ListTasksParams {
tenant: None,
context_id: None,
status: None,
page_size: None,
page_token: None,
status_timestamp_after: None,
include_artifacts: None,
history_length: None,
},
None,
)
.await
.expect("list tasks");
assert!(
!list.tasks.is_empty(),
"should have at least one task after streaming, got {}",
list.tasks.len()
);
}
#[tokio::test]
async fn full_handler_lifecycle_failing_executor() {
let handler = RequestHandlerBuilder::new(FailingExecutor)
.build()
.expect("build handler");
let result = handler
.on_send_message(make_send_params("fail"), false, None)
.await;
match result {
Ok(SendMessageResult::Response(SendMessageResponse::Task(task))) => {
assert_eq!(
task.status.state,
TaskState::Failed,
"failing executor should produce Failed task"
);
}
Err(_) => {
}
_ => panic!("expected failed task or error"),
}
let result = handler
.on_send_message(make_send_params("fail-stream"), true, None)
.await
.expect("send streaming");
let mut reader = match result {
SendMessageResult::Stream(r) => r,
_ => panic!("expected stream"),
};
let mut saw_failed = false;
while let Some(event) = reader.read().await {
if let Ok(StreamResponse::StatusUpdate(u)) = event {
if u.status.state == TaskState::Failed {
saw_failed = true;
}
}
}
assert!(
saw_failed,
"expected a Failed status update in the stream from failing executor"
);
}