gRPC Plugin
The gRPC plugin tests gRPC services against their Protocol Buffers definition. Drift reads your .proto file, exposes every RPC method as a testable operation, encodes each request as a protobuf message, and compares the decoded response against your expectations.
Supported features
Scalar fields, nested messages, and enum fields
Repeated fields and map fields
oneoffieldsUnary, server-streaming, client-streaming, and bidirectional-streaming methods
gRPC status codes and status messages
Prerequisites
The
.protofile that defines the service (it must be fully resolved with no external files/dependencies)A running gRPC server
The
grpcplugin installed in your plugin directory
Write a test
Point sources at your .proto file and declare the grpc plugin:
drift-testcase-file: v1
title: "RouteGuide"
sources:
- name: routeguide
path: ../routeguide.proto
plugins:
- name: grpc
operations:
GetFeature_KnownLocation:
target: routeguide:routeguide.RouteGuide/GetFeature
description: "Returns a named feature at a known location"
parameters:
request:
body:
latitude: 407838351
longitude: -746143763
expected:
response:
body:
name: "Patriots Path, Mendham, NJ 07945, USA"Run the tests against your server:
drift verify \ --server-url grpc://localhost:50051 \ --test-files drift/routeguide.testcases.yaml
Target format
A target names the source namespace, the fully qualified service, and the method:
<namespace>:<package>.<Service>/<Method>
Request and response
Set request fields under parameters.request.body and assert on response fields under expected.response.body. Field names match the field names in your .proto file.
Drift compares only the fields you list, so you can assert on part of a response and ignore the rest. Enum fields are returned as their string names, such as HIGH or FEATURE_QUALITY_UNSPECIFIED.
Streaming methods
Use a YAML list wherever a stream carries more than one message:
Method type |
|
|
|---|---|---|
Unary | Map | Map |
Server-streaming | Map | List, compared in order |
Client-streaming | List, sent in order | Map |
Bidirectional-streaming | List, sent in order | List, compared in order |
RecordRoute_BasicClientStream:
target: routeguide:routeguide.RouteGuide/RecordRoute
parameters:
request:
body:
- latitude: 407838351
longitude: -746143763
- latitude: 413628156
longitude: -749015468
expected:
response:
body:
point_count: 2
feature_count: 2Streaming assertions compare messages by position, so the order of your list matters.
gRPC errors
Assert on the status code and message returned by a failed call:
GetFeature_NotFound:
target: routeguide:routeguide.RouteGuide/GetFeatureStrict
parameters:
request:
body:
latitude: 0
longitude: 0
expected:
response:
grpc-status: NOT_FOUND
grpc-message: "feature not found"Use grpc-status with the status name rather than its numeric value. To match part of a message, use the contains matcher:
grpc-message:
contains: "not found"When you assert a non-successful grpc-status, Drift skips response body validation, because a failed call carries no message body.
Publishing to PactFlow
When publishing to PactFlow, use grpc or protobuf as the value for the specification e.g.
pact pactflow publish-provider-contract \ --provider grpc-example \ --provider-app-version 1.0.0 \ ./routeguide.proto \ --specification grpc \ ...
Differences from the OpenAPI plugin
If you have written Drift tests for a REST API, three things change:
Targets name a service and method, not an HTTP path and verb.
Request data goes under
parameters.request.bodyas protobuf fields. There are no query parameters, path parameters, or HTTP headers.You assert on
grpc-statusandgrpc-messageinstead of an HTTP status code.
Limitations
Drift compares streamed messages by position. It does not support unordered or partial stream matching.
Drift does not currently support asserting on gRPC metadata.