From cb973dcf0726b30f69c208f3afc6a676f282c4dd Mon Sep 17 00:00:00 2001 From: Oleg Bespalov Date: Wed, 9 Aug 2023 13:57:17 +0200 Subject: [PATCH 1/6] Document GPRC Connection's TLS option --- ...0-Client-connect-connect-address-params.md | 82 ++++++++++++++++++- ...0-Client-connect-connect-address-params.md | 82 ++++++++++++++++++- 2 files changed, 160 insertions(+), 4 deletions(-) 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 index 6d48c31c9..ffff18b08 100644 --- 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 @@ -20,8 +20,20 @@ See [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) t | `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. | +| `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. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) | TLS settings of the connection. Defaults not defined. | + +## TLS + +TLS settings of the connection, if not defined, the main TLS config from options will be used. + +| Name | Type | Description | +|------|------|-------------| +| `tls.cert` | string | PEM formatted client certificate. | +| `tls.key` | string | PEM formatted client private key. | +| `tls.password` | string | Password for decrypting the client's private key. | +| `tls.cacerts` | string / array | PEM formatted strings of the certificate authorities. | ### Examples @@ -50,3 +62,69 @@ export default () => { }; ``` + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +// note: there are no such services +const params = { + 'foo1.grpcbin.test.k6.io:9001': { + plaintext: false, + tls: { + cacerts: [open('cacerts0.pem')], + cert: open('cert0.pem'), + key: open('key0.pem'), + }, + }, + 'foo2.grpcbin.test.k6.io:9002': { + plaintext: false, + tls: { + cacerts: open('cacerts1.pem'), + cert: open('cert1.pem'), + key: open('key1.pem'), + password: 'cert1-passphrase', + }, + }, +}; +const clients = { + 'foo1.grpcbin.test.k6.io:9001': new grpc.Client(), + 'foo2.grpcbin.test.k6.io:9002': new grpc.Client(), +}; + +export default () => { + if (__ITER === 0) { + clients['foo1.grpcbin.test.k6.io:9001'].connect( + 'foo1.grpcbin.test.k6.io:9001', + params['foo1.grpcbin.test.k6.io:9001'] + ); + clients['foo2.grpcbin.test.k6.io:9002'].connect( + 'foo2.grpcbin.test.k6.io:9002', + params['foo2.grpcbin.test.k6.io:9002'] + ); + } + + const response1 = clients['foo1.grpcbin.test.k6.io:9001'].invoke('hello.HelloService/SayHello', { + greeting: 'Bert', + }); + + check(response1, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response1.message)); + + const response2 = clients['foo2.grpcbin.test.k6.io:9002'].invoke('hello.HelloService/SayHello', { + greeting: 'Ernie', + }); + + check(response2, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response2.message)); +}; +``` +
\ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md index 273a365a4..a949ef216 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md @@ -20,8 +20,20 @@ See [Client.close()](/javascript-api/k6-net-grpc/client/client-close) to close t | `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. | +| `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. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) | TLS settings of the connection. Defaults not defined. | + +## TLS + +TLS settings of the connection, if not defined, the main TLS config from options will be used. + +| Name | Type | Description | +|------|------|-------------| +| `tls.cert` | string | PEM formatted client certificate. | +| `tls.key` | string | PEM formatted client private key. | +| `tls.password` | string | Password for decrypting the client's private key. | +| `tls.cacerts` | string / array | PEM formatted strings of the certificate authorities. | ### Examples @@ -50,3 +62,69 @@ export default () => { }; ``` + +
+ +```javascript +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + +// note: there are no such services +const params = { + 'foo1.grpcbin.test.k6.io:9001': { + plaintext: false, + tls: { + cacerts: [open('cacerts0.pem')], + cert: open('cert0.pem'), + key: open('key0.pem'), + }, + }, + 'foo2.grpcbin.test.k6.io:9002': { + plaintext: false, + tls: { + cacerts: open('cacerts1.pem'), + cert: open('cert1.pem'), + key: open('key1.pem'), + password: 'cert1-passphrase', + }, + }, +}; +const clients = { + 'foo1.grpcbin.test.k6.io:9001': new grpc.Client(), + 'foo2.grpcbin.test.k6.io:9002': new grpc.Client(), +}; + +export default () => { + if (__ITER === 0) { + clients['foo1.grpcbin.test.k6.io:9001'].connect( + 'foo1.grpcbin.test.k6.io:9001', + params['foo1.grpcbin.test.k6.io:9001'] + ); + clients['foo2.grpcbin.test.k6.io:9002'].connect( + 'foo2.grpcbin.test.k6.io:9002', + params['foo2.grpcbin.test.k6.io:9002'] + ); + } + + const response1 = clients['foo1.grpcbin.test.k6.io:9001'].invoke('hello.HelloService/SayHello', { + greeting: 'Bert', + }); + + check(response1, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response1.message)); + + const response2 = clients['foo2.grpcbin.test.k6.io:9002'].invoke('hello.HelloService/SayHello', { + greeting: 'Ernie', + }); + + check(response2, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response2.message)); +}; +``` +
\ No newline at end of file From b04ff5985bd66f1b2be790c6f88fcafca70dca68 Mon Sep 17 00:00:00 2001 From: Oleg Bespalov Date: Fri, 11 Aug 2023 10:03:02 +0200 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Heitor Tashiro Sergent --- .../20 Client/20-Client-connect-connect-address-params.md | 8 +++++--- .../20 Client/20-Client-connect-connect-address-params.md | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) 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 index ffff18b08..c810f2d87 100644 --- 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 @@ -22,11 +22,11 @@ See [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) t | `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. | -| `ConnectParams.tls` (optional) | object | [TLS](#tls) | TLS settings of the connection. Defaults not defined. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) settings of the connection. Defaults to `null`. | ## TLS -TLS settings of the connection, if not defined, the main TLS config from options will be used. +TLS settings of the connection. If not defined, the main TLS config from options will be used. | Name | Type | Description | |------|------|-------------| @@ -69,7 +69,9 @@ export default () => { import grpc from 'k6/experimental/grpc'; import { check } from 'k6'; -// note: there are no such services +// note: the services in this example don't exist. If you would like +// to run this example, make sure to replace the URLs, and +// the cacerts, cert, key, and password variables. const params = { 'foo1.grpcbin.test.k6.io:9001': { plaintext: false, diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md index a949ef216..b80d6f3ed 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md @@ -22,11 +22,11 @@ See [Client.close()](/javascript-api/k6-net-grpc/client/client-close) to close t | `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. | -| `ConnectParams.tls` (optional) | object | [TLS](#tls) | TLS settings of the connection. Defaults not defined. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) settings of the connection. Defaults to `null`. | ## TLS -TLS settings of the connection, if not defined, the main TLS config from options will be used. +TLS settings of the connection. If not defined, the main TLS config from options will be used. | Name | Type | Description | |------|------|-------------| From 7baff9ed2ee3ba3943cfdf27e734b6c87369ad91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Crevon?= Date: Mon, 14 Aug 2023 14:33:32 +0200 Subject: [PATCH 3/6] Update src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md Co-authored-by: Mihail Stoykov <312246+mstoykov@users.noreply.github.com> --- ...0-Client-connect-connect-address-params.md | 106 +++++++++--------- 1 file changed, 50 insertions(+), 56 deletions(-) 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 index c810f2d87..7a70897cd 100644 --- 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 @@ -66,67 +66,61 @@ export default () => {
```javascript -import grpc from 'k6/experimental/grpc'; -import { check } from 'k6'; +import grpc from "k6/experimental/grpc"; +import { check } from "k6"; +import { SharedArray } from "k6/data"; +import exec from "k6/execution"; -// note: the services in this example don't exist. If you would like +// note: the services in this example don't exist. If you would like // to run this example, make sure to replace the URLs, and // the cacerts, cert, key, and password variables. -const params = { - 'foo1.grpcbin.test.k6.io:9001': { - plaintext: false, - tls: { - cacerts: [open('cacerts0.pem')], - cert: open('cert0.pem'), - key: open('key0.pem'), - }, - }, - 'foo2.grpcbin.test.k6.io:9002': { - plaintext: false, - tls: { - cacerts: open('cacerts1.pem'), - cert: open('cert1.pem'), - key: open('key1.pem'), - password: 'cert1-passphrase', - }, - }, -}; -const clients = { - 'foo1.grpcbin.test.k6.io:9001': new grpc.Client(), - 'foo2.grpcbin.test.k6.io:9002': new grpc.Client(), -}; +const grpcArgs = new SharedArray("grpc", () => { + // Using SharedArray here so that not every VU gets a copy of every certificate a key + return [ + { + host: "foo1.grpcbin.test.k6.io:9001", + plaintext: false, + params: { + tls: { + cacerts: [open("cacerts0.pem")], + cert: open("cert0.pem"), + key: open("key0.pem"), + }, + }, + }, + { + host: "foo2.grpcbin.test.k6.io:9002", + params: { + plaintext: false, + tls: { + cacerts: open("cacerts1.pem"), + cert: open("cert1.pem"), + key: open("key1.pem"), + password: "cert1-passphrase", + }, + }, + }, + ]; +}); + +const client = new grpc.Client(); export default () => { - if (__ITER === 0) { - clients['foo1.grpcbin.test.k6.io:9001'].connect( - 'foo1.grpcbin.test.k6.io:9001', - params['foo1.grpcbin.test.k6.io:9001'] - ); - clients['foo2.grpcbin.test.k6.io:9002'].connect( - 'foo2.grpcbin.test.k6.io:9002', - params['foo2.grpcbin.test.k6.io:9002'] - ); - } - - const response1 = clients['foo1.grpcbin.test.k6.io:9001'].invoke('hello.HelloService/SayHello', { - greeting: 'Bert', - }); - - check(response1, { - 'status is OK': (r) => r && r.status === grpc.StatusOK, - }); - - console.log(JSON.stringify(response1.message)); - - const response2 = clients['foo2.grpcbin.test.k6.io:9002'].invoke('hello.HelloService/SayHello', { - greeting: 'Ernie', - }); - - check(response2, { - 'status is OK': (r) => r && r.status === grpc.StatusOK, - }); - - console.log(JSON.stringify(response2.message)); + if (__ITER === 0) { + // Take one config and use it for this one VU + let grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + client.connect(grpcArg.host, grpcArg.params); + } + + const response = client.invoke("hello.HelloService/SayHello", { + greeting: "Bert", + }); + + check(response, { + "status is OK": (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); }; ```
\ No newline at end of file From e06bfc1c4b11e3680298e25d3b4a1aabd7452a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Crevon?= Date: Mon, 14 Aug 2023 14:33:42 +0200 Subject: [PATCH 4/6] Update src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md Co-authored-by: Mihail Stoykov <312246+mstoykov@users.noreply.github.com> --- ...0-Client-connect-connect-address-params.md | 110 +++++++++--------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md index b80d6f3ed..c81173c51 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md @@ -66,65 +66,61 @@ export default () => {
```javascript -import grpc from 'k6/net/grpc'; -import { check } from 'k6'; - -// note: there are no such services -const params = { - 'foo1.grpcbin.test.k6.io:9001': { - plaintext: false, - tls: { - cacerts: [open('cacerts0.pem')], - cert: open('cert0.pem'), - key: open('key0.pem'), - }, - }, - 'foo2.grpcbin.test.k6.io:9002': { - plaintext: false, - tls: { - cacerts: open('cacerts1.pem'), - cert: open('cert1.pem'), - key: open('key1.pem'), - password: 'cert1-passphrase', - }, - }, -}; -const clients = { - 'foo1.grpcbin.test.k6.io:9001': new grpc.Client(), - 'foo2.grpcbin.test.k6.io:9002': new grpc.Client(), -}; +import grpc from "k6/experimental/grpc"; +import { check } from "k6"; +import { SharedArray } from "k6/data"; +import exec from "k6/execution"; + +// note: the services in this example don't exist. If you would like +// to run this example, make sure to replace the URLs, and +// the cacerts, cert, key, and password variables. +const grpcArgs = new SharedArray("grpc", () => { + // Using SharedArray here so that not every VU gets a copy of every certificate a key + return [ + { + host: "foo1.grpcbin.test.k6.io:9001", + plaintext: false, + params: { + tls: { + cacerts: [open("cacerts0.pem")], + cert: open("cert0.pem"), + key: open("key0.pem"), + }, + }, + }, + { + host: "foo2.grpcbin.test.k6.io:9002", + params: { + plaintext: false, + tls: { + cacerts: open("cacerts1.pem"), + cert: open("cert1.pem"), + key: open("key1.pem"), + password: "cert1-passphrase", + }, + }, + }, + ]; +}); + +const client = new grpc.Client(); export default () => { - if (__ITER === 0) { - clients['foo1.grpcbin.test.k6.io:9001'].connect( - 'foo1.grpcbin.test.k6.io:9001', - params['foo1.grpcbin.test.k6.io:9001'] - ); - clients['foo2.grpcbin.test.k6.io:9002'].connect( - 'foo2.grpcbin.test.k6.io:9002', - params['foo2.grpcbin.test.k6.io:9002'] - ); - } - - const response1 = clients['foo1.grpcbin.test.k6.io:9001'].invoke('hello.HelloService/SayHello', { - greeting: 'Bert', - }); - - check(response1, { - 'status is OK': (r) => r && r.status === grpc.StatusOK, - }); - - console.log(JSON.stringify(response1.message)); - - const response2 = clients['foo2.grpcbin.test.k6.io:9002'].invoke('hello.HelloService/SayHello', { - greeting: 'Ernie', - }); - - check(response2, { - 'status is OK': (r) => r && r.status === grpc.StatusOK, - }); - - console.log(JSON.stringify(response2.message)); + if (__ITER === 0) { + // Take one config and use it for this one VU + let grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + client.connect(grpcArg.host, grpcArg.params); + } + + const response = client.invoke("hello.HelloService/SayHello", { + greeting: "Bert", + }); + + check(response, { + "status is OK": (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); }; ```
\ No newline at end of file From 1021f52b364fa633353f0a82ad6bd679361016fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Crevon?= Date: Mon, 14 Aug 2023 14:39:09 +0200 Subject: [PATCH 5/6] Update src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md Co-authored-by: Ivan <2103732+codebien@users.noreply.github.com> --- .../20 Client/20-Client-connect-connect-address-params.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 7a70897cd..ca020b953 100644 --- 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 @@ -108,7 +108,7 @@ const client = new grpc.Client(); export default () => { if (__ITER === 0) { // Take one config and use it for this one VU - let grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + const grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; client.connect(grpcArg.host, grpcArg.params); } From 213ce62a42bc68be9f251bb1160f2c89c7537f50 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov <312246+mstoykov@users.noreply.github.com> Date: Mon, 14 Aug 2023 15:39:40 +0300 Subject: [PATCH 6/6] Update src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md --- .../20 Client/20-Client-connect-connect-address-params.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md index c81173c51..da195d7df 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md @@ -108,7 +108,7 @@ const client = new grpc.Client(); export default () => { if (__ITER === 0) { // Take one config and use it for this one VU - let grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + const grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; client.connect(grpcArg.host, grpcArg.params); }