# gRPC

> Call gRPC services: unary calls and server streams, with requests built from JSON files or tables, and check their status, their answers, their metadata and the messages they stream.

Source: https://axx.nimbusxr.us/references/packs/grpc/

Call gRPC services: unary calls and server streams, with requests built from JSON files or tables, and check their status, their answers, their metadata and the messages they stream.

Register the service once, usually in the `Background`:

```gherkin
Given the tracking grpc service with the following properties:
  | address | localhost:8410 |
```

- **The contract is the service's proto.** A `proto` row names its `.proto` file (compiled by Axx, with its imports) or a descriptor set (`protoc --descriptor_set_out --include_imports`); without one, Axx reads the service's descriptors through its server reflection. Requests are built with them, so a field the request message does not have fails the step, and answers are read with them.
- **Methods** are named `package.Service/Method`, as grpcurl names them; `Service/Method` or `Method` do when only one of the service's methods has that name.
- **Requests and answers are proto JSON:** fields by their JSON names (`lastScan.location`) or their proto names, enums by name, 64-bit numbers and bytes as proto JSON has them. A request's table sets paths into it, as the REST pack's request properties do.
- **The checks read the service's last call** in the scenario. A call that answers another status than OK does not fail the step that makes it: check its status.
- **Server streams** belong to the scenario, which closes them when it ends. Their messages are checked as they come; their status once they end.
- **Secrets stay secret:** `${env:..}` values in the properties, such as a token in `header.authorization`, are masked in logs and failures, and `${token:..}` names a token of the scenario.

Add it to a project with `axx pack add grpc`.

## Steps

### `grpc.service`

```gherkin
Given the {word} grpc service with the following properties:
  | property | value |
```

The table may start with the row naming its columns, as above, or go straight to its rows.

Register a gRPC service under a name. Its calls go over one connection per address for the run.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

| Property | Takes | Values | Default |
|---|---|---|---|
| `address` | the service's `host:port` |  | _required_ |
| `proto` | its `.proto` file, compiled with its imports, or a descriptor set (`protoc --descriptor_set_out --include_imports`); without it, Axx reads the service's server reflection |  | |
| `tls` | whether the connection is TLS, checked against the system's certificates | `true`, `false` | `false` |
| `header.<name>` | metadata sent with every call, such as `header.authorization` |  | |
| `timeout` | the deadline of each unary call, like `5s` |  | `10s` |

Values are expanded (`${env:..}`, `${sys:..}`, `${token:..}`); what `${env:..}` references expand to is masked everywhere.

**Example:**

```gherkin
Given the tracking grpc service with the following properties:
  | address | localhost:8410 |
Given the rating grpc service with the following properties:
  | address              | rating.parcels.example:443 |
  | tls                  | true                       |
  | proto                | protos/rating.proto        |
  | header.authorization | Bearer ${env:RATING_TOKEN} |
```

_Since 0.1.5._

### `grpc.call`

```gherkin
When the {word} method is called on the {word} grpc service
```

Call a method with an empty request message.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

**Example:**

```gherkin
When the parcels.tracking.v1.Tracking/ListDepots method is called on the tracking grpc service
```

_Since 0.1.5._

### `grpc.call.fields`

```gherkin
When the {word} method is called on the {word} grpc service with the following fields:
  | path | value |
```

The table may start with the row naming its columns, as above, or go straight to its rows.

Call a method with a request message built from the table.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

Each row is a path into the request (a field name, a dotted path like `lastScan.location`, or a JSONPath) and its value: a value takes the type of its field, double quotes make it text, `null` leaves the field unset and `undefined` removes it.

**Example:**

```gherkin
When the parcels.tracking.v1.Tracking/GetParcel method is called on the tracking grpc service with the following fields:
  | reference | PX-GRP-6101 |
```

_Since 0.1.5._

### `grpc.call.file`

```gherkin
When the {word} method is called on the {word} grpc service with the {filepath} message[[ and the following fields:]]
```

Call a method with the request message of a JSON file of the project (proto JSON), with the table's fields set into it when the step has one.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |
| `{filepath}` | a file of the project: a path relative to the feature file's directory, the `resources` directories or axx.yaml's directory (looked for in that order), or an absolute path, quoted when it has a space | `seeds/parcels.yaml`, `kafka/scan-delivered.json` |

Each row is a path into the request (a field name, a dotted path like `lastScan.location`, or a JSONPath) and its value: a value takes the type of its field, double quotes make it text, `null` leaves the field unset and `undefined` removes it.

**Variants**, the parts in `[[...]]` said or left out:

- `the {word} method is called on the {word} grpc service with the {filepath} message`
- `the {word} method is called on the {word} grpc service with the {filepath} message and the following fields:`

**Example:**

```gherkin
When the parcels.tracking.v1.Tracking/GetParcel method is called on the tracking grpc service with the grpc/get-parcel.json message
When the parcels.tracking.v1.Tracking/GetParcel method is called on the tracking grpc service with the grpc/get-parcel.json message and the following fields:
  | reference | PX-GRP-6102 |
```

_Since 0.1.5._

### `grpc.status`

```gherkin
Then [[within {duration} ]]the {word} grpc service answered {word}[[ with a message containing {string}]]
```

Check the status the service's last call answered: `OK`, `NOT_FOUND`, `INVALID_ARGUMENT`..., and the text its message contains.

- A server stream answers when it ends: the check waits for that, 10 seconds or `within {duration}`.

| Parameter | Takes | For example |
|---|---|---|
| `{duration}` | a duration in seconds (`s`) or minutes (`m`) | `5s`, `2m` |
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |
| `{string}` | text in double or single quotes, which the step leaves out | `"Get a quote"`, `'Express'` |

**Variants**, the parts in `[[...]]` said or left out:

- `the {word} grpc service answered {word}`
- `within {duration} the {word} grpc service answered {word}`
- `the {word} grpc service answered {word} with a message containing {string}`
- `within {duration} the {word} grpc service answered {word} with a message containing {string}`

**Example:**

```gherkin
Then the tracking grpc service answered OK
Then the tracking grpc service answered NOT_FOUND with a message containing 'PX-GRP-6199'
Then within 30s the tracking grpc service answered OK
```

_Since 0.1.5._

### `grpc.answer`

```gherkin
Then the {word} grpc service's answer has the following fields:
  | path | value |
```

The table may start with the row naming its columns, as above, or go straight to its rows.

Check the answer of the service's last call, a unary call that answered OK.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

Each row is a path into the answer as proto JSON (a field's JSON name, a dotted path like `lastScan.location`, or a JSONPath) and its value, compared as text: `null` for null and `undefined` for absent. Fields with their default values (`0`, `""`, `false`) are in the answer.

**Example:**

```gherkin
Then the tracking grpc service's answer has the following fields:
  | status            | OUT_FOR_DELIVERY |
  | lastScan.location | Leipzig          |
```

_Since 0.1.5._

### `grpc.metadata`

```gherkin
Then the {word} grpc service's answer has the following metadata:
  | name | value |
```

The table may start with the row naming its columns, as above, or go straight to its rows.

Check the metadata the service's last call answered with: its headers and trailers.

| Parameter | Takes | For example |
|---|---|---|
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

Each row is a name, in any case, and its value, compared as text: several values are joined with `, `; `undefined` for absent.

**Example:**

```gherkin
Then the tracking grpc service's answer has the following metadata:
  | x-served-by | tracking-v1 |
```

_Since 0.1.5._

### `grpc.streamed`

```gherkin
Then [[within {duration} ]]the {word} grpc service streamed a message where:
  | path | value |
```

The table may start with the row naming its columns, as above, or go straight to its rows.

Check that the service's last call, a server stream, sent a message with those values.

- The check waits for it: 10 seconds, or `within {duration}`.
- When the stream has ended, it fails at once, with the status it ended with.

| Parameter | Takes | For example |
|---|---|---|
| `{duration}` | a duration in seconds (`s`) or minutes (`m`) | `5s`, `2m` |
| `{word}` | one word, with no spaces | `parcels`, `PX-4101` |

Each row is a path into the message as proto JSON and its value, compared as text: `null` for null and `undefined` for absent.

**Variants**, the parts in `[[...]]` said or left out:

- `the {word} grpc service streamed a message where:`
- `within {duration} the {word} grpc service streamed a message where:`

**Example:**

```gherkin
Then within 20s the tracking grpc service streamed a message where:
  | reference | PX-GRP-6103      |
  | status    | OUT_FOR_DELIVERY |
```

_Since 0.1.5._
