Driving your service over gRPC
Start. tomato starts your service and its dependencies. The client only needs to know where the service is: an address, or nothing at all for the shell.
Act. A When step tells the client what to do, and it does it the way another service would: it sends a request.
Answer. The service answers through the same door: a status, headers and a body.
Assert. Then steps check that answer. Check the effects too, through the other resources: the row in the database, the message on Kafka.
Reset. Before the next scenario the client forgets its headers and cookies, so no scenario leans on another's.
What it needs: reflection
The client asks your service for its own schema, through gRPC server reflection, so you name a method the way you’d say it, and write messages as JSON. One line in the service turns it on:
reflection.Register(server) // Go
new ReflectionService(packageDefinition).addToServer(server) // Node.js, @grpc/reflection
The suite
resources:
todos-client: { type: grpc, address: localhost:50051 }
Scenario: The service describes itself
Then "todos-client" exposes service "todos.v1.TodoService"
And "todos-client" service "todos.v1.TodoService" has method "AddTodo"
Scenario: A todo is added
When "todos-client" calls "todos.v1.TodoService/AddTodo" with:
"""
{"title": "Buy milk"}
"""
Then "todos-client" call succeeds
And "todos-client" response json "title" is "Buy milk"
And "todos-client" response json "done" is "false"
Scenario: A todo needs a title
When "todos-client" calls "todos.v1.TodoService/AddTodo" with:
"""
{"title": ""}
"""
Then "todos-client" call fails
And "todos-client" response status is "INVALID_ARGUMENT"
And "todos-client" response error contains "title is required"
What it can do
| To | Step |
|---|---|
| send metadata | metadata "authorization" is "Bearer …" |
| call | calls "pkg.Service/Method", … with: a JSON message |
| check the outcome | call succeeds, call fails, response status is "NOT_FOUND", response error contains "…" |
| check the message | every JSON check the http client has: response json "a.b" is, contains:, matches: |
| check the schema | exposes service "…", service "…" has method "…" |
Notes
- A failed call is a result, not a broken step.
INVALID_ARGUMENTis something to assert. Only a call that can’t be made (an unknown method, a message that doesn’t fit) fails the step. - Zero values are in the JSON.
"done": falseis there to assert, though protobuf doesn’t send it. - Enums are names,
int64is a string."ROLE_ADMIN","priceCents": "250". - Unary calls only. Streaming calls need steps of their own; they’re refused with a clear message for now.