19
19
20
20
import static com .google .common .truth .Truth .assertThat ;
21
21
import static io .grpc .xds .DataPlaneRule .ENDPOINT_HOST_NAME ;
22
+ import static io .grpc .xds .XdsTestControlPlaneService .ADS_TYPE_URL_CDS ;
23
+ import static io .grpc .xds .XdsTestControlPlaneService .ADS_TYPE_URL_EDS ;
22
24
import static org .junit .Assert .assertEquals ;
23
25
24
26
import com .github .xds .type .v3 .TypedStruct ;
27
+ import com .google .common .collect .ImmutableMap ;
25
28
import com .google .protobuf .Any ;
26
29
import com .google .protobuf .Struct ;
27
30
import com .google .protobuf .Value ;
36
39
import io .envoyproxy .envoy .config .endpoint .v3 .Endpoint ;
37
40
import io .envoyproxy .envoy .config .endpoint .v3 .LbEndpoint ;
38
41
import io .envoyproxy .envoy .config .endpoint .v3 .LocalityLbEndpoints ;
42
+ import io .envoyproxy .envoy .config .route .v3 .Route ;
43
+ import io .envoyproxy .envoy .config .route .v3 .RouteAction ;
44
+ import io .envoyproxy .envoy .config .route .v3 .RouteConfiguration ;
45
+ import io .envoyproxy .envoy .config .route .v3 .RouteMatch ;
46
+ import io .envoyproxy .envoy .config .route .v3 .VirtualHost ;
39
47
import io .envoyproxy .envoy .extensions .load_balancing_policies .wrr_locality .v3 .WrrLocality ;
40
48
import io .grpc .CallOptions ;
41
49
import io .grpc .Channel ;
42
50
import io .grpc .ClientCall ;
43
51
import io .grpc .ClientInterceptor ;
52
+ import io .grpc .ClientStreamTracer ;
44
53
import io .grpc .ForwardingClientCall .SimpleForwardingClientCall ;
45
54
import io .grpc .ForwardingClientCallListener ;
46
55
import io .grpc .LoadBalancerRegistry ;
@@ -89,8 +98,7 @@ public void pingPong() throws Exception {
89
98
ManagedChannel channel = dataPlane .getManagedChannel ();
90
99
SimpleServiceGrpc .SimpleServiceBlockingStub blockingStub = SimpleServiceGrpc .newBlockingStub (
91
100
channel );
92
- SimpleRequest request = SimpleRequest .newBuilder ()
93
- .build ();
101
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
94
102
SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
95
103
.setResponseMessage ("Hi, xDS! Authority= test-server" )
96
104
.build ();
@@ -104,8 +112,7 @@ public void pingPong_edsEndpoint_authorityOverride() throws Exception {
104
112
ManagedChannel channel = dataPlane .getManagedChannel ();
105
113
SimpleServiceGrpc .SimpleServiceBlockingStub blockingStub = SimpleServiceGrpc .newBlockingStub (
106
114
channel );
107
- SimpleRequest request = SimpleRequest .newBuilder ()
108
- .build ();
115
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
109
116
SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
110
117
.setResponseMessage ("Hi, xDS! Authority= " + ENDPOINT_HOST_NAME )
111
118
.build ();
@@ -145,8 +152,7 @@ public void pingPong_metadataLoadBalancer() throws Exception {
145
152
// We add an interceptor to catch the response headers from the server.
146
153
SimpleServiceGrpc .SimpleServiceBlockingStub blockingStub = SimpleServiceGrpc .newBlockingStub (
147
154
dataPlane .getManagedChannel ()).withInterceptors (responseHeaderInterceptor );
148
- SimpleRequest request = SimpleRequest .newBuilder ()
149
- .build ();
155
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
150
156
SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
151
157
.setResponseMessage ("Hi, xDS! Authority= test-server" )
152
158
.build ();
@@ -160,6 +166,100 @@ public void pingPong_metadataLoadBalancer() throws Exception {
160
166
}
161
167
}
162
168
169
+ // Try to trigger "UNAVAILABLE: CDS encountered error: unable to find available subchannel for
170
+ // cluster cluster:cluster1" race, if XdsNameResolver updates its ConfigSelector before
171
+ // cluster_manager config.
172
+ @ Test
173
+ public void changeClusterForRoute () throws Exception {
174
+ // Start with route to cluster0
175
+ InetSocketAddress edsInetSocketAddress
176
+ = (InetSocketAddress ) dataPlane .getServer ().getListenSockets ().get (0 );
177
+ controlPlane .getService ().setXdsConfig (
178
+ ADS_TYPE_URL_EDS ,
179
+ ImmutableMap .of (
180
+ "eds-service-0" ,
181
+ ControlPlaneRule .buildClusterLoadAssignment (
182
+ edsInetSocketAddress .getHostName (), "" , edsInetSocketAddress .getPort (),
183
+ "eds-service-0" ),
184
+ "eds-service-1" ,
185
+ ControlPlaneRule .buildClusterLoadAssignment (
186
+ edsInetSocketAddress .getHostName (), "" , edsInetSocketAddress .getPort (),
187
+ "eds-service-1" )));
188
+ controlPlane .getService ().setXdsConfig (
189
+ ADS_TYPE_URL_CDS ,
190
+ ImmutableMap .of (
191
+ "cluster0" ,
192
+ ControlPlaneRule .buildCluster ("cluster0" , "eds-service-0" ),
193
+ "cluster1" ,
194
+ ControlPlaneRule .buildCluster ("cluster1" , "eds-service-1" )));
195
+ controlPlane .setRdsConfig (RouteConfiguration .newBuilder ()
196
+ .setName ("route-config.googleapis.com" )
197
+ .addVirtualHosts (VirtualHost .newBuilder ()
198
+ .addDomains ("test-server" )
199
+ .addRoutes (Route .newBuilder ()
200
+ .setMatch (RouteMatch .newBuilder ().setPrefix ("/" ).build ())
201
+ .setRoute (RouteAction .newBuilder ().setCluster ("cluster0" ).build ())
202
+ .build ())
203
+ .build ())
204
+ .build ());
205
+
206
+ class ClusterClientStreamTracer extends ClientStreamTracer {
207
+ boolean usedCluster1 ;
208
+
209
+ @ Override
210
+ public void addOptionalLabel (String key , String value ) {
211
+ if ("grpc.lb.backend_service" .equals (key )) {
212
+ usedCluster1 = "cluster1" .equals (value );
213
+ }
214
+ }
215
+ }
216
+
217
+ ClusterClientStreamTracer tracer = new ClusterClientStreamTracer ();
218
+ ClientStreamTracer .Factory tracerFactory = new ClientStreamTracer .Factory () {
219
+ @ Override
220
+ public ClientStreamTracer newClientStreamTracer (
221
+ ClientStreamTracer .StreamInfo info , Metadata headers ) {
222
+ return tracer ;
223
+ }
224
+ };
225
+ ClientInterceptor tracerInterceptor = new ClientInterceptor () {
226
+ @ Override
227
+ public <ReqT , RespT > ClientCall <ReqT , RespT > interceptCall (
228
+ MethodDescriptor <ReqT , RespT > method , CallOptions callOptions , Channel next ) {
229
+ return next .newCall (method , callOptions .withStreamTracerFactory (tracerFactory ));
230
+ }
231
+ };
232
+ SimpleServiceGrpc .SimpleServiceBlockingStub stub = SimpleServiceGrpc
233
+ .newBlockingStub (dataPlane .getManagedChannel ())
234
+ .withInterceptors (tracerInterceptor );
235
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
236
+ SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
237
+ .setResponseMessage ("Hi, xDS! Authority= test-server" )
238
+ .build ();
239
+ assertThat (stub .unaryRpc (request )).isEqualTo (goldenResponse );
240
+ assertThat (tracer .usedCluster1 ).isFalse ();
241
+
242
+ // Check for errors when swapping route to cluster1
243
+ controlPlane .setRdsConfig (RouteConfiguration .newBuilder ()
244
+ .setName ("route-config.googleapis.com" )
245
+ .addVirtualHosts (VirtualHost .newBuilder ()
246
+ .addDomains ("test-server" )
247
+ .addRoutes (Route .newBuilder ()
248
+ .setMatch (RouteMatch .newBuilder ().setPrefix ("/" ).build ())
249
+ .setRoute (RouteAction .newBuilder ().setCluster ("cluster1" ).build ())
250
+ .build ())
251
+ .build ())
252
+ .build ());
253
+
254
+ for (int j = 0 ; j < 10 ; j ++) {
255
+ stub .unaryRpc (request );
256
+ if (tracer .usedCluster1 ) {
257
+ break ;
258
+ }
259
+ }
260
+ assertThat (tracer .usedCluster1 ).isTrue ();
261
+ }
262
+
163
263
// Captures response headers from the server.
164
264
private static class ResponseHeaderClientInterceptor implements ClientInterceptor {
165
265
Metadata reponseHeaders ;
@@ -199,8 +299,7 @@ public void pingPong_ringHash() {
199
299
ManagedChannel channel = dataPlane .getManagedChannel ();
200
300
SimpleServiceGrpc .SimpleServiceBlockingStub blockingStub = SimpleServiceGrpc .newBlockingStub (
201
301
channel );
202
- SimpleRequest request = SimpleRequest .newBuilder ()
203
- .build ();
302
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
204
303
SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
205
304
.setResponseMessage ("Hi, xDS! Authority= test-server" )
206
305
.build ();
@@ -231,8 +330,7 @@ public void pingPong_logicalDns_authorityOverride() {
231
330
ManagedChannel channel = dataPlane .getManagedChannel ();
232
331
SimpleServiceGrpc .SimpleServiceBlockingStub blockingStub = SimpleServiceGrpc .newBlockingStub (
233
332
channel );
234
- SimpleRequest request = SimpleRequest .newBuilder ()
235
- .build ();
333
+ SimpleRequest request = SimpleRequest .getDefaultInstance ();
236
334
SimpleResponse goldenResponse = SimpleResponse .newBuilder ()
237
335
.setResponseMessage ("Hi, xDS! Authority= localhost:" + serverAddress .getPort ())
238
336
.build ();
0 commit comments