From 3b9f2645d500ddc7f23c1e2df93c763ba0be8d7d Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Fri, 21 Mar 2025 09:35:46 +0000 Subject: [PATCH 1/8] xds: propagate audience from cluster resource in gcp auth filter --- .../io/grpc/xds/GcpAuthenticationFilter.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index add885c6416..b0e540898d9 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -16,6 +16,9 @@ package io.grpc.xds; +import static io.grpc.xds.XdsNameResolver.CLUSTER_SELECTION_KEY; +import static io.grpc.xds.XdsNameResolver.XDS_CONFIG_CALL_OPTION_KEY; + import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.IdTokenCredentials; import com.google.common.primitives.UnsignedLongs; @@ -34,8 +37,11 @@ import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.Status; +import io.grpc.StatusOr; import io.grpc.auth.MoreCallCredentials; import io.grpc.xds.MetadataRegistry.MetadataValueParser; +import io.grpc.xds.XdsClusterResource.CdsUpdate; +import io.grpc.xds.XdsConfig.XdsClusterConfig; import io.grpc.xds.client.XdsResourceType.ResourceInvalidException; import java.util.LinkedHashMap; import java.util.Map; @@ -52,6 +58,8 @@ final class GcpAuthenticationFilter implements Filter { static final String TYPE_URL = "type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig"; + static String filterInstanceName; + static final class Provider implements Filter.Provider { @Override public String[] typeUrls() { @@ -65,6 +73,7 @@ public boolean isClientFilter() { @Override public GcpAuthenticationFilter newInstance(String name) { + filterInstanceName = name; return new GcpAuthenticationFilter(); } @@ -119,17 +128,23 @@ public ClientInterceptor buildClientInterceptor(FilterConfig config, public ClientCall interceptCall( MethodDescriptor method, CallOptions callOptions, Channel next) { - /*String clusterName = callOptions.getOption(XdsAttributes.ATTR_CLUSTER_NAME); - if (clusterName == null) { + String clusterName = callOptions.getOption(CLUSTER_SELECTION_KEY); + if (clusterName.startsWith("cluster_specifier_plugin:")) { return next.newCall(method, callOptions); - }*/ + } - // TODO: Fetch the CDS resource for the cluster. - // If the CDS resource is not available, fail the RPC with Status.UNAVAILABLE. + XdsConfig xdsConfig = callOptions.getOption(XDS_CONFIG_CALL_OPTION_KEY); + StatusOr xdsCluster = xdsConfig.getClusters().get(clusterName); + CdsUpdate cdsUpdate = xdsCluster.getValue().getClusterResource(); + if (cdsUpdate == null) { + // fail the RPC with Status.UNAVAILABLE. + return new FailingClientCall<>(Status.UNAVAILABLE.withDescription("CDS resource unavailable")); + } - // TODO: Extract the audience from the CDS resource metadata. - // If the audience is not found or is in the wrong format, fail the RPC. - String audience = "TEST_AUDIENCE"; + if (!cdsUpdate.filterMetadata().containsKey(filterInstanceName)) { + return next.newCall(method, callOptions); + } + String audience = String.valueOf(cdsUpdate.filterMetadata().get(filterInstanceName)); try { CallCredentials existingCallCredentials = callOptions.getCredentials(); From f2dffe4ce377555a576c2ca4784ee4acad26cc98 Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Tue, 25 Mar 2025 11:38:47 +0000 Subject: [PATCH 2/8] address comments --- .../io/grpc/xds/GcpAuthenticationFilter.java | 49 +++++++++++---- .../grpc/xds/GcpAuthenticationFilterTest.java | 22 +++++-- .../grpc/xds/GrpcXdsClientImplDataTest.java | 15 ++--- .../test/java/io/grpc/xds/XdsTestUtils.java | 59 +++++++++++++++++++ 4 files changed, 120 insertions(+), 25 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index b0e540898d9..fd0d8e3740f 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -39,6 +39,7 @@ import io.grpc.Status; import io.grpc.StatusOr; import io.grpc.auth.MoreCallCredentials; +import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; import io.grpc.xds.MetadataRegistry.MetadataValueParser; import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsConfig.XdsClusterConfig; @@ -58,7 +59,12 @@ final class GcpAuthenticationFilter implements Filter { static final String TYPE_URL = "type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig"; - static String filterInstanceName; + String filterInstanceName; + + GcpAuthenticationFilter(String name) { + filterInstanceName = name; + } + static final class Provider implements Filter.Provider { @Override @@ -73,8 +79,7 @@ public boolean isClientFilter() { @Override public GcpAuthenticationFilter newInstance(String name) { - filterInstanceName = name; - return new GcpAuthenticationFilter(); + return new GcpAuthenticationFilter(name); } @Override @@ -129,27 +134,37 @@ public ClientCall interceptCall( MethodDescriptor method, CallOptions callOptions, Channel next) { String clusterName = callOptions.getOption(CLUSTER_SELECTION_KEY); - if (clusterName.startsWith("cluster_specifier_plugin:")) { + if (!clusterName.startsWith("cluster:")) { return next.newCall(method, callOptions); } - XdsConfig xdsConfig = callOptions.getOption(XDS_CONFIG_CALL_OPTION_KEY); - StatusOr xdsCluster = xdsConfig.getClusters().get(clusterName); + StatusOr xdsCluster = + xdsConfig.getClusters().get(clusterName); + if (!xdsCluster.hasValue()) { + return next.newCall(method, callOptions); + } CdsUpdate cdsUpdate = xdsCluster.getValue().getClusterResource(); if (cdsUpdate == null) { - // fail the RPC with Status.UNAVAILABLE. - return new FailingClientCall<>(Status.UNAVAILABLE.withDescription("CDS resource unavailable")); + return new FailingClientCall<>( + Status.UNAVAILABLE.withDescription("CDS resource unavailable")); } - if (!cdsUpdate.filterMetadata().containsKey(filterInstanceName)) { + if (!cdsUpdate.parsedMetadata().containsKey("FILTER_INSTANCE_NAME")) { return next.newCall(method, callOptions); } - String audience = String.valueOf(cdsUpdate.filterMetadata().get(filterInstanceName)); + + AudienceWrapper audience; + try { + audience = (AudienceWrapper) cdsUpdate.parsedMetadata().get(filterInstanceName); + } catch (ClassCastException e) { + return new FailingClientCall<>( + Status.UNAVAILABLE.withDescription("Invalid CDS Resource")); + } try { CallCredentials existingCallCredentials = callOptions.getCredentials(); CallCredentials newCallCredentials = - getCallCredentials(callCredentialsCache, audience, credentials); + getCallCredentials(callCredentialsCache, audience.audience, credentials); if (existingCallCredentials != null) { callOptions = callOptions.withCallCredentials( new CompositeCallCredentials(existingCallCredentials, newCallCredentials)); @@ -250,13 +265,21 @@ V getOrInsert(K key, Function create) { static class AudienceMetadataParser implements MetadataValueParser { + static final class AudienceWrapper { + final String audience; + + AudienceWrapper(String audience) { + this.audience = audience; + } + } + @Override public String getTypeUrl() { return "type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.Audience"; } @Override - public String parse(Any any) throws ResourceInvalidException { + public AudienceWrapper parse(Any any) throws ResourceInvalidException { Audience audience; try { audience = any.unpack(Audience.class); @@ -268,7 +291,7 @@ public String parse(Any any) throws ResourceInvalidException { throw new ResourceInvalidException( "Audience URL is empty. Metadata value must contain a valid URL."); } - return url; + return new AudienceWrapper(url); } } } diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index 52efaf9bd7b..61839a5f2e8 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -17,12 +17,15 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; +import static io.grpc.xds.XdsNameResolver.CLUSTER_SELECTION_KEY; +import static io.grpc.xds.XdsNameResolver.XDS_CONFIG_CALL_OPTION_KEY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import com.google.protobuf.Any; import com.google.protobuf.Empty; @@ -34,6 +37,7 @@ import io.grpc.Channel; import io.grpc.ClientInterceptor; import io.grpc.MethodDescriptor; +import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.testing.TestMethodDescriptors; import io.grpc.xds.GcpAuthenticationFilter.GcpAuthenticationConfig; import org.junit.Test; @@ -92,21 +96,29 @@ public void testParseFilterConfig_withInvalidMessageType() { } @Test - public void testClientInterceptor_createsAndReusesCachedCredentials() { + public void testClientInterceptor_createsAndReusesCachedCredentials() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig defaultXdsConfig = XdsTestUtils.getDefaultXdsConfigWithCdsUpdate(serverName); + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); - GcpAuthenticationFilter filter = new GcpAuthenticationFilter(); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); // Mock channel and capture CallOptions - Channel mockChannel = Mockito.mock(Channel.class); + Channel mockChannel = mock(Channel.class); ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); + // Set CallOptions with required keys + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + // Execute interception twice to check caching - interceptor.interceptCall(methodDescriptor, CallOptions.DEFAULT, mockChannel); - interceptor.interceptCall(methodDescriptor, CallOptions.DEFAULT, mockChannel); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); // Capture and verify CallOptions for CallCredentials presence Mockito.verify(mockChannel, Mockito.times(2)) diff --git a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java index bfaa17245cf..e53ed9047ca 100644 --- a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java @@ -129,6 +129,7 @@ import io.grpc.xds.Endpoints.LbEndpoint; import io.grpc.xds.Endpoints.LocalityLbEndpoints; import io.grpc.xds.Filter.FilterConfig; +import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; import io.grpc.xds.MetadataRegistry.MetadataValueParser; import io.grpc.xds.RouteLookupServiceClusterSpecifierPlugin.RlsPluginConfig; import io.grpc.xds.VirtualHost.Route; @@ -2417,8 +2418,7 @@ public Object parse(Any value) { } @Test - public void processCluster_parsesAudienceMetadata() - throws ResourceInvalidException, InvalidProtocolBufferException { + public void processCluster_parsesAudienceMetadata() throws Exception { MetadataRegistry.getInstance(); Audience audience = Audience.newBuilder() @@ -2462,7 +2462,10 @@ public void processCluster_parsesAudienceMetadata() "FILTER_METADATA", ImmutableMap.of( "key1", "value1", "key2", 42.0)); - assertThat(update.parsedMetadata()).isEqualTo(expectedParsedMetadata); + assertThat(update.parsedMetadata().get("FILTER_METADATA")) + .isEqualTo(expectedParsedMetadata.get("FILTER_METADATA")); + assertThat(update.parsedMetadata().get("AUDIENCE_METADATA")) + .isInstanceOf(AudienceWrapper.class); } @Test @@ -2519,8 +2522,7 @@ public void processCluster_parsesAddressMetadata() throws Exception { } @Test - public void processCluster_metadataKeyCollision_resolvesToTypedMetadata() - throws ResourceInvalidException, InvalidProtocolBufferException { + public void processCluster_metadataKeyCollision_resolvesToTypedMetadata() throws Exception { MetadataRegistry metadataRegistry = MetadataRegistry.getInstance(); MetadataValueParser testParser = @@ -2575,8 +2577,7 @@ public Object parse(Any value) { } @Test - public void parseNonAggregateCluster_withHttp11ProxyTransportSocket() - throws ResourceInvalidException, InvalidProtocolBufferException { + public void parseNonAggregateCluster_withHttp11ProxyTransportSocket() throws Exception { XdsClusterResource.isEnabledXdsHttpConnect = true; Http11ProxyUpstreamTransport http11ProxyUpstreamTransport = diff --git a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java index 9f90777be3d..dc8ccc407dd 100644 --- a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java +++ b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java @@ -56,6 +56,8 @@ import io.grpc.stub.StreamObserver; import io.grpc.xds.Endpoints.LbEndpoint; import io.grpc.xds.Endpoints.LocalityLbEndpoints; +import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; +import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; import io.grpc.xds.client.Bootstrapper; import io.grpc.xds.client.Locality; @@ -280,6 +282,63 @@ static XdsConfig getDefaultXdsConfig(String serverHostName) return builder.build(); } + static XdsConfig getDefaultXdsConfigWithCdsUpdate(String serverHostName) + throws XdsResourceType.ResourceInvalidException, IOException { + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverHostName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverHostName, RDS_NAME, CLUSTER_NAME); + Bootstrapper.ServerInfo serverInfo = null; + XdsResourceType.Args args = new XdsResourceType.Args(serverInfo, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverHostName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, serverInfo, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + "cluster:" + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); + + builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster("cluster:" + CLUSTER_NAME, StatusOr.fromValue(clusterConfig)); + + return builder.build(); + } + static Map createMinimalLbEndpointsMap(String serverHostName) { Map lbEndpointsMap = new HashMap<>(); LbEndpoint lbEndpoint = LbEndpoint.create( From cf09105c2d508040b5588888144ec0b3ece91c2a Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Tue, 25 Mar 2025 17:11:53 +0000 Subject: [PATCH 3/8] address comments --- .../io/grpc/xds/GcpAuthenticationFilter.java | 57 ++++++++++++++----- .../test/java/io/grpc/xds/XdsTestUtils.java | 6 +- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index fd0d8e3740f..e1d193a7e59 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -16,11 +16,13 @@ package io.grpc.xds; +import static com.google.common.base.Preconditions.checkNotNull; import static io.grpc.xds.XdsNameResolver.CLUSTER_SELECTION_KEY; import static io.grpc.xds.XdsNameResolver.XDS_CONFIG_CALL_OPTION_KEY; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.IdTokenCredentials; +import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLongs; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; @@ -41,7 +43,6 @@ import io.grpc.auth.MoreCallCredentials; import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; import io.grpc.xds.MetadataRegistry.MetadataValueParser; -import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsConfig.XdsClusterConfig; import io.grpc.xds.client.XdsResourceType.ResourceInvalidException; import java.util.LinkedHashMap; @@ -59,10 +60,10 @@ final class GcpAuthenticationFilter implements Filter { static final String TYPE_URL = "type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig"; - String filterInstanceName; + final String filterInstanceName; GcpAuthenticationFilter(String name) { - filterInstanceName = name; + filterInstanceName = checkNotNull(name, "name"); } @@ -134,31 +135,59 @@ public ClientCall interceptCall( MethodDescriptor method, CallOptions callOptions, Channel next) { String clusterName = callOptions.getOption(CLUSTER_SELECTION_KEY); + if (clusterName == null) { + return new FailingClientCall<>( + Status.UNAVAILABLE.withDescription( + String.format( + "GCP Authn for %s does not contain cluster resource", filterInstanceName))); + } + if (!clusterName.startsWith("cluster:")) { return next.newCall(method, callOptions); } XdsConfig xdsConfig = callOptions.getOption(XDS_CONFIG_CALL_OPTION_KEY); + if (xdsConfig == null) { + return new FailingClientCall<>( + Status.UNAVAILABLE.withDescription( + String.format( + "GCP Authn for %s with %s does not contain xds configuration", + filterInstanceName, clusterName))); + } + StatusOr xdsCluster = - xdsConfig.getClusters().get(clusterName); + xdsConfig.getClusters().get(clusterName.substring(8)); // get rid of prefix "cluster:" + if (xdsCluster == null) { + return new FailingClientCall<>( + Status.UNAVAILABLE.withDescription( + String.format( + "GCP Authn for %s with %s does not contain xds cluster", + filterInstanceName, clusterName))); + } + if (!xdsCluster.hasValue()) { return next.newCall(method, callOptions); } - CdsUpdate cdsUpdate = xdsCluster.getValue().getClusterResource(); - if (cdsUpdate == null) { - return new FailingClientCall<>( - Status.UNAVAILABLE.withDescription("CDS resource unavailable")); - } + ImmutableMap parsedMetadata = xdsCluster.getValue().getClusterResource() + .parsedMetadata(); - if (!cdsUpdate.parsedMetadata().containsKey("FILTER_INSTANCE_NAME")) { + if (parsedMetadata == null || !parsedMetadata.containsKey(filterInstanceName)) { return next.newCall(method, callOptions); } AudienceWrapper audience; - try { - audience = (AudienceWrapper) cdsUpdate.parsedMetadata().get(filterInstanceName); - } catch (ClassCastException e) { + if (parsedMetadata.get(filterInstanceName) instanceof AudienceWrapper) { + audience = (AudienceWrapper) parsedMetadata.get(filterInstanceName); + if (audience.audience == null) { + return next.newCall(method, callOptions); + } + } + else { return new FailingClientCall<>( - Status.UNAVAILABLE.withDescription("Invalid CDS Resource")); + Status.UNAVAILABLE.withDescription( + String.format("GCP Authn found wrong type in %s metadata: %s=%s", + clusterName, filterInstanceName, + parsedMetadata.get(filterInstanceName) == null + ? null : parsedMetadata.get(filterInstanceName)))); } try { diff --git a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java index dc8ccc407dd..2cd2b4086d5 100644 --- a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java +++ b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java @@ -322,11 +322,11 @@ static XdsConfig getDefaultXdsConfigWithCdsUpdate(String serverHostName) parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, serverInfo, null, null, null, false) + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) .lbPolicyConfig(getWrrLbConfigAsMap()); cdsUpdate.parsedMetadata(parsedMetadata.build()); XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( - "cluster:" + CLUSTER_NAME, + CLUSTER_NAME, cdsUpdate.build(), new EndpointConfig(StatusOr.fromValue(edsUpdate))); @@ -334,7 +334,7 @@ static XdsConfig getDefaultXdsConfigWithCdsUpdate(String serverHostName) .setListener(ldsUpdate) .setRoute(rdsUpdate) .setVirtualHost(virtualHost) - .addCluster("cluster:" + CLUSTER_NAME, StatusOr.fromValue(clusterConfig)); + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)); return builder.build(); } From e6be504c32e6696a24a3c33e8409d588a62e9a6e Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Wed, 26 Mar 2025 06:01:14 +0000 Subject: [PATCH 4/8] address comments --- .../io/grpc/xds/GcpAuthenticationFilter.java | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index e1d193a7e59..6bec74289e8 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -22,7 +22,6 @@ import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.IdTokenCredentials; -import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLongs; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; @@ -155,40 +154,37 @@ public ClientCall interceptCall( } StatusOr xdsCluster = - xdsConfig.getClusters().get(clusterName.substring(8)); // get rid of prefix "cluster:" + xdsConfig.getClusters().get(clusterName.substring("cluster:".length())); if (xdsCluster == null) { return new FailingClientCall<>( Status.UNAVAILABLE.withDescription( String.format( - "GCP Authn for %s with %s does not contain xds cluster", + "GCP Authn for %s with %s - xds cluster config does not contain xds cluster", filterInstanceName, clusterName))); } if (!xdsCluster.hasValue()) { - return next.newCall(method, callOptions); + return new FailingClientCall<>( + xdsCluster.getStatus().withDescription( + String.format( + "GCP Authn for %s with %s - xds cluster does not contain cluster resource", + filterInstanceName, clusterName))); } - ImmutableMap parsedMetadata = xdsCluster.getValue().getClusterResource() - .parsedMetadata(); - if (parsedMetadata == null || !parsedMetadata.containsKey(filterInstanceName)) { + Object audienceObj = + xdsCluster.getValue().getClusterResource().parsedMetadata().get(filterInstanceName); + if (audienceObj == null) { return next.newCall(method, callOptions); } - AudienceWrapper audience; - if (parsedMetadata.get(filterInstanceName) instanceof AudienceWrapper) { - audience = (AudienceWrapper) parsedMetadata.get(filterInstanceName); - if (audience.audience == null) { - return next.newCall(method, callOptions); - } - } - else { + if (!(audienceObj instanceof AudienceWrapper)) { return new FailingClientCall<>( Status.UNAVAILABLE.withDescription( String.format("GCP Authn found wrong type in %s metadata: %s=%s", clusterName, filterInstanceName, - parsedMetadata.get(filterInstanceName) == null - ? null : parsedMetadata.get(filterInstanceName)))); + audienceObj == null ? null : audienceObj.getClass()))); } + AudienceWrapper audience = (AudienceWrapper) audienceObj; try { CallCredentials existingCallCredentials = callOptions.getCredentials(); @@ -298,7 +294,7 @@ static final class AudienceWrapper { final String audience; AudienceWrapper(String audience) { - this.audience = audience; + this.audience = checkNotNull(audience); } } From bcec5d027509c6720c9888765d00aba6a4b25be8 Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Wed, 26 Mar 2025 15:38:53 +0000 Subject: [PATCH 5/8] address comments and add test for failure cases --- .../io/grpc/xds/GcpAuthenticationFilter.java | 13 +- .../grpc/xds/GcpAuthenticationFilterTest.java | 139 +++++++++++++++++- .../test/java/io/grpc/xds/XdsTestUtils.java | 61 +------- 3 files changed, 142 insertions(+), 71 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index 6bec74289e8..786b47016b1 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -22,6 +22,7 @@ import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.IdTokenCredentials; +import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.UnsignedLongs; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; @@ -164,11 +165,7 @@ public ClientCall interceptCall( } if (!xdsCluster.hasValue()) { - return new FailingClientCall<>( - xdsCluster.getStatus().withDescription( - String.format( - "GCP Authn for %s with %s - xds cluster does not contain cluster resource", - filterInstanceName, clusterName))); + return new FailingClientCall<>(xdsCluster.getStatus()); } Object audienceObj = @@ -241,9 +238,11 @@ public String typeUrl() { } /** An implementation of {@link ClientCall} that fails when started. */ - private static final class FailingClientCall extends ClientCall { + @VisibleForTesting + static final class FailingClientCall extends ClientCall { - private final Status error; + @VisibleForTesting + final Status error; public FailingClientCall(Status error) { this.error = error; diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index 61839a5f2e8..aeb487412af 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -19,6 +19,13 @@ import static com.google.common.truth.Truth.assertThat; import static io.grpc.xds.XdsNameResolver.CLUSTER_SELECTION_KEY; import static io.grpc.xds.XdsNameResolver.XDS_CONFIG_CALL_OPTION_KEY; +import static io.grpc.xds.XdsTestUtils.CLUSTER_NAME; +import static io.grpc.xds.XdsTestUtils.EDS_NAME; +import static io.grpc.xds.XdsTestUtils.ENDPOINT_HOSTNAME; +import static io.grpc.xds.XdsTestUtils.ENDPOINT_PORT; +import static io.grpc.xds.XdsTestUtils.RDS_NAME; +import static io.grpc.xds.XdsTestUtils.buildRouteConfiguration; +import static io.grpc.xds.XdsTestUtils.getWrrLbConfigAsMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -27,19 +34,37 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; import com.google.protobuf.Empty; import com.google.protobuf.Message; import com.google.protobuf.UInt64Value; +import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; import io.envoyproxy.envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig; import io.envoyproxy.envoy.extensions.filters.http.gcp_authn.v3.TokenCacheConfig; import io.grpc.CallOptions; import io.grpc.Channel; +import io.grpc.ClientCall; import io.grpc.ClientInterceptor; import io.grpc.MethodDescriptor; +import io.grpc.Status; +import io.grpc.StatusOr; import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.testing.TestMethodDescriptors; +import io.grpc.xds.Endpoints.LbEndpoint; +import io.grpc.xds.Endpoints.LocalityLbEndpoints; +import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; +import io.grpc.xds.GcpAuthenticationFilter.FailingClientCall; import io.grpc.xds.GcpAuthenticationFilter.GcpAuthenticationConfig; +import io.grpc.xds.XdsClusterResource.CdsUpdate; +import io.grpc.xds.XdsConfig.XdsClusterConfig; +import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; +import io.grpc.xds.client.Locality; +import io.grpc.xds.client.XdsResourceType; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -96,9 +121,52 @@ public void testParseFilterConfig_withInvalidMessageType() { } @Test - public void testClientInterceptor_createsAndReusesCachedCredentials() throws Exception { + public void testClientInterceptor() throws Exception { String serverName = InProcessServerBuilder.generateName(); - XdsConfig defaultXdsConfig = XdsTestUtils.getDefaultXdsConfigWithCdsUpdate(serverName); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); @@ -109,10 +177,72 @@ public void testClientInterceptor_createsAndReusesCachedCredentials() throws Exc // Mock channel and capture CallOptions Channel mockChannel = mock(Channel.class); - ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); // Set CallOptions with required keys - CallOptions callOptionsWithXds = CallOptions.DEFAULT + CallOptions callOptionsWithXds = CallOptions.DEFAULT; + + // Execute interception twice to check caching + ClientCall call = interceptor.interceptCall( + methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + FailingClientCall clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("does not contain cluster resource"); + + callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0"); + + // Execute interception twice to check caching + call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("does not contain xds configuration"); + + XdsConfig defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + // Execute interception twice to check caching + call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("does not contain xds cluster"); + + StatusOr errorCluster = + StatusOr.fromStatus(Status.NOT_FOUND.withDescription("Cluster resource not found")); + defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, errorCluster).build(); + callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + // Create interceptor + interceptor = filter.buildClientInterceptor(config, null, null); + methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + mockChannel = mock(Channel.class); + call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()) + .contains("Cluster resource not found"); + + // Success case + defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + // Set CallOptions with required keys + callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); @@ -120,6 +250,7 @@ public void testClientInterceptor_createsAndReusesCachedCredentials() throws Exc interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); // Capture and verify CallOptions for CallCredentials presence Mockito.verify(mockChannel, Mockito.times(2)) .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); diff --git a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java index 2cd2b4086d5..52953ef5407 100644 --- a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java +++ b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java @@ -56,8 +56,6 @@ import io.grpc.stub.StreamObserver; import io.grpc.xds.Endpoints.LbEndpoint; import io.grpc.xds.Endpoints.LocalityLbEndpoints; -import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser.AudienceWrapper; -import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; import io.grpc.xds.client.Bootstrapper; import io.grpc.xds.client.Locality; @@ -282,63 +280,6 @@ static XdsConfig getDefaultXdsConfig(String serverHostName) return builder.build(); } - static XdsConfig getDefaultXdsConfigWithCdsUpdate(String serverHostName) - throws XdsResourceType.ResourceInvalidException, IOException { - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverHostName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverHostName, RDS_NAME, CLUSTER_NAME); - Bootstrapper.ServerInfo serverInfo = null; - XdsResourceType.Args args = new XdsResourceType.Args(serverInfo, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverHostName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); - XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( - CLUSTER_NAME, - cdsUpdate.build(), - new EndpointConfig(StatusOr.fromValue(edsUpdate))); - - builder - .setListener(ldsUpdate) - .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) - .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)); - - return builder.build(); - } - static Map createMinimalLbEndpointsMap(String serverHostName) { Map lbEndpointsMap = new HashMap<>(); LbEndpoint lbEndpoint = LbEndpoint.create( @@ -350,7 +291,7 @@ static Map createMinimalLbEndpointsMap(String ser } @SuppressWarnings("unchecked") - private static ImmutableMap getWrrLbConfigAsMap() throws IOException { + static ImmutableMap getWrrLbConfigAsMap() throws IOException { String lbConfigStr = "{\"wrr_locality_experimental\" : " + "{ \"childPolicy\" : [{\"round_robin\" : {}}]}}"; From 0236a04d629ff547a4b0e8adb54df6d5c1b38168 Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Tue, 1 Apr 2025 16:47:53 +0000 Subject: [PATCH 6/8] Fix unit tests --- .../io/grpc/xds/GcpAuthenticationFilter.java | 3 +- .../grpc/xds/GcpAuthenticationFilterTest.java | 499 ++++++++++++++++-- 2 files changed, 452 insertions(+), 50 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index 786b47016b1..14c191f0957 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -178,8 +178,7 @@ public ClientCall interceptCall( return new FailingClientCall<>( Status.UNAVAILABLE.withDescription( String.format("GCP Authn found wrong type in %s metadata: %s=%s", - clusterName, filterInstanceName, - audienceObj == null ? null : audienceObj.getClass()))); + clusterName, filterInstanceName, audienceObj.getClass()))); } AudienceWrapper audience = (AudienceWrapper) audienceObj; diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index aeb487412af..0ec6498a3d8 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -27,12 +27,14 @@ import static io.grpc.xds.XdsTestUtils.buildRouteConfiguration; import static io.grpc.xds.XdsTestUtils.getWrrLbConfigAsMap; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -62,6 +64,8 @@ import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; import io.grpc.xds.client.Locality; import io.grpc.xds.client.XdsResourceType; +import io.grpc.xds.client.XdsResourceType.ResourceInvalidException; +import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -121,7 +125,8 @@ public void testParseFilterConfig_withInvalidMessageType() { } @Test - public void testClientInterceptor() throws Exception { + public void testClientInterceptor_success() + throws IOException, ResourceInvalidException { String serverName = InProcessServerBuilder.generateName(); XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); @@ -168,6 +173,229 @@ public void testClientInterceptor() throws Exception { cdsUpdate.build(), new EndpointConfig(StatusOr.fromValue(edsUpdate))); + XdsConfig defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + // Set CallOptions with required keys + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = Mockito.mock(Channel.class); + ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); + + // Execute interception twice to check caching + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + + // Capture and verify CallOptions for CallCredentials presence + verify(mockChannel, Mockito.times(1)) + .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); + + // Retrieve the CallOptions captured from both calls + CallOptions capturedOptions = callOptionsCaptor.getAllValues().get(0); + + // Ensure that CallCredentials was added + assertNotNull(capturedOptions.getCredentials()); + } + + @Test + public void testClientInterceptor_createsAndReusesCachedCredentials() + throws IOException, ResourceInvalidException { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); + + XdsConfig defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + // Set CallOptions with required keys + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = Mockito.mock(Channel.class); + ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); + + // Execute interception twice to check caching + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + + // Capture and verify CallOptions for CallCredentials presence + verify(mockChannel, Mockito.times(2)) + .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); + + // Retrieve the CallOptions captured from both calls + CallOptions firstCapturedOptions = callOptionsCaptor.getAllValues().get(0); + CallOptions secondCapturedOptions = callOptionsCaptor.getAllValues().get(1); + + // Ensure that CallCredentials was added + assertNotNull(firstCapturedOptions.getCredentials()); + assertNotNull(secondCapturedOptions.getCredentials()); + + // Ensure that the CallCredentials from both calls are the same, indicating caching + assertSame(firstCapturedOptions.getCredentials(), secondCapturedOptions.getCredentials()); + } + + @Test + public void testClientInterceptor_notAudienceWrapper() + throws IOException, ResourceInvalidException { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", "TEST_AUDIENCE"); // not AudienceWrapper + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); + + XdsConfig defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + // Set CallOptions with required keys + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = Mockito.mock(Channel.class); + + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + FailingClientCall clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("GCP Authn found wrong type"); + } + + @Test + public void testClientInterceptor_withoutClusterSelectionKey() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); @@ -187,83 +415,258 @@ public void testClientInterceptor() throws Exception { assertTrue(call instanceof FailingClientCall); FailingClientCall clientCall = (FailingClientCall) call; assertThat(clientCall.error.getDescription()).contains("does not contain cluster resource"); + } + + @Test + public void testClientInterceptor_clusterSelectionKeyWithoutPrefix() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - callOptionsWithXds = CallOptions.DEFAULT + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = mock(Channel.class); + + XdsConfig defaultXdsConfig = builder + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(virtualHost) + .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + + // Execute interception twice to check caching + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertFalse(call instanceof FailingClientCall); + verify(mockChannel).newCall(methodDescriptor, callOptionsWithXds); + } + + @Test + public void testClientInterceptor_xdsConfigDoesNotExist() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = mock(Channel.class); + + CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0"); // Execute interception twice to check caching - call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); assertTrue(call instanceof FailingClientCall); - clientCall = (FailingClientCall) call; + FailingClientCall clientCall = (FailingClientCall) call; assertThat(clientCall.error.getDescription()).contains("does not contain xds configuration"); + } + + @Test + public void testClientInterceptor_incorrectClusterName() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Need to create endpoints to create locality endpoints map to create edsUpdate + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + + // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder + XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( + EDS_NAME, lbEndpointsMap, Collections.emptyList()); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( + CLUSTER_NAME, + cdsUpdate.build(), + new EndpointConfig(StatusOr.fromValue(edsUpdate))); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + + // Create interceptor + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + + // Mock channel and capture CallOptions + Channel mockChannel = mock(Channel.class); XdsConfig defaultXdsConfig = builder .setListener(ldsUpdate) .setRoute(rdsUpdate) .setVirtualHost(virtualHost) .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - callOptionsWithXds = CallOptions.DEFAULT + CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); // Execute interception twice to check caching - call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); assertTrue(call instanceof FailingClientCall); - clientCall = (FailingClientCall) call; + FailingClientCall clientCall = (FailingClientCall) call; assertThat(clientCall.error.getDescription()).contains("does not contain xds cluster"); + } - StatusOr errorCluster = - StatusOr.fromStatus(Status.NOT_FOUND.withDescription("Cluster resource not found")); - defaultXdsConfig = builder - .setListener(ldsUpdate) - .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) - .addCluster(CLUSTER_NAME, errorCluster).build(); - callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") - .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + @Test + public void testClientInterceptor_statusOrError() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); + + Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( + serverName, RouterFilter.ROUTER_CONFIG); + + HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( + 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); + XdsListenerResource.LdsUpdate ldsUpdate = + XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + + RouteConfiguration routeConfiguration = + buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); + XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); + XdsRouteConfigureResource.RdsUpdate rdsUpdate = + XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + + // Take advantage of knowing that there is only 1 virtual host in the route configuration + assertThat(rdsUpdate.virtualHosts).hasSize(1); + VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + + // Use ImmutableMap.Builder to construct the map + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + cdsUpdate.parsedMetadata(parsedMetadata.build()); + + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); // Create interceptor - interceptor = filter.buildClientInterceptor(config, null, null); - methodDescriptor = TestMethodDescriptors.voidMethod(); + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); // Mock channel and capture CallOptions - mockChannel = mock(Channel.class); - call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - assertTrue(call instanceof FailingClientCall); - clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()) - .contains("Cluster resource not found"); + Channel mockChannel = mock(Channel.class); - // Success case - defaultXdsConfig = builder + StatusOr errorCluster = + StatusOr.fromStatus(Status.NOT_FOUND.withDescription("Cluster resource not found")); + XdsConfig defaultXdsConfig = builder .setListener(ldsUpdate) .setRoute(rdsUpdate) .setVirtualHost(virtualHost) - .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - // Set CallOptions with required keys - callOptionsWithXds = CallOptions.DEFAULT + .addCluster(CLUSTER_NAME, errorCluster).build(); + CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); // Execute interception twice to check caching - interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - - ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); - // Capture and verify CallOptions for CallCredentials presence - Mockito.verify(mockChannel, Mockito.times(2)) - .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); - - // Retrieve the CallOptions captured from both calls - CallOptions firstCapturedOptions = callOptionsCaptor.getAllValues().get(0); - CallOptions secondCapturedOptions = callOptionsCaptor.getAllValues().get(1); - - // Ensure that CallCredentials was added - assertNotNull(firstCapturedOptions.getCredentials()); - assertNotNull(secondCapturedOptions.getCredentials()); - - // Ensure that the CallCredentials from both calls are the same, indicating caching - assertSame(firstCapturedOptions.getCredentials(), secondCapturedOptions.getCredentials()); + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); + FailingClientCall clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("Cluster resource not found"); } } From a845f3d5ad2c14ee91f5f200cf4b3388b8dd4c3e Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Wed, 2 Apr 2025 08:58:10 +0000 Subject: [PATCH 7/8] fix unit tests --- .../io/grpc/xds/GcpAuthenticationFilter.java | 29 +- .../grpc/xds/GcpAuthenticationFilterTest.java | 525 ++++-------------- 2 files changed, 131 insertions(+), 423 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index 14c191f0957..b5568efe400 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -153,7 +153,6 @@ public ClientCall interceptCall( "GCP Authn for %s with %s does not contain xds configuration", filterInstanceName, clusterName))); } - StatusOr xdsCluster = xdsConfig.getClusters().get(clusterName.substring("cluster:".length())); if (xdsCluster == null) { @@ -163,17 +162,14 @@ public ClientCall interceptCall( "GCP Authn for %s with %s - xds cluster config does not contain xds cluster", filterInstanceName, clusterName))); } - if (!xdsCluster.hasValue()) { return new FailingClientCall<>(xdsCluster.getStatus()); } - Object audienceObj = xdsCluster.getValue().getClusterResource().parsedMetadata().get(filterInstanceName); if (audienceObj == null) { return next.newCall(method, callOptions); } - if (!(audienceObj instanceof AudienceWrapper)) { return new FailingClientCall<>( Status.UNAVAILABLE.withDescription( @@ -181,23 +177,14 @@ public ClientCall interceptCall( clusterName, filterInstanceName, audienceObj.getClass()))); } AudienceWrapper audience = (AudienceWrapper) audienceObj; - - try { - CallCredentials existingCallCredentials = callOptions.getCredentials(); - CallCredentials newCallCredentials = - getCallCredentials(callCredentialsCache, audience.audience, credentials); - if (existingCallCredentials != null) { - callOptions = callOptions.withCallCredentials( - new CompositeCallCredentials(existingCallCredentials, newCallCredentials)); - } else { - callOptions = callOptions.withCallCredentials(newCallCredentials); - } - } - catch (Exception e) { - // If we fail to attach CallCredentials due to any reason, return a FailingClientCall - return new FailingClientCall<>(Status.UNAUTHENTICATED - .withDescription("Failed to attach CallCredentials.") - .withCause(e)); + CallCredentials existingCallCredentials = callOptions.getCredentials(); + CallCredentials newCallCredentials = + getCallCredentials(callCredentialsCache, audience.audience, credentials); + if (existingCallCredentials != null) { + callOptions = callOptions.withCallCredentials( + new CompositeCallCredentials(existingCallCredentials, newCallCredentials)); + } else { + callOptions = callOptions.withCallCredentials(newCallCredentials); } return next.newCall(method, callOptions); } diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index 0ec6498a3d8..a476f54e1ac 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -27,7 +27,6 @@ import static io.grpc.xds.XdsTestUtils.buildRouteConfiguration; import static io.grpc.xds.XdsTestUtils.getWrrLbConfigAsMap; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; @@ -62,6 +61,9 @@ import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsConfig.XdsClusterConfig; import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; +import io.grpc.xds.XdsEndpointResource.EdsUpdate; +import io.grpc.xds.XdsListenerResource.LdsUpdate; +import io.grpc.xds.XdsRouteConfigureResource.RdsUpdate; import io.grpc.xds.client.Locality; import io.grpc.xds.client.XdsResourceType; import io.grpc.xds.client.XdsResourceType.ResourceInvalidException; @@ -79,6 +81,17 @@ public class GcpAuthenticationFilterTest { private static final GcpAuthenticationFilter.Provider FILTER_PROVIDER = new GcpAuthenticationFilter.Provider(); + private static final String serverName = InProcessServerBuilder.generateName(); + private static final LdsUpdate ldsUpdate = getLdsUpdate(); + private static final EdsUpdate edsUpdate = getEdsUpdate(); + private static final RdsUpdate rdsUpdate = getRdsUpdate(); + private static final CdsUpdate cdsUpdate = getCdsUpdate(); + + @Test + public void testNewFilterInstancesPerFilterName() { + assertThat(new GcpAuthenticationFilter("FILTER_INSTANCE_NAME1")) + .isNotEqualTo(new GcpAuthenticationFilter("FILTER_INSTANCE_NAME1")); + } @Test public void filterType_clientOnly() { @@ -125,548 +138,256 @@ public void testParseFilterConfig_withInvalidMessageType() { } @Test - public void testClientInterceptor_success() - throws IOException, ResourceInvalidException { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); + public void testClientInterceptor_success() throws IOException, ResourceInvalidException { XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( CLUSTER_NAME, - cdsUpdate.build(), + cdsUpdate, new EndpointConfig(StatusOr.fromValue(edsUpdate))); - - XdsConfig defaultXdsConfig = builder + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() .setListener(ldsUpdate) .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - // Set CallOptions with required keys CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions Channel mockChannel = Mockito.mock(Channel.class); ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); - - // Execute interception twice to check caching interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - // Capture and verify CallOptions for CallCredentials presence - verify(mockChannel, Mockito.times(1)) - .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); - - // Retrieve the CallOptions captured from both calls + verify(mockChannel).newCall(eq(methodDescriptor), callOptionsCaptor.capture()); CallOptions capturedOptions = callOptionsCaptor.getAllValues().get(0); - - // Ensure that CallCredentials was added assertNotNull(capturedOptions.getCredentials()); } @Test public void testClientInterceptor_createsAndReusesCachedCredentials() throws IOException, ResourceInvalidException { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( CLUSTER_NAME, - cdsUpdate.build(), + cdsUpdate, new EndpointConfig(StatusOr.fromValue(edsUpdate))); - - XdsConfig defaultXdsConfig = builder + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() .setListener(ldsUpdate) .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - // Set CallOptions with required keys CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions Channel mockChannel = Mockito.mock(Channel.class); ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); - - // Execute interception twice to check caching interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - // Capture and verify CallOptions for CallCredentials presence verify(mockChannel, Mockito.times(2)) .newCall(eq(methodDescriptor), callOptionsCaptor.capture()); - - // Retrieve the CallOptions captured from both calls CallOptions firstCapturedOptions = callOptionsCaptor.getAllValues().get(0); CallOptions secondCapturedOptions = callOptionsCaptor.getAllValues().get(1); - - // Ensure that CallCredentials was added assertNotNull(firstCapturedOptions.getCredentials()); assertNotNull(secondCapturedOptions.getCredentials()); - - // Ensure that the CallCredentials from both calls are the same, indicating caching assertSame(firstCapturedOptions.getCredentials(), secondCapturedOptions.getCredentials()); } @Test - public void testClientInterceptor_notAudienceWrapper() - throws IOException, ResourceInvalidException { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); + public void testClientInterceptor_withoutClusterSelectionKey() throws Exception { + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + Channel mockChannel = mock(Channel.class); + CallOptions callOptionsWithXds = CallOptions.DEFAULT; + ClientCall call = interceptor.interceptCall( + methodDescriptor, callOptionsWithXds, mockChannel); - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", "TEST_AUDIENCE"); // not AudienceWrapper + assertTrue(call instanceof FailingClientCall); + FailingClientCall clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("does not contain cluster resource"); + } - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); + @Test + public void testClientInterceptor_clusterSelectionKeyWithoutPrefix() throws Exception { XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( CLUSTER_NAME, - cdsUpdate.build(), + cdsUpdate, new EndpointConfig(StatusOr.fromValue(edsUpdate))); - - XdsConfig defaultXdsConfig = builder + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() .setListener(ldsUpdate) .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - // Set CallOptions with required keys CallOptions callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(CLUSTER_SELECTION_KEY, "cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + Channel mockChannel = mock(Channel.class); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - // Mock channel and capture CallOptions - Channel mockChannel = Mockito.mock(Channel.class); - - ClientCall call = - interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - assertTrue(call instanceof FailingClientCall); - FailingClientCall clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()).contains("GCP Authn found wrong type"); + verify(mockChannel).newCall(methodDescriptor, callOptionsWithXds); } @Test - public void testClientInterceptor_withoutClusterSelectionKey() throws Exception { - String serverName = InProcessServerBuilder.generateName(); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); - + public void testClientInterceptor_xdsConfigDoesNotExist() throws Exception { GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions Channel mockChannel = mock(Channel.class); + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0"); + ClientCall call = + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - // Set CallOptions with required keys - CallOptions callOptionsWithXds = CallOptions.DEFAULT; - - // Execute interception twice to check caching - ClientCall call = interceptor.interceptCall( - methodDescriptor, callOptionsWithXds, mockChannel); assertTrue(call instanceof FailingClientCall); FailingClientCall clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()).contains("does not contain cluster resource"); + assertThat(clientCall.error.getDescription()).contains("does not contain xds configuration"); } @Test - public void testClientInterceptor_clusterSelectionKeyWithoutPrefix() throws Exception { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); + public void testClientInterceptor_incorrectClusterName() throws Exception { XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( CLUSTER_NAME, - cdsUpdate.build(), + cdsUpdate, new EndpointConfig(StatusOr.fromValue(edsUpdate))); + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) + .addCluster("custer0", StatusOr.fromValue(clusterConfig)).build(); + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions Channel mockChannel = mock(Channel.class); - - XdsConfig defaultXdsConfig = builder - .setListener(ldsUpdate) - .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) - .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); - CallOptions callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster0") - .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - - // Execute interception twice to check caching ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - assertFalse(call instanceof FailingClientCall); - verify(mockChannel).newCall(methodDescriptor, callOptionsWithXds); + + assertTrue(call instanceof FailingClientCall); + FailingClientCall clientCall = (FailingClientCall) call; + assertThat(clientCall.error.getDescription()).contains("does not contain xds cluster"); } @Test - public void testClientInterceptor_xdsConfigDoesNotExist() throws Exception { - String serverName = InProcessServerBuilder.generateName(); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); + public void testClientInterceptor_statusOrError() throws Exception { + StatusOr errorCluster = + StatusOr.fromStatus(Status.NOT_FOUND.withDescription("Cluster resource not found")); + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() + .setListener(ldsUpdate) + .setRoute(rdsUpdate) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) + .addCluster(CLUSTER_NAME, errorCluster).build(); + CallOptions callOptionsWithXds = CallOptions.DEFAULT + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") + .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions Channel mockChannel = mock(Channel.class); - - CallOptions callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0"); - - // Execute interception twice to check caching ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); FailingClientCall clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()).contains("does not contain xds configuration"); + assertThat(clientCall.error.getDescription()).contains("Cluster resource not found"); } @Test - public void testClientInterceptor_incorrectClusterName() throws Exception { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - - Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( - serverName, RouterFilter.ROUTER_CONFIG); - - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( - 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); - - RouteConfiguration routeConfiguration = - buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); - - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); - - // Need to create endpoints to create locality endpoints map to create edsUpdate - Map lbEndpointsMap = new HashMap<>(); - LbEndpoint lbEndpoint = LbEndpoint.create( - serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); - lbEndpointsMap.put( - Locality.create("", "", ""), - LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); - - // Need to create EdsUpdate to create CdsUpdate to create XdsClusterConfig for builder - XdsEndpointResource.EdsUpdate edsUpdate = new XdsEndpointResource.EdsUpdate( - EDS_NAME, lbEndpointsMap, Collections.emptyList()); - - // Use ImmutableMap.Builder to construct the map - ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); - parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); - - CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( - CLUSTER_NAME, EDS_NAME, null, null, null, null, false) - .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); + public void testClientInterceptor_notAudienceWrapper() + throws IOException, ResourceInvalidException { XdsConfig.XdsClusterConfig clusterConfig = new XdsConfig.XdsClusterConfig( CLUSTER_NAME, - cdsUpdate.build(), + getCdsUpdateWithIncorrectAudienceWrapper(), new EndpointConfig(StatusOr.fromValue(edsUpdate))); - - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); - GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor - ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); - MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions - Channel mockChannel = mock(Channel.class); - - XdsConfig defaultXdsConfig = builder + XdsConfig defaultXdsConfig = new XdsConfig.XdsConfigBuilder() .setListener(ldsUpdate) .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) + .setVirtualHost(rdsUpdate.virtualHosts.get(0)) .addCluster(CLUSTER_NAME, StatusOr.fromValue(clusterConfig)).build(); CallOptions callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster") + .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - // Execute interception twice to check caching + GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); + GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); + ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); + MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); + Channel mockChannel = Mockito.mock(Channel.class); ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); + assertTrue(call instanceof FailingClientCall); FailingClientCall clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()).contains("does not contain xds cluster"); + assertThat(clientCall.error.getDescription()).contains("GCP Authn found wrong type"); } - @Test - public void testClientInterceptor_statusOrError() throws Exception { - String serverName = InProcessServerBuilder.generateName(); - XdsConfig.XdsConfigBuilder builder = new XdsConfig.XdsConfigBuilder(); - + private static LdsUpdate getLdsUpdate() { Filter.NamedFilterConfig routerFilterConfig = new Filter.NamedFilterConfig( serverName, RouterFilter.ROUTER_CONFIG); - HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName( 0L, RDS_NAME, Collections.singletonList(routerFilterConfig)); - XdsListenerResource.LdsUpdate ldsUpdate = - XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + return XdsListenerResource.LdsUpdate.forApiListener(httpConnectionManager); + } + private static RdsUpdate getRdsUpdate() { RouteConfiguration routeConfiguration = buildRouteConfiguration(serverName, RDS_NAME, CLUSTER_NAME); XdsResourceType.Args args = new XdsResourceType.Args(null, "0", "0", null, null, null); - XdsRouteConfigureResource.RdsUpdate rdsUpdate = - XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + try { + return XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); + } catch (ResourceInvalidException ex) { + return null; + } + } - // Take advantage of knowing that there is only 1 virtual host in the route configuration - assertThat(rdsUpdate.virtualHosts).hasSize(1); - VirtualHost virtualHost = rdsUpdate.virtualHosts.get(0); + private static EdsUpdate getEdsUpdate() { + Map lbEndpointsMap = new HashMap<>(); + LbEndpoint lbEndpoint = LbEndpoint.create( + serverName, ENDPOINT_PORT, 0, true, ENDPOINT_HOSTNAME, ImmutableMap.of()); + lbEndpointsMap.put( + Locality.create("", "", ""), + LocalityLbEndpoints.create(ImmutableList.of(lbEndpoint), 10, 0, ImmutableMap.of())); + return new XdsEndpointResource.EdsUpdate(EDS_NAME, lbEndpointsMap, Collections.emptyList()); + } - // Use ImmutableMap.Builder to construct the map + private static CdsUpdate getCdsUpdate() { ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); parsedMetadata.put("FILTER_INSTANCE_NAME", new AudienceWrapper("TEST_AUDIENCE")); + try { + CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( + CLUSTER_NAME, EDS_NAME, null, null, null, null, false) + .lbPolicyConfig(getWrrLbConfigAsMap()); + return cdsUpdate.parsedMetadata(parsedMetadata.build()).build(); + } catch (IOException ex) { + return null; + } + } + private static CdsUpdate getCdsUpdateWithIncorrectAudienceWrapper() throws IOException { + ImmutableMap.Builder parsedMetadata = ImmutableMap.builder(); + parsedMetadata.put("FILTER_INSTANCE_NAME", "TEST_AUDIENCE"); CdsUpdate.Builder cdsUpdate = CdsUpdate.forEds( CLUSTER_NAME, EDS_NAME, null, null, null, null, false) .lbPolicyConfig(getWrrLbConfigAsMap()); - cdsUpdate.parsedMetadata(parsedMetadata.build()); - - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); - GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); - - // Create interceptor - ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); - MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - - // Mock channel and capture CallOptions - Channel mockChannel = mock(Channel.class); - - StatusOr errorCluster = - StatusOr.fromStatus(Status.NOT_FOUND.withDescription("Cluster resource not found")); - XdsConfig defaultXdsConfig = builder - .setListener(ldsUpdate) - .setRoute(rdsUpdate) - .setVirtualHost(virtualHost) - .addCluster(CLUSTER_NAME, errorCluster).build(); - CallOptions callOptionsWithXds = CallOptions.DEFAULT - .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") - .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - - // Execute interception twice to check caching - ClientCall call = - interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); - assertTrue(call instanceof FailingClientCall); - FailingClientCall clientCall = (FailingClientCall) call; - assertThat(clientCall.error.getDescription()).contains("Cluster resource not found"); + return cdsUpdate.parsedMetadata(parsedMetadata.build()).build(); } } From e64df5de9582340b997653bc010049a679893397 Mon Sep 17 00:00:00 2001 From: MV Shiva Prasad Date: Wed, 2 Apr 2025 10:05:45 +0000 Subject: [PATCH 8/8] fix unit tests --- .../io/grpc/xds/GcpAuthenticationFilterTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index a476f54e1ac..a5e142b4094 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -151,13 +151,13 @@ public void testClientInterceptor_success() throws IOException, ResourceInvalidE CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = Mockito.mock(Channel.class); ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); verify(mockChannel).newCall(eq(methodDescriptor), callOptionsCaptor.capture()); @@ -180,13 +180,13 @@ public void testClientInterceptor_createsAndReusesCachedCredentials() CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = Mockito.mock(Channel.class); ArgumentCaptor callOptionsCaptor = ArgumentCaptor.forClass(CallOptions.class); + interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); @@ -207,6 +207,7 @@ public void testClientInterceptor_withoutClusterSelectionKey() throws Exception MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = mock(Channel.class); CallOptions callOptionsWithXds = CallOptions.DEFAULT; + ClientCall call = interceptor.interceptCall( methodDescriptor, callOptionsWithXds, mockChannel); @@ -229,12 +230,12 @@ public void testClientInterceptor_clusterSelectionKeyWithoutPrefix() throws Exce CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); + Channel mockChannel = mock(Channel.class); GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); - Channel mockChannel = mock(Channel.class); interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); verify(mockChannel).newCall(methodDescriptor, callOptionsWithXds); @@ -249,6 +250,7 @@ public void testClientInterceptor_xdsConfigDoesNotExist() throws Exception { Channel mockChannel = mock(Channel.class); CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0"); + ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); @@ -271,12 +273,12 @@ public void testClientInterceptor_incorrectClusterName() throws Exception { CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = mock(Channel.class); + ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); @@ -297,12 +299,12 @@ public void testClientInterceptor_statusOrError() throws Exception { CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = mock(Channel.class); + ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel); @@ -326,12 +328,12 @@ public void testClientInterceptor_notAudienceWrapper() CallOptions callOptionsWithXds = CallOptions.DEFAULT .withOption(CLUSTER_SELECTION_KEY, "cluster:cluster0") .withOption(XDS_CONFIG_CALL_OPTION_KEY, defaultXdsConfig); - GcpAuthenticationConfig config = new GcpAuthenticationConfig(10); GcpAuthenticationFilter filter = new GcpAuthenticationFilter("FILTER_INSTANCE_NAME"); ClientInterceptor interceptor = filter.buildClientInterceptor(config, null, null); MethodDescriptor methodDescriptor = TestMethodDescriptors.voidMethod(); Channel mockChannel = Mockito.mock(Channel.class); + ClientCall call = interceptor.interceptCall(methodDescriptor, callOptionsWithXds, mockChannel);