1919import static com .google .common .truth .Truth .assertThat ;
2020import static io .grpc .xds .XdsNameResolver .CLUSTER_SELECTION_KEY ;
2121import static io .grpc .xds .XdsNameResolver .XDS_CONFIG_CALL_OPTION_KEY ;
22+ import static io .grpc .xds .XdsTestUtils .CLUSTER_NAME ;
23+ import static io .grpc .xds .XdsTestUtils .EDS_NAME ;
24+ import static io .grpc .xds .XdsTestUtils .ENDPOINT_HOSTNAME ;
25+ import static io .grpc .xds .XdsTestUtils .ENDPOINT_PORT ;
26+ import static io .grpc .xds .XdsTestUtils .RDS_NAME ;
27+ import static io .grpc .xds .XdsTestUtils .buildRouteConfiguration ;
28+ import static io .grpc .xds .XdsTestUtils .getWrrLbConfigAsMap ;
2229import static org .junit .Assert .assertEquals ;
2330import static org .junit .Assert .assertNotNull ;
2431import static org .junit .Assert .assertNull ;
2734import static org .mockito .ArgumentMatchers .eq ;
2835import static org .mockito .Mockito .mock ;
2936
37+ import com .google .common .collect .ImmutableList ;
38+ import com .google .common .collect .ImmutableMap ;
3039import com .google .protobuf .Any ;
3140import com .google .protobuf .Empty ;
3241import com .google .protobuf .Message ;
3342import com .google .protobuf .UInt64Value ;
43+ import io .envoyproxy .envoy .config .route .v3 .RouteConfiguration ;
3444import io .envoyproxy .envoy .extensions .filters .http .gcp_authn .v3 .GcpAuthnFilterConfig ;
3545import io .envoyproxy .envoy .extensions .filters .http .gcp_authn .v3 .TokenCacheConfig ;
3646import io .grpc .CallOptions ;
3747import io .grpc .Channel ;
48+ import io .grpc .ClientCall ;
3849import io .grpc .ClientInterceptor ;
3950import io .grpc .MethodDescriptor ;
51+ import io .grpc .Status ;
52+ import io .grpc .StatusOr ;
4053import io .grpc .inprocess .InProcessServerBuilder ;
4154import io .grpc .testing .TestMethodDescriptors ;
55+ import io .grpc .xds .Endpoints .LbEndpoint ;
56+ import io .grpc .xds .Endpoints .LocalityLbEndpoints ;
57+ import io .grpc .xds .GcpAuthenticationFilter .AudienceMetadataParser .AudienceWrapper ;
58+ import io .grpc .xds .GcpAuthenticationFilter .FailingClientCall ;
4259import io .grpc .xds .GcpAuthenticationFilter .GcpAuthenticationConfig ;
60+ import io .grpc .xds .XdsClusterResource .CdsUpdate ;
61+ import io .grpc .xds .XdsConfig .XdsClusterConfig ;
62+ import io .grpc .xds .XdsConfig .XdsClusterConfig .EndpointConfig ;
63+ import io .grpc .xds .client .Locality ;
64+ import io .grpc .xds .client .XdsResourceType ;
65+ import java .util .Collections ;
66+ import java .util .HashMap ;
67+ import java .util .Map ;
4368import org .junit .Test ;
4469import org .junit .runner .RunWith ;
4570import org .junit .runners .JUnit4 ;
@@ -96,9 +121,52 @@ public void testParseFilterConfig_withInvalidMessageType() {
96121 }
97122
98123 @ Test
99- public void testClientInterceptor_createsAndReusesCachedCredentials () throws Exception {
124+ public void testClientInterceptor () throws Exception {
100125 String serverName = InProcessServerBuilder .generateName ();
101- XdsConfig defaultXdsConfig = XdsTestUtils .getDefaultXdsConfigWithCdsUpdate (serverName );
126+ XdsConfig .XdsConfigBuilder builder = new XdsConfig .XdsConfigBuilder ();
127+
128+ Filter .NamedFilterConfig routerFilterConfig = new Filter .NamedFilterConfig (
129+ serverName , RouterFilter .ROUTER_CONFIG );
130+
131+ HttpConnectionManager httpConnectionManager = HttpConnectionManager .forRdsName (
132+ 0L , RDS_NAME , Collections .singletonList (routerFilterConfig ));
133+ XdsListenerResource .LdsUpdate ldsUpdate =
134+ XdsListenerResource .LdsUpdate .forApiListener (httpConnectionManager );
135+
136+ RouteConfiguration routeConfiguration =
137+ buildRouteConfiguration (serverName , RDS_NAME , CLUSTER_NAME );
138+ XdsResourceType .Args args = new XdsResourceType .Args (null , "0" , "0" , null , null , null );
139+ XdsRouteConfigureResource .RdsUpdate rdsUpdate =
140+ XdsRouteConfigureResource .getInstance ().doParse (args , routeConfiguration );
141+
142+ // Take advantage of knowing that there is only 1 virtual host in the route configuration
143+ assertThat (rdsUpdate .virtualHosts ).hasSize (1 );
144+ VirtualHost virtualHost = rdsUpdate .virtualHosts .get (0 );
145+
146+ // Need to create endpoints to create locality endpoints map to create edsUpdate
147+ Map <Locality , LocalityLbEndpoints > lbEndpointsMap = new HashMap <>();
148+ LbEndpoint lbEndpoint = LbEndpoint .create (
149+ serverName , ENDPOINT_PORT , 0 , true , ENDPOINT_HOSTNAME , ImmutableMap .of ());
150+ lbEndpointsMap .put (
151+ Locality .create ("" , "" , "" ),
152+ LocalityLbEndpoints .create (ImmutableList .of (lbEndpoint ), 10 , 0 , ImmutableMap .of ()));
153+
154+ // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder
155+ XdsEndpointResource .EdsUpdate edsUpdate = new XdsEndpointResource .EdsUpdate (
156+ EDS_NAME , lbEndpointsMap , Collections .emptyList ());
157+
158+ // Use ImmutableMap.Builder to construct the map
159+ ImmutableMap .Builder <String , Object > parsedMetadata = ImmutableMap .builder ();
160+ parsedMetadata .put ("FILTER_INSTANCE_NAME" , new AudienceWrapper ("TEST_AUDIENCE" ));
161+
162+ CdsUpdate .Builder cdsUpdate = CdsUpdate .forEds (
163+ CLUSTER_NAME , EDS_NAME , null , null , null , null , false )
164+ .lbPolicyConfig (getWrrLbConfigAsMap ());
165+ cdsUpdate .parsedMetadata (parsedMetadata .build ());
166+ XdsConfig .XdsClusterConfig clusterConfig = new XdsConfig .XdsClusterConfig (
167+ CLUSTER_NAME ,
168+ cdsUpdate .build (),
169+ new EndpointConfig (StatusOr .fromValue (edsUpdate )));
102170
103171 GcpAuthenticationConfig config = new GcpAuthenticationConfig (10 );
104172 GcpAuthenticationFilter filter = new GcpAuthenticationFilter ("FILTER_INSTANCE_NAME" );
@@ -109,17 +177,80 @@ public void testClientInterceptor_createsAndReusesCachedCredentials() throws Exc
109177
110178 // Mock channel and capture CallOptions
111179 Channel mockChannel = mock (Channel .class );
112- ArgumentCaptor <CallOptions > callOptionsCaptor = ArgumentCaptor .forClass (CallOptions .class );
113180
114181 // Set CallOptions with required keys
115- CallOptions callOptionsWithXds = CallOptions .DEFAULT
182+ CallOptions callOptionsWithXds = CallOptions .DEFAULT ;
183+
184+ // Execute interception twice to check caching
185+ ClientCall <Void , Void > call = interceptor .interceptCall (
186+ methodDescriptor , callOptionsWithXds , mockChannel );
187+ assertTrue (call instanceof FailingClientCall );
188+ FailingClientCall <Void , Void > clientCall = (FailingClientCall <Void , Void >) call ;
189+ assertThat (clientCall .error .getDescription ()).contains ("does not contain cluster resource" );
190+
191+ callOptionsWithXds = CallOptions .DEFAULT
192+ .withOption (CLUSTER_SELECTION_KEY , "cluster:cluster0" );
193+
194+ // Execute interception twice to check caching
195+ call = interceptor .interceptCall (methodDescriptor , callOptionsWithXds , mockChannel );
196+ assertTrue (call instanceof FailingClientCall );
197+ clientCall = (FailingClientCall <Void , Void >) call ;
198+ assertThat (clientCall .error .getDescription ()).contains ("does not contain xds configuration" );
199+
200+ XdsConfig defaultXdsConfig = builder
201+ .setListener (ldsUpdate )
202+ .setRoute (rdsUpdate )
203+ .setVirtualHost (virtualHost )
204+ .addCluster (CLUSTER_NAME , StatusOr .fromValue (clusterConfig )).build ();
205+ callOptionsWithXds = CallOptions .DEFAULT
206+ .withOption (CLUSTER_SELECTION_KEY , "cluster:cluster" )
207+ .withOption (XDS_CONFIG_CALL_OPTION_KEY , defaultXdsConfig );
208+
209+ // Execute interception twice to check caching
210+ call = interceptor .interceptCall (methodDescriptor , callOptionsWithXds , mockChannel );
211+ assertTrue (call instanceof FailingClientCall );
212+ clientCall = (FailingClientCall <Void , Void >) call ;
213+ assertThat (clientCall .error .getDescription ()).contains ("does not contain xds cluster" );
214+
215+ StatusOr <XdsClusterConfig > errorCluster =
216+ StatusOr .fromStatus (Status .NOT_FOUND .withDescription ("Cluster resource not found" ));
217+ defaultXdsConfig = builder
218+ .setListener (ldsUpdate )
219+ .setRoute (rdsUpdate )
220+ .setVirtualHost (virtualHost )
221+ .addCluster (CLUSTER_NAME , errorCluster ).build ();
222+ callOptionsWithXds = CallOptions .DEFAULT
223+ .withOption (CLUSTER_SELECTION_KEY , "cluster:cluster0" )
224+ .withOption (XDS_CONFIG_CALL_OPTION_KEY , defaultXdsConfig );
225+
226+ // Create interceptor
227+ interceptor = filter .buildClientInterceptor (config , null , null );
228+ methodDescriptor = TestMethodDescriptors .voidMethod ();
229+
230+ // Mock channel and capture CallOptions
231+ mockChannel = mock (Channel .class );
232+ call = interceptor .interceptCall (methodDescriptor , callOptionsWithXds , mockChannel );
233+ assertTrue (call instanceof FailingClientCall );
234+ clientCall = (FailingClientCall <Void , Void >) call ;
235+ assertThat (clientCall .error .getDescription ())
236+ .contains ("Cluster resource not found" );
237+
238+ // Success case
239+ defaultXdsConfig = builder
240+ .setListener (ldsUpdate )
241+ .setRoute (rdsUpdate )
242+ .setVirtualHost (virtualHost )
243+ .addCluster (CLUSTER_NAME , StatusOr .fromValue (clusterConfig )).build ();
244+ // Set CallOptions with required keys
245+ callOptionsWithXds = CallOptions .DEFAULT
116246 .withOption (CLUSTER_SELECTION_KEY , "cluster:cluster0" )
117247 .withOption (XDS_CONFIG_CALL_OPTION_KEY , defaultXdsConfig );
118248
119249 // Execute interception twice to check caching
120250 interceptor .interceptCall (methodDescriptor , callOptionsWithXds , mockChannel );
121251 interceptor .interceptCall (methodDescriptor , callOptionsWithXds , mockChannel );
122252
253+ ArgumentCaptor <CallOptions > callOptionsCaptor = ArgumentCaptor .forClass (CallOptions .class );
123254 // Capture and verify CallOptions for CallCredentials presence
124255 Mockito .verify (mockChannel , Mockito .times (2 ))
125256 .newCall (eq (methodDescriptor ), callOptionsCaptor .capture ());
0 commit comments