diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts new file mode 100644 index 00000000..7f07e896 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts @@ -0,0 +1,68 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Metadata to be attached for the given type of RPCs. + */ +export interface _grpc_testing_ClientConfigureRequest_Metadata { + 'type'?: (_grpc_testing_ClientConfigureRequest_RpcType | keyof typeof _grpc_testing_ClientConfigureRequest_RpcType); + 'key'?: (string); + 'value'?: (string); +} + +/** + * Metadata to be attached for the given type of RPCs. + */ +export interface _grpc_testing_ClientConfigureRequest_Metadata__Output { + 'type': (keyof typeof _grpc_testing_ClientConfigureRequest_RpcType); + 'key': (string); + 'value': (string); +} + +// Original file: proto/grpc/testing/messages.proto + +/** + * Type of RPCs to send. + */ +export enum _grpc_testing_ClientConfigureRequest_RpcType { + EMPTY_CALL = 0, + UNARY_CALL = 1, +} + +/** + * Configurations for a test client. + */ +export interface ClientConfigureRequest { + /** + * The types of RPCs the client sends. + */ + 'types'?: (_grpc_testing_ClientConfigureRequest_RpcType | keyof typeof _grpc_testing_ClientConfigureRequest_RpcType)[]; + /** + * The collection of custom metadata to be attached to RPCs sent by the client. + */ + 'metadata'?: (_grpc_testing_ClientConfigureRequest_Metadata)[]; + /** + * The deadline to use, in seconds, for all RPCs. If unset or zero, the + * client will use the default from the command-line. + */ + 'timeout_sec'?: (number); +} + +/** + * Configurations for a test client. + */ +export interface ClientConfigureRequest__Output { + /** + * The types of RPCs the client sends. + */ + 'types': (keyof typeof _grpc_testing_ClientConfigureRequest_RpcType)[]; + /** + * The collection of custom metadata to be attached to RPCs sent by the client. + */ + 'metadata': (_grpc_testing_ClientConfigureRequest_Metadata__Output)[]; + /** + * The deadline to use, in seconds, for all RPCs. If unset or zero, the + * client will use the default from the command-line. + */ + 'timeout_sec': (number); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts new file mode 100644 index 00000000..df663240 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts @@ -0,0 +1,14 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Response for updating a test client's configuration. + */ +export interface ClientConfigureResponse { +} + +/** + * Response for updating a test client's configuration. + */ +export interface ClientConfigureResponse__Output { +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts new file mode 100644 index 00000000..1aa9773c --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts @@ -0,0 +1,14 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Request for retrieving a test client's accumulated stats. + */ +export interface LoadBalancerAccumulatedStatsRequest { +} + +/** + * Request for retrieving a test client's accumulated stats. + */ +export interface LoadBalancerAccumulatedStatsRequest__Output { +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts new file mode 100644 index 00000000..91157ac4 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts @@ -0,0 +1,78 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats { + /** + * The number of RPCs that were started for this method. + */ + 'rpcs_started'?: (number); + /** + * The number of RPCs that completed with each status for this method. The + * key is the integral value of a google.rpc.Code; the value is the count. + */ + 'result'?: ({[key: number]: number}); +} + +export interface _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats__Output { + /** + * The number of RPCs that were started for this method. + */ + 'rpcs_started': (number); + /** + * The number of RPCs that completed with each status for this method. The + * key is the integral value of a google.rpc.Code; the value is the count. + */ + 'result': ({[key: number]: number}); +} + +/** + * Accumulated stats for RPCs sent by a test client. + */ +export interface LoadBalancerAccumulatedStatsResponse { + /** + * The total number of RPCs have ever issued for each type. + * Deprecated: use stats_per_method.rpcs_started instead. + */ + 'num_rpcs_started_by_method'?: ({[key: string]: number}); + /** + * The total number of RPCs have ever completed successfully for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_succeeded_by_method'?: ({[key: string]: number}); + /** + * The total number of RPCs have ever failed for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_failed_by_method'?: ({[key: string]: number}); + /** + * Per-method RPC statistics. The key is the RpcType in string form; e.g. + * 'EMPTY_CALL' or 'UNARY_CALL' + */ + 'stats_per_method'?: ({[key: string]: _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats}); +} + +/** + * Accumulated stats for RPCs sent by a test client. + */ +export interface LoadBalancerAccumulatedStatsResponse__Output { + /** + * The total number of RPCs have ever issued for each type. + * Deprecated: use stats_per_method.rpcs_started instead. + */ + 'num_rpcs_started_by_method': ({[key: string]: number}); + /** + * The total number of RPCs have ever completed successfully for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_succeeded_by_method': ({[key: string]: number}); + /** + * The total number of RPCs have ever failed for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_failed_by_method': ({[key: string]: number}); + /** + * Per-method RPC statistics. The key is the RpcType in string form; e.g. + * 'EMPTY_CALL' or 'UNARY_CALL' + */ + 'stats_per_method'?: ({[key: string]: _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats__Output}); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts index aa4f409f..2c972726 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -1,6 +1,8 @@ // Original file: proto/grpc/testing/test.proto import * as grpc from '@grpc/grpc-js' +import { LoadBalancerAccumulatedStatsRequest as _grpc_testing_LoadBalancerAccumulatedStatsRequest, LoadBalancerAccumulatedStatsRequest__Output as _grpc_testing_LoadBalancerAccumulatedStatsRequest__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsRequest'; +import { LoadBalancerAccumulatedStatsResponse as _grpc_testing_LoadBalancerAccumulatedStatsResponse, LoadBalancerAccumulatedStatsResponse__Output as _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsResponse'; import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; @@ -8,6 +10,21 @@ import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, L * A service used to obtain stats for verifying LB behavior. */ export interface LoadBalancerStatsServiceClient extends grpc.Client { + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** * Gets the backend distribution for RPCs sent by a test client. */ @@ -29,6 +46,11 @@ export interface LoadBalancerStatsServiceClient extends grpc.Client { * A service used to obtain stats for verifying LB behavior. */ export interface LoadBalancerStatsServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + GetClientAccumulatedStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerAccumulatedStatsRequest__Output, _grpc_testing_LoadBalancerAccumulatedStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerAccumulatedStatsResponse>): void; + /** * Gets the backend distribution for RPCs sent by a test client. */ diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts new file mode 100644 index 00000000..693c37ec --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts @@ -0,0 +1,37 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { ClientConfigureRequest as _grpc_testing_ClientConfigureRequest, ClientConfigureRequest__Output as _grpc_testing_ClientConfigureRequest__Output } from '../../grpc/testing/ClientConfigureRequest'; +import { ClientConfigureResponse as _grpc_testing_ClientConfigureResponse, ClientConfigureResponse__Output as _grpc_testing_ClientConfigureResponse__Output } from '../../grpc/testing/ClientConfigureResponse'; + +/** + * A service to dynamically update the configuration of an xDS test client. + */ +export interface XdsUpdateClientConfigureServiceClient extends grpc.Client { + /** + * Update the tes client's configuration. + */ + Configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Update the tes client's configuration. + */ + configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service to dynamically update the configuration of an xDS test client. + */ +export interface XdsUpdateClientConfigureServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Update the tes client's configuration. + */ + Configure(call: grpc.ServerUnaryCall<_grpc_testing_ClientConfigureRequest__Output, _grpc_testing_ClientConfigureResponse>, callback: grpc.sendUnaryData<_grpc_testing_ClientConfigureResponse>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts index 330dbc9f..aedfa245 100644 --- a/packages/grpc-js-xds/interop/generated/test.ts +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -5,6 +5,7 @@ import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServic import { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; import { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; import { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; +import { XdsUpdateClientConfigureServiceClient as _grpc_testing_XdsUpdateClientConfigureServiceClient } from './grpc/testing/XdsUpdateClientConfigureService'; import { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; @@ -16,9 +17,13 @@ export interface ProtoGrpcType { grpc: { testing: { BoolValue: MessageTypeDefinition + ClientConfigureRequest: MessageTypeDefinition + ClientConfigureResponse: MessageTypeDefinition EchoStatus: MessageTypeDefinition Empty: MessageTypeDefinition GrpclbRouteType: EnumTypeDefinition + LoadBalancerAccumulatedStatsRequest: MessageTypeDefinition + LoadBalancerAccumulatedStatsResponse: MessageTypeDefinition LoadBalancerStatsRequest: MessageTypeDefinition LoadBalancerStatsResponse: MessageTypeDefinition /** @@ -50,6 +55,10 @@ export interface ProtoGrpcType { * that case. */ UnimplementedService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A service to dynamically update the configuration of an xDS test client. + */ + XdsUpdateClientConfigureService: SubtypeConstructor & { service: ServiceDefinition } /** * A service to remotely control health status of an xDS test server. */ diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 526c5194..c3cb55d5 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -26,6 +26,9 @@ import { TestServiceClient } from './generated/grpc/testing/TestService'; import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancerStatsResponse'; import * as yargs from 'yargs'; import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; +import { XdsUpdateClientConfigureServiceHandlers } from './generated/grpc/testing/XdsUpdateClientConfigureService'; +import { Empty__Output } from './generated/grpc/testing/Empty'; +import { LoadBalancerAccumulatedStatsResponse } from './generated/grpc/testing/LoadBalancerAccumulatedStatsResponse'; grpc_xds.register(); @@ -159,47 +162,95 @@ class CallStatsTracker { } } -function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { - let anyCallSucceeded: boolean = false; - setInterval(() => { - const notifier = callStatsTracker.startCall(); - let gotMetadata: boolean = false; - let hostname: string | null = null; - let completed: boolean = false; - let completedWithError: boolean = false; - const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + REQUEST_TIMEOUT_SEC); - const call = client.emptyCall({}, {deadline}, (error, value) => { - if (error) { - if (failOnFailedRpcs && anyCallSucceeded) { - console.error('A call failed after a call succeeded'); - process.exit(1); - } - completed = true; - completedWithError = true; - notifier.onCallFailed(error.message); - } else { - anyCallSucceeded = true; - if (gotMetadata) { - if (hostname === null) { - notifier.onCallFailed('Hostname omitted from call metadata'); - } else { - notifier.onCallSucceeded(hostname); - } - } +type CallType = 'EMPTY_CALL' | 'UNARY_CALL'; + +interface ClientConfiguration { + callTypes: (CallType)[]; + metadata: { + EMPTY_CALL: grpc.Metadata, + UNARY_CALL: grpc.Metadata + }, + timeoutSec: number +} + +const currentConfig: ClientConfiguration = { + callTypes: ['EMPTY_CALL'], + metadata: { + EMPTY_CALL: new grpc.Metadata(), + UNARY_CALL: new grpc.Metadata() + }, + timeoutSec: REQUEST_TIMEOUT_SEC +}; + +let anyCallSucceeded = false; + +const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { + stats_per_method: { + 'EMPTY_CALL': { + rpcs_started: 0, + result: {} + }, + 'UNARY_CALL': { + rpcs_started: 0, + result: {} + } + } +}; + +function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + const callTypeStats = accumulatedStats.stats_per_method![type]; + callTypeStats.rpcs_started! += 1; + + const notifier = callStatsTracker.startCall(); + let gotMetadata: boolean = false; + let hostname: string | null = null; + let completed: boolean = false; + let completedWithError: boolean = false; + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + currentConfig.timeoutSec); + const callback = (error: grpc.ServiceError | undefined, value: Empty__Output | undefined) => { + const statusCode = error?.code ?? grpc.status.OK; + callTypeStats.result![statusCode] = (callTypeStats.result![statusCode] ?? 0) + 1; + if (error) { + if (failOnFailedRpcs && anyCallSucceeded) { + console.error('A call failed after a call succeeded'); + process.exit(1); } - }); - call.on('metadata', (metadata) => { - hostname = (metadata.get('hostname') as string[])[0] ?? null; - gotMetadata = true; - if (completed && !completedWithError) { + completed = true; + completedWithError = true; + notifier.onCallFailed(error.message); + } else { + anyCallSucceeded = true; + if (gotMetadata) { if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } } - }) + } + }; + const method = (type === 'EMPTY_CALL' ? client.emptyCall : client.unaryCall).bind(client); + const call = method({}, currentConfig.metadata[type], {deadline}, callback); + call.on('metadata', (metadata) => { + hostname = (metadata.get('hostname') as string[])[0] ?? null; + gotMetadata = true; + if (completed && !completedWithError) { + if (hostname === null) { + notifier.onCallFailed('Hostname omitted from call metadata'); + } else { + notifier.onCallSucceeded(hostname); + } + } + }); + +} + +function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + setInterval(() => { + for (const callType of currentConfig.callTypes) { + makeSingleRequest(client, callType, failOnFailedRpcs, callStatsTracker); + } }, 1000/qps); } @@ -234,11 +285,30 @@ function main() { }, (error) => { callback({code: grpc.status.ABORTED, details: 'Call stats collection failed'}); }); + }, + GetClientAccumulatedStats: (call, callback) => { + callback(null, accumulatedStats); + } + } + + const xdsUpdateClientConfigureServiceImpl: XdsUpdateClientConfigureServiceHandlers = { + Configure: (call, callback) => { + const callMetadata = { + EMPTY_CALL: new grpc.Metadata(), + UNARY_CALL: new grpc.Metadata() + } + for (const metadataItem of call.request.metadata) { + callMetadata[metadataItem.type].add(metadataItem.key, metadataItem.value); + } + currentConfig.callTypes = call.request.types; + currentConfig.metadata = callMetadata; + currentConfig.timeoutSec = call.request.timeout_sec } } const server = new grpc.Server(); server.addService(loadedProto.grpc.testing.LoadBalancerStatsService.service, loadBalancerStatsServiceImpl); + server.addService(loadedProto.grpc.testing.XdsUpdateClientConfigureService.service, xdsUpdateClientConfigureServiceImpl); server.bindAsync(`0.0.0.0:${argv.stats_port}`, grpc.ServerCredentials.createInsecure(), (error, port) => { if (error) { throw error; diff --git a/packages/grpc-js-xds/proto/grpc/testing/messages.proto b/packages/grpc-js-xds/proto/grpc/testing/messages.proto index 70e34277..559876ed 100644 --- a/packages/grpc-js-xds/proto/grpc/testing/messages.proto +++ b/packages/grpc-js-xds/proto/grpc/testing/messages.proto @@ -212,3 +212,59 @@ message LoadBalancerStatsResponse { int32 num_failures = 2; map rpcs_by_method = 3; } + +// Request for retrieving a test client's accumulated stats. +message LoadBalancerAccumulatedStatsRequest {} + +// Accumulated stats for RPCs sent by a test client. +message LoadBalancerAccumulatedStatsResponse { + // The total number of RPCs have ever issued for each type. + // Deprecated: use stats_per_method.rpcs_started instead. + map num_rpcs_started_by_method = 1 [deprecated = true]; + // The total number of RPCs have ever completed successfully for each type. + // Deprecated: use stats_per_method.result instead. + map num_rpcs_succeeded_by_method = 2 [deprecated = true]; + // The total number of RPCs have ever failed for each type. + // Deprecated: use stats_per_method.result instead. + map num_rpcs_failed_by_method = 3 [deprecated = true]; + + message MethodStats { + // The number of RPCs that were started for this method. + int32 rpcs_started = 1; + + // The number of RPCs that completed with each status for this method. The + // key is the integral value of a google.rpc.Code; the value is the count. + map result = 2; + } + + // Per-method RPC statistics. The key is the RpcType in string form; e.g. + // 'EMPTY_CALL' or 'UNARY_CALL' + map stats_per_method = 4; +} + +// Configurations for a test client. +message ClientConfigureRequest { + // Type of RPCs to send. + enum RpcType { + EMPTY_CALL = 0; + UNARY_CALL = 1; + } + + // Metadata to be attached for the given type of RPCs. + message Metadata { + RpcType type = 1; + string key = 2; + string value = 3; + } + + // The types of RPCs the client sends. + repeated RpcType types = 1; + // The collection of custom metadata to be attached to RPCs sent by the client. + repeated Metadata metadata = 2; + // The deadline to use, in seconds, for all RPCs. If unset or zero, the + // client will use the default from the command-line. + int32 timeout_sec = 3; +} + +// Response for updating a test client's configuration. +message ClientConfigureResponse {} diff --git a/packages/grpc-js-xds/proto/grpc/testing/test.proto b/packages/grpc-js-xds/proto/grpc/testing/test.proto index 9d0fadd9..b2606a00 100644 --- a/packages/grpc-js-xds/proto/grpc/testing/test.proto +++ b/packages/grpc-js-xds/proto/grpc/testing/test.proto @@ -83,6 +83,10 @@ service LoadBalancerStatsService { // Gets the backend distribution for RPCs sent by a test client. rpc GetClientStats(LoadBalancerStatsRequest) returns (LoadBalancerStatsResponse) {} + + // Gets the accumulated stats for RPCs sent by a test client. + rpc GetClientAccumulatedStats(LoadBalancerAccumulatedStatsRequest) + returns (LoadBalancerAccumulatedStatsResponse) {} } // A service to remotely control health status of an xDS test server. @@ -90,3 +94,9 @@ service XdsUpdateHealthService { rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty); rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty); } + +// A service to dynamically update the configuration of an xDS test client. +service XdsUpdateClientConfigureService { + // Update the tes client's configuration. + rpc Configure(ClientConfigureRequest) returns (ClientConfigureResponse); +}