From 94d68a3feab124a908cf95682dfcb254726ec0b5 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov <312246+mstoykov@users.noreply.github.com> Date: Mon, 19 Jun 2023 14:59:25 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#65764=20k6=20v0.45?= =?UTF-8?q?.0=20updates=20by=20@mstoykov?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add metadata JS API and maintainance around it * k6: Add k6/experimental/grpc annotations * k6: bump k6 to v0.45 * Add browser options --------- Co-authored-by: Oleg Bespalov --- types/k6/execution.d.ts | 13 ++- types/k6/experimental/grpc.d.ts | 154 +++++++++++++++++++++++++++++ types/k6/index.d.ts | 3 +- types/k6/options.d.ts | 8 ++ types/k6/test/execution.ts | 12 +++ types/k6/test/experimental/grpc.ts | 66 +++++++++++++ types/k6/test/options.ts | 25 +++++ types/k6/tsconfig.json | 1 + 8 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 types/k6/experimental/grpc.d.ts create mode 100644 types/k6/test/experimental/grpc.ts diff --git a/types/k6/execution.d.ts b/types/k6/execution.d.ts index ada9c885f4..8fa9b6ad9d 100644 --- a/types/k6/execution.d.ts +++ b/types/k6/execution.d.ts @@ -101,9 +101,20 @@ declare namespace execution { idInTest: number; /** - * Hash to set or get VU tags. + * Map to set or get VU tags. + * @deprecated should use `metrics.tags` instead of just `tags` */ tags: Record; + metrics: { + /** + * Map to set or get VU tags. + */ + tags: Record; + /** + * Map to set or get VU metadata. + */ + metadata: Record; + } }; } diff --git a/types/k6/experimental/grpc.d.ts b/types/k6/experimental/grpc.d.ts new file mode 100644 index 0000000000..9c8342b687 --- /dev/null +++ b/types/k6/experimental/grpc.d.ts @@ -0,0 +1,154 @@ +// === Response === +// ---------------- + +/** + * gRPC response. + */ +export interface Response { + status: number; + + message: object; + + headers: object; + + trailers: object; + + error: object; +} + +export interface ConnectParams { + plaintext?: boolean; + + reflect?: boolean; + + timeout?: string | number; + + maxReceiveSize?: number; + + maxSendSize?: number; +} + +export interface Params { + /** + * @deprecated Use metadata instead. + */ + headers?: object; + + metadata?: object; + + tags?: object; + + timeout?: string | number; +} + +export interface GrpcError { + code: number; + details: string[] | object[]; + message: string; +} + +/** + * This module provides classes for Remote Procedure Calls over HTTP/2. + * https://k6.io/docs/javascript-api/k6-experimental/grpc/ + */ +declare namespace grpc { + /** + * gRPC client to interact with a gRPC server. + * https://k6.io/docs/javascript-api/k6-experimental/grpc/client/ + */ + class Client { + protected __brand: never; + + constructor(); + + /** Opens a connection to a gRPC server. */ + connect(address: string, params?: ConnectParams): void; + + /** Loads and parses the protocol buffer descriptors. */ + load(importPaths: string[], ...protoFiles: string[]): void; + + /** Loads a protoset and parses the protocol buffer descriptors */ + loadProtoset(protosetPath: string): void; + + /** Invokes an unary RPC request. */ + invoke(url: string, request: object, params?: Params): Response; + + /** Close the connection. */ + close(): void; + } + + /** + * StreamEvent describes the possible events that can be emitted + * by a gRPC stream. + */ + enum StreamEvent { + /** + * Event fired when data has been received from the server. + */ + Data = 'data', + + /** + * Event fired when a stream has been closed due to an error. + */ + Error = 'error', + + /** + * Event fired when the stream closes. + */ + End = 'end', + } + + /** + * Stream allows you to use streaming RPCs. + */ + class Stream { + /** + * The gRPC stream constructor, representing a single gRPC stream. + * + * @param client - the gRPC client to use, it must be connected. + * @param url - the RPC method to call. + * @param params - the parameters to use for the RPC call. + */ + constructor(client: Client, url: string, params?: Params); + + /** + * Set up handler functions for various events on the gRPC stream. + * + * @param event - the event to listen for + * @param listener - the callback to invoke when the event is emitted + */ + on(event: StreamEvent, listener: (data: object | GrpcError | undefined) => void): void; + + /** + * Writes a request to the stream. + * + * @param request - the request (message) to send to the server + */ + write(request: object): void; + + /** + * Signals to the server that the client has finished sending messages. + */ + end(): void; + } + + const StatusOK: number; + const StatusCanceled: number; + const StatusUnknown: number; + const StatusInvalidArgument: number; + const StatusDeadlineExceeded: number; + const StatusNotFound: number; + const StatusAlreadyExists: number; + const StatusPermissionDenied: number; + const StatusResourceExhausted: number; + const StatusFailedPrecondition: number; + const StatusAborted: number; + const StatusOutOfRange: number; + const StatusUnimplemented: number; + const StatusInternal: number; + const StatusUnavailable: number; + const StatusDataLoss: number; + const StatusUnauthenticated: number; +} + +export default grpc; diff --git a/types/k6/index.d.ts b/types/k6/index.d.ts index 4ca26c2564..466f7619ff 100644 --- a/types/k6/index.d.ts +++ b/types/k6/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for k6 0.44 +// Type definitions for k6 0.45 // Project: https://k6.io/docs/ // Definitions by: na-- // Mihail Stoykov @@ -48,6 +48,7 @@ import './experimental/timers'; import './experimental/tracing'; import './experimental/webcrypto'; import './experimental/websockets'; +import './experimental/grpc'; import './ws'; import './net/grpc'; diff --git a/types/k6/options.d.ts b/types/k6/options.d.ts index 4d5a679aaf..99f94e148c 100644 --- a/types/k6/options.d.ts +++ b/types/k6/options.d.ts @@ -242,6 +242,9 @@ export abstract class BaseScenario { /** Tags specific to this scenario. */ tags?: { [name: string]: string }; + + /** Additional options for each scenario */ + options?: ScenarioOptions; } /** @@ -439,3 +442,8 @@ export type Scenario = | ConstantArrivalRateScenario | RampingArrivalRateScenario | ExternallyControlledScenario; + +export interface ScenarioOptions { + /** Browser specific options */ + browser?: any; +} diff --git a/types/k6/test/execution.ts b/types/k6/test/execution.ts index d08fd41ff6..3968c0bfe3 100644 --- a/types/k6/test/execution.ts +++ b/types/k6/test/execution.ts @@ -23,6 +23,18 @@ execution.vu.tags['mytag3'] = true; // @ts-expect-error execution.vu.tags['mytag4'] = [1, 2, 3]; +execution.vu.metrics.tags['mytag'] = 'value1'; +execution.vu.metrics.tags['mytag2'] = 2; +execution.vu.metrics.tags['mytag3'] = true; +// @ts-expect-error +execution.vu.metrics.tags['mytag4'] = [1, 2, 3]; + +execution.vu.metrics.metadata['mytag'] = 'value1'; +execution.vu.metrics.metadata['mytag2'] = 2; +execution.vu.metrics.metadata['mytag3'] = true; +// @ts-expect-error +execution.vu.metrics.metadata['mytag4'] = [1, 2, 3]; + execution.test.abort(); // $ExpectType void execution.test.abort('this is the reason'); // $ExpectType void // @ts-expect-error diff --git a/types/k6/test/experimental/grpc.ts b/types/k6/test/experimental/grpc.ts new file mode 100644 index 0000000000..a061690d5c --- /dev/null +++ b/types/k6/test/experimental/grpc.ts @@ -0,0 +1,66 @@ +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +client.connect('hola'); +client.connect('localhost:8080', { plaintext: true }); +client.connect('localhost:8080', { plaintext: true, reflect: true }); +client.connect('localhost:8080', { timeout: 30 }); +client.connect('localhost:8080', { timeout: '30' }); +client.connect('localhost:8080', { maxReceiveSize: 30, maxSendSize: 30 }); + +client.close(); + +client.load(['../googleapis/google'], 'language_service.proto', 'extra_service.proto'); + +client.loadProtoset('./lib/test.protoset'); + +const req = { + latitude: 410248224, + longitude: -747127767, +}; +const params = { + metadata: { 'x-my-header': 'k6test' }, + tags: { k6test: 'yes' }, + timeout: 30, +}; +const response = client.invoke('main.RouteGuide/GetFeature', req, params); +response.error; +response.headers; +response.message; // $ExpectType object +response.status; +response.trailers; + +const params_with_string_timeout = { + metadata: { 'x-my-header': 'k6test' }, + tags: { k6test: 'yes' }, + timeout: '30', +}; +client.invoke('main.RouteGuide/UpdateFeature', req, params_with_string_timeout); + +const stream = new grpc.Stream(client, 'main.RouteGuide/GetFeature', params); + +stream.on(grpc.StreamEvent.Data, (data) => { + data; // $ExpectType object | GrpcError | undefined +}); + +stream.write({ latitude: 410248224, longitude: -747127767 }); +stream.end(); + +grpc.StatusOK; +grpc.StatusCanceled; +grpc.StatusUnknown; +grpc.StatusInvalidArgument; +grpc.StatusDeadlineExceeded; +grpc.StatusNotFound; +grpc.StatusAlreadyExists; +grpc.StatusPermissionDenied; +grpc.StatusResourceExhausted; +grpc.StatusFailedPrecondition; +grpc.StatusAborted; +grpc.StatusOutOfRange; +grpc.StatusUnimplemented; +grpc.StatusInternal; +grpc.StatusUnavailable; +grpc.StatusDataLoss; +grpc.StatusUnauthenticated; diff --git a/types/k6/test/options.ts b/types/k6/test/options.ts index 0df6499eb0..0a5b511077 100644 --- a/types/k6/test/options.ts +++ b/types/k6/test/options.ts @@ -101,3 +101,28 @@ const tlsOptions4: Options = { }, ], }; + +const browserScenarios: Scenario[] = [ + { + executor: 'shared-iterations', + iterations: 100, + options: { + browser: { + type: 'chromium', + }, + }, + }, +]; + +const browserScenariosBad: Scenario[] = [ + { + executor: 'shared-iterations', + iterations: 100, + options: { + // @ts-expect-error + somethingElse: { + type: 'chromium', + }, + }, + }, +]; diff --git a/types/k6/tsconfig.json b/types/k6/tsconfig.json index 44e01566bc..1d8b382329 100644 --- a/types/k6/tsconfig.json +++ b/types/k6/tsconfig.json @@ -37,6 +37,7 @@ "test/tracing.ts", "test/webcrypto.ts", "test/websockets.ts", + "test/experimental/grpc.ts", "test/ws.ts" ] }