diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental.md index 592db6fd65..2541680046 100644 --- a/src/data/markdown/docs/02 javascript api/07 k6-experimental.md +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental.md @@ -12,4 +12,5 @@ excerpt: "k6 experimental APIs" | [timers](/javascript-api/k6-experimental/timers/) | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` | | [tracing](/javascript-api/k6-experimental/tracing/) | Support for instrumenting HTTP requests with tracing information. | | [webcrypto](/javascript-api/k6-experimental/webcrypto/) | Implements the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). | -| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). | \ No newline at end of file +| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). | +| [grpc](/javascript-api/k6-experimental/grpc/) | Extends `k6/net/grpc` with the streaming capabilities. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md new file mode 100644 index 0000000000..8197972ac5 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md @@ -0,0 +1,62 @@ +--- +title: "grpc" +excerpt: "Experimental GRPC module" +--- + + + +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. + +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. + +| Class/Method | Description | +|--------------|-------------| +| [Client](/javascript-api/k6-experimental/grpc/client) | gRPC client used for making RPC calls to a gRPC Server. | +| [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. | +| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Connects to a given gRPC service. | +| [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). | +| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. | +| [Params](/javascript-api/k6-experimental/grpc/params) | RPC Request specific options. | +| [Response](/javascript-api/k6-experimental/grpc/response) | Returned by RPC requests. | +| [Constants](/javascript-api/k6-experimental/grpc/constants) | Define constants to distinguish between [gRPC Response](/javascript-api/k6-experimental/grpc/response) statuses. | +| [Stream](/javascript-api/k6-experimental/grpc/stream) | Creates a new GRPC stream. | +| [Stream.on(event, handler)](/javascript-api/k6-experimental/grpc/stream/stream-on) | Adds a new listener to one of the possible stream event's. | +| [Stream.write(message)](/javascript-api/k6-experimental/grpc/stream/stream-write) | Writes a message to the stream. | +| [Stream.end()](/javascript-api/k6-experimental/grpc/stream/stream-end) | Signals to server that client finished sending. | + +## Metrics + +k6 takes specific measurements for gRPC requests. +For the complete list, refer to the [Metrics reference](/using-k6/metrics/reference#grpc). + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcb.in:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md new file mode 100644 index 0000000000..6caad11920 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md @@ -0,0 +1,105 @@ +--- +title: Client +excerpt: 'Client is a gRPC client that can interact with a gRPC server.' +--- + +`Client` is a gRPC client that can interact with a gRPC server. + + + +| Method | Description | +|--------|-------------| +| [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. | +| [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. | +| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Opens a connection to the given gRPC server. | +| [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). | +| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. | + + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +// Download addsvc.proto for https://grpcb.in/, located at: +// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto +// and put it in the same folder as this script. +client.load(null, 'addsvc.proto'); + +export default () => { + client.connect('grpcb.in:9001', { timeout: '5s' }); + + const response = client.invoke('addsvc.Add/Sum', { + a: 1, + b: 2, + }); + console.log(response.message.v); // should print 3 + + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'authorization.proto', 'route_guide.proto'); + +export function setup() { + client.connect('auth.googleapis.com:443'); + const resp = client.invoke('google.cloud.authorization.v1.AuthService/GetAccessToken', { + username: 'john.smith@k6.io', + password: 'its-a-secret', + }); + client.close(); + return resp.message.accessToken; +} + +export default (token) => { + client.connect('route.googleapis.com:443'); + const metadata = { + authorization: `bearer ${token}`, + }; + const response = client.invoke( + 'google.cloud.route.v1.RoutingService/GetFeature', + { + latitude: 410248224, + longitude: -747127767, + }, + { metadata } + ); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('language.googleapis.com:443'); + } + const response = client.invoke('google.cloud.language.v1.LanguageService/AnalyzeSentiment', {}); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + // Do NOT close the client +}; +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md new file mode 100644 index 0000000000..f4dbc8b7a0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md @@ -0,0 +1,43 @@ +--- +title: "Client.load(importPaths, ...protoFiles)" +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.' +--- + +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. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| importPaths | Array<string> \| `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. | +| protoFiles | Array<string> | [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) for the list of proto files to load/parse. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +client.load( + ['../googleapis/google'], + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/v1/spanner.proto' +); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md new file mode 100644 index 0000000000..1b585f20fe --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md @@ -0,0 +1,25 @@ +--- +title: "Client.loadProtoset(protosetPath)" +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.' +--- + +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. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| 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. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.loadProtoset('./dummy.protoset'); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md new file mode 100644 index 0000000000..6d48c31c98 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md @@ -0,0 +1,52 @@ +--- +title: "Client.connect(address [,params])" +excerpt: 'Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown.' +--- + +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). + +See [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) to close the connection. + +| Parameter | Type | Description | +|-----------|------|-------------| +| 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`. | +| params (optional) | object | [ConnectParams](#connectparams) object containing additional connect parameters. | + + +## ConnectParams + +| Name | Type | Description | +|------|------|-------------| +| `ConnectParams.plaintext` | bool | If `true` will connect to the gRPC server using plaintext i.e. insecure. Defaults to `false` i.e. secure via TLS. | +| `ConnectParams.reflect` | boolean | Whether to use the [gRPC server reflection protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) when connecting. | +| `ConnectParams.timeout` | string / number | Connection timeout to use. Default timeout is `"60s"`.
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | +| `ConnectParams.maxReceiveSize` | number | Sets the maximum message size in bytes the client can receive.Defaults to 0. | +| `ConnectParams.maxSendSize` | number | Sets the maximum message size in bytes the client can send.Defaults to 0. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080'); +}; +``` +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080', { plaintext: true }); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md new file mode 100644 index 0000000000..336f6c4eb7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md @@ -0,0 +1,51 @@ +--- +title: "Client.invoke(url, request [,params])" +excerpt: 'Invokes an unary RPC request to the given method.' +--- + +Invokes an unary RPC request to the given method. + +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 +error will be thrown. + +[Client.connect()](/javascript-api/k6-experimental/grpc/client/client-connect) must be called first before invoking a request, otherwise an error will be thrown. + +| Parameter | Type | Description | +|-----------|------|-------------| +| 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. | +| request | object | The canonical request object, as-per the [Protobuf JSON Mapping](https://developers.google.com/protocol-buffers/docs/proto3#json). | +| params (optional) | object | [Params](/javascript-api/k6-experimental/grpc/params) object containing additional request parameters. + +### Returns + +| Type | Description | +|------|-------------| +| `Response` | gRPC [Response](/javascript-api/k6-experimental/grpc/response) object. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'routeguide.proto'); + +export default () => { + client.connect('localhost:10000', { plaintext: true }); + const response = client.invoke('main.RouteGuide/GetFeature', { + latitude: 410248224, + longitude: -747127767, + }); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + console.log(response.message.name); + // output: 3 Hasta Way, Newton, NJ 07860, USA + + client.close(); +}; +``` + +
+ diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md new file mode 100644 index 0000000000..9402dc6da3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md @@ -0,0 +1,23 @@ +--- +title: "Client.close()" +excerpt: 'Close the connection to the gRPC service. Tear down all underlying connections.' +--- + +Close the connection to the gRPC service. Tear down all underlying connections. + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('localhost:8080'); + client.close(); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md new file mode 100644 index 0000000000..4ebe15f908 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md @@ -0,0 +1,39 @@ +--- +title: "Params" +head_title: 'gRPC.params' +excerpt: 'Params is an object used by the gRPC methods that generate RPC requests.' +--- + +*Params* is an object used by the gRPC methods that generate RPC requests. *Params* contains request-specific options like headers that should be inserted into the request. + +| Name | Type | Description | +|------|------|-------------| +| `Params.metadata` | object | Object with key-value pairs representing custom metadata the user would like to add to the request. | +| `Params.tags` | object | Key-value pairs where the keys are names of tags and the values are tag values. Response time metrics generated as a result of the request will have these tags added to them, allowing the user to filter out those results specifically, when looking at results data. | +| `Params.timeout` | string / number | Request timeout to use. Default timeout is 60 seconds (`"60s"`).
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | + + +### Example of custom metadata headers and tags + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load([], 'route_guide.proto'); + +export default function () { + const req = { + latitude: 410248224, + longitude: -747127767, + }; + const params = { + metadata: { 'x-my-header': 'k6test' }, + tags: { k6test: 'yes' }, + }; + const response = client.invoke('main.RouteGuide/GetFeature', req, params); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md new file mode 100644 index 0000000000..a8d8d1ead5 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md @@ -0,0 +1,66 @@ +--- +title: "Stream.on()" +excerpt: 'Set up handler functions for various events on the GRPC stream.' +--- + +Set up handler functions for various events on the GRPC stream. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------- | +| event | string | The event name to define a handler for. | +| handler | function | The function to call when the event happens. | + +Possible events: + +| Event name | Description | +| --------- | -------- | +| data | Emitted when the server sends data| +| error | Emitted when an error occurs. In case of the error, an [`Error`](/javascript-api/k6-experimental/grpc/stream/stream-error) object sends to the handler function.| +| end | Emitted when stream closes | + + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + // sets up a handler for the data (server sends data) event + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Traveled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + // sets up a handler for the end event (stream closes) + stream.on('end', function () { + // The server has finished sending + client.close(); + console.log('All done'); + }); + + // sets up a handler for the error event (an error occurs) + stream.on('error', function (e) { + // An error has occurred and the stream has been closed. + console.log('Error: ' + JSON.stringify(e)); + }); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md new file mode 100644 index 0000000000..3b676c6922 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md @@ -0,0 +1,13 @@ +--- +title: "Error" +head_title: 'gRPC.Error' +excerpt: 'The error object of a gRPC stream.' +--- + +The error object is the object that is passed to the `error` event handler function. + +| Name | Type | Description | +|------|------|-------------| +| `Error.code` | number | A gRPC error code. | +| `Error.details` | array | A list details attached to the error. | +| `Error.message` | string | An original error message. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md new file mode 100644 index 0000000000..37fd1c1bee --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md @@ -0,0 +1,45 @@ +--- +title: "Stream.end()" +excerpt: 'Signals to the server that the client has finished sending.' +--- + +Signals to the server that the client has finished sending messages. + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Traveled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + // send 2 items + stream.write({ latitude: 406109563, longitude: -742186778 }); + stream.write({ latitude: 416802456, longitude: -742370183 }); + + // send end-signal to the server + stream.end(); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md new file mode 100644 index 0000000000..0b8087749b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md @@ -0,0 +1,41 @@ +--- +title: "Stream.write()" +excerpt: 'Writes a message to the stream.' +--- + +Writes a message to the stream. + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + }); + + // send an item + stream.write({ latitude: 406109563, longitude: -742186778 }); + + // send end-signal to the server + stream.end(); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md new file mode 100644 index 0000000000..abd61d0916 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md @@ -0,0 +1,43 @@ +--- +title: "Response" +head_title: 'gRPC.Response' +excerpt: 'The response object of a gRPC request.' +--- + +| Name | Type | Description | +|------|------|-------------| +| `Response.status` | number | The response gRPC status code. Use the gRPC [status constants](/javascript-api/k6-experimental/grpc/constants) to check equality. | +| `Response.message` | object | The successful protobuf message, serialized to JSON. Will be `null` if `status !== grpc.StatusOK`. | +| `Response.headers` | object | Key-value pairs representing all the metadata headers returned by the gRPC server. | +| `Response.trailers` | object | Key-value pairs representing all the metadata trailers returned by the gRPC server. | +| `Response.error` | object | If `status !== grpc.StatusOK` then the error protobuf message, serialized to JSON; otherwise `null`. | + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcb.in:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md new file mode 100644 index 0000000000..364bead9b6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md @@ -0,0 +1,56 @@ +--- +title: 'Constants' +excerpt: 'Define constants to distinguish between gRPC Response' +--- + +Define constants to distinguish between [gRPC Response](/javascript-api/k6-experimental/grpc/response) statuses. + +| Constant | Description | +|----------|-------------| +| `StatusOK` | OK is returned on success. | +| `StatusCanceled` | Canceled indicates the operation was canceled (typically by the caller). | +| `StatusUnknown` | Unknown error. | +| `StatusInvalidArgument` | InvalidArgument indicates the client specified an invalid argument. | +| `StatusDeadlineExceeded` | DeadlineExceeded means operation expired before completion. | +| `StatusNotFound` | NotFound means some requested entity (e.g., file or directory) was not found. | +| `StatusAlreadyExists` | AlreadyExists means an attempt to create an entity failed because one already exists. | +| `StatusPermissionDenied` | PermissionDenied indicates the caller does not have permission to execute the specified operation. | +| `StatusResourceExhausted` | ResourceExhausted indicates some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. | +| `StatusFailedPrecondition` | FailedPrecondition indicates operation was rejected because the system is not in a state required for the operation's execution. | +| `StatusAborted` | Aborted indicates the operation was aborted, typically due to a concurrency issue like sequencer check failures, transaction aborts, etc. | +| `StatusOutOfRange` | OutOfRange means operation was attempted past the valid range. E.g., seeking or reading past end of file. | +| `StatusUnimplemented` | Unimplemented indicates operation is not implemented or not supported/enabled in this service. | +| `StatusInternal` | Internal errors. Means some invariants expected by the underlying system have been broken. | +| `StatusUnavailable` | Unavailable indicates the service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | +| `StatusDataLoss` | DataLoss indicates unrecoverable data loss or corruption. | +| `StatusUnauthenticated` | Unauthenticated indicates the request does not have valid authentication credentials for the operation. | + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcb.in:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md new file mode 100644 index 0000000000..b70f413abc --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md @@ -0,0 +1,199 @@ +--- +title: Stream +excerpt: 'GRPC Streams' +--- + +Using a GRPC client creates a stream. An important note that the client should be already connected (client.connect called) to the server before creating a stream. + +| Method | Description | +|--------|-------------| +| [Stream(client, url, [,params])](/javascript-api/k6-experimental/grpc/stream) | Using a GRPC client creates a stream. | +| [Stream.write(message)](/javascript-api/k6-experimental/grpc/stream/stream-write) | Writes a message to the stream. | +| [Stream.on(event, handler)](/javascript-api/k6-experimental/grpc/stream/stream-on) | Set up handler functions for various events on the GRPC stream. | +| [Stream.end()](/javascript-api/k6-experimental/grpc/stream/stream-end) | Signals to the server that the client has finished sending. | + +### Examples + +_A k6 script that sends several randomly chosen points from the pre-generated feature database with a variable delay in between. Prints the statistics when they are sent from the server._ + + + +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000'; +const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto'; + +const client = new Client(); +client.load([], GRPC_PROTO_PATH); + +// a sample DB of points +const DB = [ + { + location: { latitude: 407838351, longitude: -746143763 }, + name: 'Patriots Path, Mendham, NJ 07945, USA', + }, + { + location: { latitude: 408122808, longitude: -743999179 }, + name: '101 New Jersey 10, Whippany, NJ 07981, USA', + }, + { + location: { latitude: 413628156, longitude: -749015468 }, + name: 'U.S. 6, Shohola, PA 18458, USA', + }, + { + location: { latitude: 419999544, longitude: -740371136 }, + name: '5 Conners Road, Kingston, NY 12401, USA', + }, + { + location: { latitude: 414008389, longitude: -743951297 }, + name: 'Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA', + }, + { + location: { latitude: 419611318, longitude: -746524769 }, + name: '287 Flugertown Road, Livingston Manor, NY 12758, USA', + }, + { + location: { latitude: 406109563, longitude: -742186778 }, + name: '4001 Tremley Point Road, Linden, NJ 07036, USA', + }, + { + location: { latitude: 416802456, longitude: -742370183 }, + name: '352 South Mountain Road, Wallkill, NY 12589, USA', + }, + { + location: { latitude: 412950425, longitude: -741077389 }, + name: 'Bailey Turn Road, Harriman, NY 10926, USA', + }, + { + location: { latitude: 412144655, longitude: -743949739 }, + name: '193-199 Wawayanda Road, Hewitt, NJ 07421, USA', + }, +]; + +export default () => { + if (__ITER == 0) { + client.connect(GRPC_ADDR, { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + stream.on('error', (err) => { + console.log('Stream Error: ' + JSON.stringify(err)); + }); + + stream.on('end', () => { + client.close(); + console.log('All done'); + }) + + // send 5 random items + for (let i = 0; i < 5; i++) { + const point = DB[Math.floor(Math.random() * DB.length)]; + pointSender(stream, point); + } + + // close the client stream + stream.end(); + + sleep(1); +}; + +const pointSender = (stream, point) => { + console.log( + 'Visiting point ' + + point.name + + ' ' + + point.location.latitude / COORD_FACTOR + + ', ' + + point.location.longitude / COORD_FACTOR + ); + + // send the location to the server + stream.write(point.location); + + sleep(0.5); +}; +``` + + + +_A k6 script that sends a rectangle message and results (features) are streamed back to the client._ + + + +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000'; +const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto'; + +const client = new Client(); + +client.load([], GRPC_PROTO_PATH); + +export default () => { + client.connect(GRPC_ADDR, { plaintext: true }); + + const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null); + + stream.on('data', function (feature) { + console.log( + 'Found feature called "' + + feature.name + + '" at ' + + feature.location.latitude / COORD_FACTOR + + ', ' + + feature.location.longitude / COORD_FACTOR + ); + }); + + stream.on('end', function () { + // The server has finished sending + client.close(); + console.log('All done'); + }); + + stream.on('error', function (e) { + // An error has occurred and the stream has been closed. + console.log('Error: ' + JSON.stringify(e)); + }); + + // send a message to the server + stream.write({ + lo: { + latitude: 400000000, + longitude: -750000000, + }, + hi: { + latitude: 420000000, + longitude: -730000000, + }, + }); + + sleep(0.5); +}; +``` + + +The preceding examples use a demo server, which you can run with the following command (Golang should be installed) in [k6 repository's root](https://github.com/grafana/k6): + + + +```bash +$ go run -mod=mod examples/grpc_server/*.go +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md index 8fb0e80f24..d05de79970 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md @@ -5,10 +5,13 @@ excerpt: "k6 gRPC API" The `k6/net/grpc` module, added in k6 v0.29.0, provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2. -
+
-The k6 gRPC API is currently considered in beta and is subject to change. Future k6 versions might have slight differences in the method and type signatures described in this documentation. +#### An extension with much better API exists +[xk6-grpc](https://github.com/grafana/xk6-grpc) implements gRPC streaming APIs. + +Currently, it's available as an experimental module [`k6/experimental/grpc`](/javascript-api/k6-experimental/grpc/). It is also likely that it will at some point become part of the core of k6.
| Class/Method | Description | diff --git a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md index e44a7d36a0..bf198e5de7 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md @@ -103,7 +103,16 @@ Apart from the usual HTTP specific metrics that k6 already tracks, the browser m k6 emits the following metrics when it interacts with a service through the [`gRPC`](https://k6.io/docs/javascript-api/k6-net-grpc/) API. -| Metric Name | Type | Description | -|---------------------|-------|-------------------------------------------| -| `grpc_req_duration` | Trend | Time to receive response from remote host | +| Metric Name | Type | Description | +|------------------------------|---------|-------------------------------------------| +| `grpc_req_duration` | Trend | Time to receive response from remote host | +| `grpc_streams` | Counter | Total number of started streams | +| `grpc_streams_msgs_sent` | Counter | Total number of messages sent | +| `grpc_streams_msgs_received` | Counter | Total number of messages received | + +
+ +Steams-related metrics (`grpc_streams*`) are available only with using `k6/experimental/grpc` module which is available since `k6` version `0.45.0`. + +
\ No newline at end of file