Skip to content

Commit 15eba58

Browse files
olegbespalovcodebienppcano
authored
Experimental grpc module (#1223)
Co-authored-by: Ivan <[email protected]> Co-authored-by: Pepe Cano <[email protected]>
1 parent 5739b88 commit 15eba58

18 files changed

+882
-6
lines changed

src/data/markdown/docs/02 javascript api/07 k6-experimental.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ excerpt: "k6 experimental APIs"
1212
| [timers](/javascript-api/k6-experimental/timers/) | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` |
1313
| [tracing](/javascript-api/k6-experimental/tracing/) | Support for instrumenting HTTP requests with tracing information. |
1414
| [webcrypto](/javascript-api/k6-experimental/webcrypto/) | Implements the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). |
15-
| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). |
15+
| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). |
16+
| [grpc](/javascript-api/k6-experimental/grpc/) | Extends `k6/net/grpc` with the streaming capabilities. |
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
title: "grpc"
3+
excerpt: "Experimental GRPC module"
4+
---
5+
6+
<ExperimentalBlockquote />
7+
8+
The `k6/experimental/grpc` module is an extension of the [`k6/net/grpc`](/javascript-api/k6-net-grpc/). It provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2.
9+
10+
The key-difference between the two modules is new `Stream` class, which provides client and server streaming support. Our long-term goal is to make this module part of k6 core, and long-term to replace the [`k6/net/grpc`](/javascript-api/k6-net-grpc/) module.
11+
12+
| Class/Method | Description |
13+
|--------------|-------------|
14+
| [Client](/javascript-api/k6-experimental/grpc/client) | gRPC client used for making RPC calls to a gRPC Server. |
15+
| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-experimental/grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. |
16+
| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Connects to a given gRPC service. |
17+
| [Client.invoke(url, request [,params])](/javascript-api/k6-experimental/grpc/client/client-invoke) | Makes a unary RPC for the given service/method and returns a [Response](/javascript-api/k6-experimental/grpc/response). |
18+
| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. |
19+
| [Params](/javascript-api/k6-experimental/grpc/params) | RPC Request specific options. |
20+
| [Response](/javascript-api/k6-experimental/grpc/response) | Returned by RPC requests. |
21+
| [Constants](/javascript-api/k6-experimental/grpc/constants) | Define constants to distinguish between [gRPC Response](/javascript-api/k6-experimental/grpc/response) statuses. |
22+
| [Stream](/javascript-api/k6-experimental/grpc/stream) | Creates a new GRPC stream. |
23+
| [Stream.on(event, handler)](/javascript-api/k6-experimental/grpc/stream/stream-on) | Adds a new listener to one of the possible stream event's. |
24+
| [Stream.write(message)](/javascript-api/k6-experimental/grpc/stream/stream-write) | Writes a message to the stream. |
25+
| [Stream.end()](/javascript-api/k6-experimental/grpc/stream/stream-end) | Signals to server that client finished sending. |
26+
27+
## Metrics
28+
29+
k6 takes specific measurements for gRPC requests.
30+
For the complete list, refer to the [Metrics reference](/using-k6/metrics/reference#grpc).
31+
32+
### Example
33+
34+
<CodeGroup labels={["grpc-test.js"]}>
35+
36+
```javascript
37+
import grpc from 'k6/experimental/grpc';
38+
import { check, sleep } from 'k6';
39+
40+
const client = new grpc.Client();
41+
client.load(['definitions'], 'hello.proto');
42+
43+
export default () => {
44+
client.connect('grpcb.in:9001', {
45+
// plaintext: false
46+
});
47+
48+
const data = { greeting: 'Bert' };
49+
const response = client.invoke('hello.HelloService/SayHello', data);
50+
51+
check(response, {
52+
'status is OK': (r) => r && r.status === grpc.StatusOK,
53+
});
54+
55+
console.log(JSON.stringify(response.message));
56+
57+
client.close();
58+
sleep(1);
59+
};
60+
```
61+
62+
</CodeGroup>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
title: Client
3+
excerpt: 'Client is a gRPC client that can interact with a gRPC server.'
4+
---
5+
6+
`Client` is a gRPC client that can interact with a gRPC server.
7+
8+
9+
10+
| Method | Description |
11+
|--------|-------------|
12+
| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-experimental/grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. |
13+
| [Client.loadProtoset(protosetPath)](/javascript-api/k6-experimental/grpc/client/client-loadprotoset) | Loads and parses the given protoset file to be made available for RPC requests. |
14+
| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Opens a connection to the given gRPC server. |
15+
| [Client.invoke(url, request [,params])](/javascript-api/k6-experimental/grpc/client/client-invoke) | Makes a unary RPC for the given service/method and returns a [Response](/javascript-api/k6-experimental/grpc/response). |
16+
| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. |
17+
18+
19+
### Examples
20+
21+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
22+
23+
```javascript
24+
import grpc from 'k6/experimental/grpc';
25+
26+
const client = new grpc.Client();
27+
// Download addsvc.proto for https://grpcb.in/, located at:
28+
// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto
29+
// and put it in the same folder as this script.
30+
client.load(null, 'addsvc.proto');
31+
32+
export default () => {
33+
client.connect('grpcb.in:9001', { timeout: '5s' });
34+
35+
const response = client.invoke('addsvc.Add/Sum', {
36+
a: 1,
37+
b: 2,
38+
});
39+
console.log(response.message.v); // should print 3
40+
41+
client.close();
42+
};
43+
```
44+
45+
</div>
46+
47+
<div class="code-group" data-props='{"labels": ["Authorization"], "lineNumbers": [true]}'>
48+
49+
```javascript
50+
import grpc from 'k6/experimental/grpc';
51+
import { check } from 'k6';
52+
53+
const client = new grpc.Client();
54+
client.load([], 'authorization.proto', 'route_guide.proto');
55+
56+
export function setup() {
57+
client.connect('auth.googleapis.com:443');
58+
const resp = client.invoke('google.cloud.authorization.v1.AuthService/GetAccessToken', {
59+
username: '[email protected]',
60+
password: 'its-a-secret',
61+
});
62+
client.close();
63+
return resp.message.accessToken;
64+
}
65+
66+
export default (token) => {
67+
client.connect('route.googleapis.com:443');
68+
const metadata = {
69+
authorization: `bearer ${token}`,
70+
};
71+
const response = client.invoke(
72+
'google.cloud.route.v1.RoutingService/GetFeature',
73+
{
74+
latitude: 410248224,
75+
longitude: -747127767,
76+
},
77+
{ metadata }
78+
);
79+
check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK });
80+
client.close();
81+
};
82+
```
83+
84+
</div>
85+
86+
<div class="code-group" data-props='{"labels": ["Single connection"], "lineNumbers": [true]}'>
87+
88+
```javascript
89+
import grpc from 'k6/experimental/grpc';
90+
import { check } from 'k6';
91+
92+
const client = new grpc.Client();
93+
client.load([], 'language_service.proto');
94+
95+
export default () => {
96+
if (__ITER == 0) {
97+
client.connect('language.googleapis.com:443');
98+
}
99+
const response = client.invoke('google.cloud.language.v1.LanguageService/AnalyzeSentiment', {});
100+
check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK });
101+
// Do NOT close the client
102+
};
103+
```
104+
105+
</div>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: "Client.load(importPaths, ...protoFiles)"
3+
excerpt: 'Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.'
4+
---
5+
6+
Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.
7+
8+
Must be called within the [`init` phase](/using-k6/test-lifecycle).
9+
10+
| Parameter | Type | Description |
11+
|-----------|------|-------------|
12+
| importPaths | Array&lt;string&gt; \| `null` | The paths used to search for dependencies that are referenced in import statements in proto source files. If no import paths are provided then "." (current directory) is assumed to be the only import path. |
13+
| protoFiles | Array&lt;string&gt; | [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) for the list of proto files to load/parse. |
14+
15+
### Examples
16+
17+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
18+
19+
```javascript
20+
import grpc from 'k6/experimental/grpc';
21+
22+
const client = new grpc.Client();
23+
client.load([], 'language_service.proto');
24+
```
25+
26+
</div>
27+
28+
<div class="code-group" data-props='{"labels": ["More complex"], "lineNumbers": [true]}'>
29+
30+
```javascript
31+
import grpc from 'k6/experimental/grpc';
32+
33+
const client = new grpc.Client();
34+
35+
client.load(
36+
['../googleapis/google'],
37+
'spanner/admin/instance/v1/spanner_instance_admin.proto',
38+
'spanner/admin/instance/v1/spanner_instance_admin.proto',
39+
'spanner/v1/spanner.proto'
40+
);
41+
```
42+
43+
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: "Client.loadProtoset(protosetPath)"
3+
excerpt: 'Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.'
4+
---
5+
6+
Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.
7+
8+
Must be called within the [`init` phase](/using-k6/test-lifecycle).
9+
10+
| Parameter | Type | Description |
11+
|-----------|------|-------------|
12+
| protosetPath | string | The path of the protoset file. If no import paths are provided then "." (current directory) is assumed to be the only import path. |
13+
14+
### Examples
15+
16+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
17+
18+
```javascript
19+
import grpc from 'k6/experimental/grpc';
20+
21+
const client = new grpc.Client();
22+
client.loadProtoset('./dummy.protoset');
23+
```
24+
25+
</div>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
title: "Client.connect(address [,params])"
3+
excerpt: 'Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown.'
4+
---
5+
6+
Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown. Cannot be called during the [`init` phase](/using-k6/test-lifecycle).
7+
8+
See [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) to close the connection.
9+
10+
| Parameter | Type | Description |
11+
|-----------|------|-------------|
12+
| address | string | The address of the gRPC server. Should be in the form: `host:port` with no protocol prefix e.g. `grpc.k6.io:443`. The host must be a literal IP address, or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name e.g. `:443` or `:https`. If the host is a literal IPv6 address it must be enclosed in square brackets, as in `[2001:db8::1]:80` or `[fe80::1%zone]:80`. |
13+
| params (optional) | object | [ConnectParams](#connectparams) object containing additional connect parameters. |
14+
15+
16+
## ConnectParams
17+
18+
| Name | Type | Description |
19+
|------|------|-------------|
20+
| `ConnectParams.plaintext` | bool | If `true` will connect to the gRPC server using plaintext i.e. insecure. Defaults to `false` i.e. secure via TLS. |
21+
| `ConnectParams.reflect` | boolean | Whether to use the [gRPC server reflection protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) when connecting. |
22+
| `ConnectParams.timeout` | string / number | Connection timeout to use. Default timeout is `"60s"`. <br/> The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. |
23+
| `ConnectParams.maxReceiveSize` | number | Sets the maximum message size in bytes the client can receive.Defaults to 0. |
24+
| `ConnectParams.maxSendSize` | number | Sets the maximum message size in bytes the client can send.Defaults to 0. |
25+
26+
### Examples
27+
28+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
29+
30+
```javascript
31+
import grpc from 'k6/experimental/grpc';
32+
33+
const client = new grpc.Client();
34+
35+
export default () => {
36+
client.connect('localhost:8080');
37+
};
38+
```
39+
</div>
40+
41+
<div class="code-group" data-props='{"labels": ["Insecure connection"], "lineNumbers": [true]}'>
42+
43+
```javascript
44+
import grpc from 'k6/experimental/grpc';
45+
46+
const client = new grpc.Client();
47+
48+
export default () => {
49+
client.connect('localhost:8080', { plaintext: true });
50+
};
51+
```
52+
</div>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
title: "Client.invoke(url, request [,params])"
3+
excerpt: 'Invokes an unary RPC request to the given method.'
4+
---
5+
6+
Invokes an unary RPC request to the given method.
7+
8+
The given method to invoke must have its RPC schema previously loaded via the [Client.load()](/javascript-api/k6-experimental/grpc/client/client-load) function, otherwise an
9+
error will be thrown.
10+
11+
[Client.connect()](/javascript-api/k6-experimental/grpc/client/client-connect) must be called first before invoking a request, otherwise an error will be thrown.
12+
13+
| Parameter | Type | Description |
14+
|-----------|------|-------------|
15+
| url | string | The gRPC method url to invoke, in the form `/package.Service/Method`, e.g. `/google.cloud.language.v1.LanguageService/AnalyzeSentiment`. The leading slash `/` is optional. |
16+
| request | object | The canonical request object, as-per the [Protobuf JSON Mapping](https://developers.google.com/protocol-buffers/docs/proto3#json). |
17+
| params (optional) | object | [Params](/javascript-api/k6-experimental/grpc/params) object containing additional request parameters.
18+
19+
### Returns
20+
21+
| Type | Description |
22+
|------|-------------|
23+
| `Response` | gRPC [Response](/javascript-api/k6-experimental/grpc/response) object. |
24+
25+
### Examples
26+
27+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
28+
29+
```javascript
30+
import grpc from 'k6/experimental/grpc';
31+
import { check } from 'k6';
32+
33+
const client = new grpc.Client();
34+
client.load([], 'routeguide.proto');
35+
36+
export default () => {
37+
client.connect('localhost:10000', { plaintext: true });
38+
const response = client.invoke('main.RouteGuide/GetFeature', {
39+
latitude: 410248224,
40+
longitude: -747127767,
41+
});
42+
check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK });
43+
console.log(response.message.name);
44+
// output: 3 Hasta Way, Newton, NJ 07860, USA
45+
46+
client.close();
47+
};
48+
```
49+
50+
</div>
51+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: "Client.close()"
3+
excerpt: 'Close the connection to the gRPC service. Tear down all underlying connections.'
4+
---
5+
6+
Close the connection to the gRPC service. Tear down all underlying connections.
7+
8+
### Examples
9+
10+
<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>
11+
12+
```javascript
13+
import grpc from 'k6/experimental/grpc';
14+
15+
const client = new grpc.Client();
16+
client.load(['definitions'], 'hello.proto');
17+
18+
export default () => {
19+
client.connect('localhost:8080');
20+
client.close();
21+
};
22+
```
23+
</div>

0 commit comments

Comments
 (0)