Skip to content

Commit 4fa8af3

Browse files
authored
Merge pull request #2392 from murgatroid99/grpc-js-xds_tests_1.8.x
grpc-js-xds: Add a framework for running xDS end-to-end tests (1.8.x)
2 parents 6b7c99b + e32bbc7 commit 4fa8af3

33 files changed

+1774
-22
lines changed

packages/grpc-js-xds/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"pretest": "npm run compile",
1414
"posttest": "npm run check",
1515
"generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto",
16-
"generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto"
16+
"generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto",
17+
"generate-test-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O test/generated --grpcLib @grpc/grpc-js grpc/testing/echo.proto"
1718
},
1819
"repository": {
1920
"type": "git",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
// Copyright 2015 gRPC authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
syntax = "proto3";
17+
18+
package grpc.testing;
19+
20+
import "grpc/testing/echo_messages.proto";
21+
import "grpc/testing/simple_messages.proto";
22+
23+
service EchoTestService {
24+
rpc Echo(EchoRequest) returns (EchoResponse);
25+
rpc Echo1(EchoRequest) returns (EchoResponse);
26+
rpc Echo2(EchoRequest) returns (EchoResponse);
27+
rpc CheckDeadlineUpperBound(SimpleRequest) returns (StringValue);
28+
rpc CheckDeadlineSet(SimpleRequest) returns (StringValue);
29+
// A service which checks that the initial metadata sent over contains some
30+
// expected key value pair
31+
rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse);
32+
rpc RequestStream(stream EchoRequest) returns (EchoResponse);
33+
rpc ResponseStream(EchoRequest) returns (stream EchoResponse);
34+
rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
35+
rpc Unimplemented(EchoRequest) returns (EchoResponse);
36+
rpc UnimplementedBidi(stream EchoRequest) returns (stream EchoResponse);
37+
}
38+
39+
service EchoTest1Service {
40+
rpc Echo(EchoRequest) returns (EchoResponse);
41+
rpc Echo1(EchoRequest) returns (EchoResponse);
42+
rpc Echo2(EchoRequest) returns (EchoResponse);
43+
// A service which checks that the initial metadata sent over contains some
44+
// expected key value pair
45+
rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse);
46+
rpc RequestStream(stream EchoRequest) returns (EchoResponse);
47+
rpc ResponseStream(EchoRequest) returns (stream EchoResponse);
48+
rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
49+
rpc Unimplemented(EchoRequest) returns (EchoResponse);
50+
}
51+
52+
service EchoTest2Service {
53+
rpc Echo(EchoRequest) returns (EchoResponse);
54+
rpc Echo1(EchoRequest) returns (EchoResponse);
55+
rpc Echo2(EchoRequest) returns (EchoResponse);
56+
// A service which checks that the initial metadata sent over contains some
57+
// expected key value pair
58+
rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse);
59+
rpc RequestStream(stream EchoRequest) returns (EchoResponse);
60+
rpc ResponseStream(EchoRequest) returns (stream EchoResponse);
61+
rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
62+
rpc Unimplemented(EchoRequest) returns (EchoResponse);
63+
}
64+
65+
service UnimplementedEchoService {
66+
rpc Unimplemented(EchoRequest) returns (EchoResponse);
67+
}
68+
69+
// A service without any rpc defined to test coverage.
70+
service NoRpcService {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
2+
// Copyright 2015 gRPC authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
syntax = "proto3";
17+
18+
package grpc.testing;
19+
20+
option cc_enable_arenas = true;
21+
22+
import "grpc/testing/xds/v3/orca_load_report.proto";
23+
24+
// Message to be echoed back serialized in trailer.
25+
message DebugInfo {
26+
repeated string stack_entries = 1;
27+
string detail = 2;
28+
}
29+
30+
// Error status client expects to see.
31+
message ErrorStatus {
32+
int32 code = 1;
33+
string error_message = 2;
34+
string binary_error_details = 3;
35+
}
36+
37+
message RequestParams {
38+
bool echo_deadline = 1;
39+
int32 client_cancel_after_us = 2;
40+
int32 server_cancel_after_us = 3;
41+
bool echo_metadata = 4;
42+
bool check_auth_context = 5;
43+
int32 response_message_length = 6;
44+
bool echo_peer = 7;
45+
string expected_client_identity = 8; // will force check_auth_context.
46+
bool skip_cancelled_check = 9;
47+
string expected_transport_security_type = 10;
48+
DebugInfo debug_info = 11;
49+
bool server_die = 12; // Server should not see a request with this set.
50+
string binary_error_details = 13;
51+
ErrorStatus expected_error = 14;
52+
int32 server_sleep_us = 15; // sleep when invoking server for deadline tests
53+
int32 backend_channel_idx = 16; // which backend to send request to
54+
bool echo_metadata_initially = 17;
55+
bool server_notify_client_when_started = 18;
56+
xds.data.orca.v3.OrcaLoadReport backend_metrics = 19;
57+
bool echo_host_from_authority_header = 20;
58+
}
59+
60+
message EchoRequest {
61+
string message = 1;
62+
RequestParams param = 2;
63+
}
64+
65+
message ResponseParams {
66+
int64 request_deadline = 1;
67+
string host = 2;
68+
string peer = 3;
69+
}
70+
71+
message EchoResponse {
72+
string message = 1;
73+
ResponseParams param = 2;
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
// Copyright 2018 gRPC authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
syntax = "proto3";
17+
18+
package grpc.testing;
19+
20+
message SimpleRequest {}
21+
22+
message SimpleResponse {}
23+
24+
message StringValue {
25+
string message = 1;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2020 The gRPC Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Local copy of Envoy xDS proto file, used for testing only.
16+
17+
syntax = "proto3";
18+
19+
package xds.data.orca.v3;
20+
21+
// See section `ORCA load report format` of the design document in
22+
// :ref:`https://github.com/envoyproxy/envoy/issues/6614`.
23+
24+
message OrcaLoadReport {
25+
// CPU utilization expressed as a fraction of available CPU resources. This
26+
// should be derived from the latest sample or measurement.
27+
double cpu_utilization = 1;
28+
29+
// Memory utilization expressed as a fraction of available memory
30+
// resources. This should be derived from the latest sample or measurement.
31+
double mem_utilization = 2;
32+
33+
// Total RPS being served by an endpoint. This should cover all services that an endpoint is
34+
// responsible for.
35+
uint64 rps = 3;
36+
37+
// Application specific requests costs. Each value is an absolute cost (e.g. 3487 bytes of
38+
// storage) associated with the request.
39+
map<string, double> request_cost = 4;
40+
41+
// Resource utilization values. Each value is expressed as a fraction of total resources
42+
// available, derived from the latest sample or measurement.
43+
map<string, double> utilization = 5;
44+
}

packages/grpc-js-xds/src/load-balancer-cds.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export class CdsLoadBalancer implements LoadBalancer {
125125

126126
private latestConfig: CdsLoadBalancingConfig | null = null;
127127
private latestAttributes: { [key: string]: unknown } = {};
128+
private xdsClient: XdsClient | null = null;
128129

129130
constructor(private readonly channelControlHelper: ChannelControlHelper) {
130131
this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper);
@@ -188,6 +189,7 @@ export class CdsLoadBalancer implements LoadBalancer {
188189
}
189190
trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2));
190191
this.latestAttributes = attributes;
192+
this.xdsClient = attributes.xdsClient as XdsClient;
191193

192194
/* If the cluster is changing, disable the old watcher before adding the new
193195
* one */
@@ -196,7 +198,7 @@ export class CdsLoadBalancer implements LoadBalancer {
196198
this.latestConfig?.getCluster() !== lbConfig.getCluster()
197199
) {
198200
trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster());
199-
getSingletonXdsClient().removeClusterWatcher(
201+
this.xdsClient.removeClusterWatcher(
200202
this.latestConfig!.getCluster(),
201203
this.watcher
202204
);
@@ -212,7 +214,7 @@ export class CdsLoadBalancer implements LoadBalancer {
212214

213215
if (!this.isWatcherActive) {
214216
trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster());
215-
getSingletonXdsClient().addClusterWatcher(lbConfig.getCluster(), this.watcher);
217+
this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher);
216218
this.isWatcherActive = true;
217219
}
218220
}
@@ -226,7 +228,7 @@ export class CdsLoadBalancer implements LoadBalancer {
226228
trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster());
227229
this.childBalancer.destroy();
228230
if (this.isWatcherActive) {
229-
getSingletonXdsClient().removeClusterWatcher(
231+
this.xdsClient?.removeClusterWatcher(
230232
this.latestConfig!.getCluster(),
231233
this.watcher
232234
);

packages/grpc-js-xds/src/load-balancer-eds.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ export class EdsLoadBalancer implements LoadBalancer {
167167

168168
private lastestConfig: EdsLoadBalancingConfig | null = null;
169169
private latestAttributes: { [key: string]: unknown } = {};
170+
private xdsClient: XdsClient | null = null;
170171
private latestEdsUpdate: ClusterLoadAssignment__Output | null = null;
171172

172173
/**
@@ -488,13 +489,14 @@ export class EdsLoadBalancer implements LoadBalancer {
488489
trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2));
489490
this.lastestConfig = lbConfig;
490491
this.latestAttributes = attributes;
492+
this.xdsClient = attributes.xdsClient as XdsClient;
491493
const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster();
492494

493495
/* If the name is changing, disable the old watcher before adding the new
494496
* one */
495497
if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) {
496498
trace('Removing old endpoint watcher for edsServiceName ' + this.edsServiceName)
497-
getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName!, this.watcher);
499+
this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher);
498500
/* Setting isWatcherActive to false here lets us have one code path for
499501
* calling addEndpointWatcher */
500502
this.isWatcherActive = false;
@@ -507,12 +509,12 @@ export class EdsLoadBalancer implements LoadBalancer {
507509

508510
if (!this.isWatcherActive) {
509511
trace('Adding new endpoint watcher for edsServiceName ' + this.edsServiceName);
510-
getSingletonXdsClient().addEndpointWatcher(this.edsServiceName, this.watcher);
512+
this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher);
511513
this.isWatcherActive = true;
512514
}
513515

514516
if (lbConfig.getLrsLoadReportingServerName()) {
515-
this.clusterDropStats = getSingletonXdsClient().addClusterDropStats(
517+
this.clusterDropStats = this.xdsClient.addClusterDropStats(
516518
lbConfig.getLrsLoadReportingServerName()!,
517519
lbConfig.getCluster(),
518520
lbConfig.getEdsServiceName() ?? ''
@@ -533,7 +535,7 @@ export class EdsLoadBalancer implements LoadBalancer {
533535
destroy(): void {
534536
trace('Destroying load balancer with edsServiceName ' + this.edsServiceName);
535537
if (this.edsServiceName) {
536-
getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName, this.watcher);
538+
this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher);
537539
}
538540
this.childBalancer.destroy();
539541
}

packages/grpc-js-xds/src/load-balancer-lrs.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export class LrsLoadBalancer implements LoadBalancer {
169169
if (!(lbConfig instanceof LrsLoadBalancingConfig)) {
170170
return;
171171
}
172-
this.localityStatsReporter = getSingletonXdsClient().addClusterLocalityStats(
172+
this.localityStatsReporter = (attributes.xdsClient as XdsClient).addClusterLocalityStats(
173173
lbConfig.getLrsLoadReportingServerName(),
174174
lbConfig.getClusterName(),
175175
lbConfig.getEdsServiceName(),

0 commit comments

Comments
 (0)