snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
This commit is contained in:
363
internal/xds/xdsclient/clientimpl_test.go
Normal file
363
internal/xds/xdsclient/clientimpl_test.go
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2025 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package xdsclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/internal/envconfig"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/stats"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/internal/xds/clients"
|
||||
"google.golang.org/grpc/internal/xds/clients/grpctransport"
|
||||
"google.golang.org/grpc/internal/xds/clients/xdsclient"
|
||||
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
|
||||
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
const (
|
||||
testXDSServerURL = "xds.example.com:8080"
|
||||
testXDSServerURL2 = "xds.example.com:8081"
|
||||
testNodeID = "test-node-id"
|
||||
testClusterName = "test-cluster"
|
||||
testUserAgentName = "test-ua-name"
|
||||
testUserAgentVer = "test-ua-ver"
|
||||
testLocalityRegion = "test-region"
|
||||
testLocalityZone = "test-zone"
|
||||
testLocalitySubZone = "test-sub-zone"
|
||||
testTargetName = "test-target"
|
||||
)
|
||||
|
||||
var (
|
||||
testMetadataJSON, _ = json.Marshal(map[string]any{"foo": "bar", "baz": float64(1)})
|
||||
)
|
||||
|
||||
func (s) TestBuildXDSClientConfig_Success(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
bootstrapContents []byte
|
||||
wantXDSClientConfig func(bootstrapCfg *bootstrap.Config) xdsclient.Config
|
||||
}{
|
||||
{
|
||||
name: "without authorities",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}]}],
|
||||
"node": {
|
||||
"id": "%s", "cluster": "%s", "metadata": %s,
|
||||
"locality": {"region": "%s", "zone": "%s", "sub_zone": "%s"},
|
||||
"user_agent_name": "%s", "user_agent_version": "%s"
|
||||
}
|
||||
}`, testXDSServerURL, testNodeID, testClusterName, testMetadataJSON, testLocalityRegion, testLocalityZone, testLocalitySubZone, testUserAgentName, testUserAgentVer)),
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node, serverCfg := c.Node(), c.XDSServers()[0]
|
||||
expectedServer := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: serverCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}}}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expectedServer: serverCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expectedServer},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, Locality: clients.Locality{Region: node.Locality.Region, Zone: node.Locality.Zone, SubZone: node.Locality.SubZone}, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, serverCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with authorities",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}]}],
|
||||
"node": {"id": "%s"},
|
||||
"authorities": {
|
||||
"auth1": {},
|
||||
"auth2": {"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}]}]}
|
||||
}
|
||||
}`, testXDSServerURL, testNodeID, testXDSServerURL2)),
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node := c.Node()
|
||||
topLevelSCfg, auth2SCfg := c.XDSServers()[0], c.Authorities()["auth2"].XDSServers[0]
|
||||
expTopLevelS := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: topLevelSCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}}}
|
||||
expAuth2S := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: auth2SCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}}}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expTopLevelS: topLevelSCfg, expAuth2S: auth2SCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expTopLevelS},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{"auth1": {XDSServers: []xdsclient.ServerConfig{expTopLevelS}}, "auth2": {XDSServers: []xdsclient.ServerConfig{expAuth2S}}},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, topLevelSCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "server features with ignore_resource_deletion",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}], "server_features": ["ignore_resource_deletion"]}],
|
||||
"node": {"id": "%s"}
|
||||
}`, testXDSServerURL, testNodeID)),
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node, serverCfg := c.Node(), c.XDSServers()[0]
|
||||
serverFeature := xdsclient.ServerFeatureIgnoreResourceDeletion
|
||||
expectedServer := xdsclient.ServerConfig{
|
||||
ServerIdentifier: clients.ServerIdentifier{ServerURI: serverCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}},
|
||||
ServerFeature: serverFeature}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expectedServer: serverCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expectedServer},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, serverCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "server features with trusted_xds_server",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}], "server_features": ["trusted_xds_server"]}],
|
||||
"node": {"id": "%s"}
|
||||
}`, testXDSServerURL, testNodeID)),
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node, serverCfg := c.Node(), c.XDSServers()[0]
|
||||
serverFeature := xdsclient.ServerFeatureTrustedXDSServer
|
||||
expectedServer := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: serverCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}},
|
||||
ServerFeature: serverFeature}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expectedServer: serverCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expectedServer},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, serverCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "server features with ignore_resource_deletion and trusted_xds_server",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "insecure"}], "server_features": ["ignore_resource_deletion", "trusted_xds_server"]}],
|
||||
"node": {"id": "%s"}
|
||||
}`, testXDSServerURL, testNodeID)),
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node, serverCfg := c.Node(), c.XDSServers()[0]
|
||||
serverFeature := xdsclient.ServerFeatureTrustedXDSServer | xdsclient.ServerFeatureIgnoreResourceDeletion
|
||||
expectedServer := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: serverCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}},
|
||||
ServerFeature: serverFeature}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expectedServer: serverCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expectedServer},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, serverCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "channel creds - unknown type skipped",
|
||||
bootstrapContents: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{"server_uri": "%s", "channel_creds": [{"type": "unknown-type"}, {"type": "insecure"}]}],
|
||||
"node": {"id": "%s"}
|
||||
}`, testXDSServerURL, testNodeID)), // "insecure" is selected
|
||||
wantXDSClientConfig: func(c *bootstrap.Config) xdsclient.Config {
|
||||
node, serverCfg := c.Node(), c.XDSServers()[0] // SelectedCreds will be "insecure"
|
||||
expectedServer := xdsclient.ServerConfig{ServerIdentifier: clients.ServerIdentifier{ServerURI: serverCfg.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"}}}
|
||||
gServerCfgMap := map[xdsclient.ServerConfig]*bootstrap.ServerConfig{expectedServer: serverCfg}
|
||||
return xdsclient.Config{
|
||||
Servers: []xdsclient.ServerConfig{expectedServer},
|
||||
Node: clients.Node{ID: node.GetId(), Cluster: node.GetCluster(), Metadata: node.Metadata, UserAgentName: node.UserAgentName, UserAgentVersion: node.GetUserAgentVersion()},
|
||||
Authorities: map[string]xdsclient.Authority{},
|
||||
ResourceTypes: map[string]xdsclient.ResourceType{
|
||||
version.V3ListenerURL: {TypeURL: version.V3ListenerURL, TypeName: xdsresource.ListenerResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewListenerResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3RouteConfigURL: {TypeURL: version.V3RouteConfigURL, TypeName: xdsresource.RouteConfigTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewRouteConfigResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3ClusterURL: {TypeURL: version.V3ClusterURL, TypeName: xdsresource.ClusterResourceTypeName, AllResourcesRequiredInSotW: true, Decoder: xdsresource.NewClusterResourceTypeDecoder(c, gServerCfgMap)},
|
||||
version.V3EndpointsURL: {TypeURL: version.V3EndpointsURL, TypeName: xdsresource.EndpointsResourceTypeName, AllResourcesRequiredInSotW: false, Decoder: xdsresource.NewEndpointsResourceTypeDecoder(c)},
|
||||
},
|
||||
MetricsReporter: &metricsReporter{recorder: stats.NewTestMetricsRecorder(), target: testTargetName},
|
||||
TransportBuilder: grpctransport.NewBuilder(map[string]grpctransport.Config{
|
||||
"insecure": {
|
||||
Credentials: insecure.NewBundle(),
|
||||
GRPCNewClient: func(target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts = append(opts, serverCfg.DialOptions()...)
|
||||
return grpc.NewClient(target, opts...)
|
||||
}},
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bootstrapConfig, err := bootstrap.NewConfigFromContents(tt.bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap config: %v", err)
|
||||
}
|
||||
gotCfg, err := BuildXDSClientConfig(bootstrapConfig, stats.NewTestMetricsRecorder(), testTargetName, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to build XDSClientConfig: %v", err)
|
||||
}
|
||||
|
||||
wantCfg := tt.wantXDSClientConfig(bootstrapConfig)
|
||||
|
||||
unexportedTypeOpts := cmpopts.IgnoreUnexported(clients.Node{}, grpctransport.Builder{})
|
||||
ignoreTypeOpts := cmpopts.IgnoreTypes(sync.Mutex{})
|
||||
resourceTypeCmpOpts := cmp.Comparer(func(a, b xdsclient.ResourceType) bool {
|
||||
return a.TypeURL == b.TypeURL && a.TypeName == b.TypeName && a.AllResourcesRequiredInSotW == b.AllResourcesRequiredInSotW && reflect.TypeOf(a.Decoder) == reflect.TypeOf(b.Decoder)
|
||||
})
|
||||
metricsReporterCmpOpts := cmp.Comparer(func(a, b clients.MetricsReporter) bool {
|
||||
if (a == nil) != (b == nil) {
|
||||
return false
|
||||
}
|
||||
if a == nil { // Both are nil
|
||||
return true
|
||||
}
|
||||
// Both are non-nil, compare type and target.
|
||||
aConcrete, aOK := a.(*metricsReporter)
|
||||
bConcrete, bOK := b.(*metricsReporter)
|
||||
if !(aOK && bOK && aConcrete.target == bConcrete.target) {
|
||||
return false
|
||||
}
|
||||
// Compare recorder by type.
|
||||
if (aConcrete.recorder == nil) != (bConcrete.recorder == nil) {
|
||||
return false
|
||||
}
|
||||
// If both are nil, recorder check passes. If both non-nil, check types.
|
||||
return aConcrete.recorder == nil || reflect.TypeOf(aConcrete.recorder) == reflect.TypeOf(bConcrete.recorder)
|
||||
})
|
||||
transportBuilderCmpOpts := cmp.Comparer(func(a, b grpctransport.Config) bool {
|
||||
// Compare Credentials by type
|
||||
credsEqual := true
|
||||
if (a.Credentials == nil) != (b.Credentials == nil) {
|
||||
credsEqual = false
|
||||
} else if a.Credentials != nil && reflect.TypeOf(a.Credentials) != reflect.TypeOf(b.Credentials) {
|
||||
credsEqual = false
|
||||
}
|
||||
// Compare GRPCNewClient by nil-ness
|
||||
newClientEqual := (a.GRPCNewClient == nil) == (b.GRPCNewClient == nil)
|
||||
return credsEqual && newClientEqual
|
||||
})
|
||||
|
||||
if diff := cmp.Diff(wantCfg, gotCfg, protocmp.Transform(), unexportedTypeOpts, ignoreTypeOpts, resourceTypeCmpOpts, metricsReporterCmpOpts, transportBuilderCmpOpts); diff != "" {
|
||||
t.Errorf("buildXDSClientConfig() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s) TestServerConfigCallCredsIntegration(t *testing.T) {
|
||||
testutils.SetEnvConfig(t, &envconfig.XDSBootstrapCallCredsEnabled, true)
|
||||
// Test server config with both channel and call credentials.
|
||||
serverConfigJSON := `{
|
||||
"server_uri": "xds-server:443",
|
||||
"channel_creds": [{"type": "tls", "config": {}}],
|
||||
"call_creds": [
|
||||
{
|
||||
"type": "jwt_token_file",
|
||||
"config": {"jwt_token_file": "/token.jwt"}
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
var sc bootstrap.ServerConfig
|
||||
if err := sc.UnmarshalJSON([]byte(serverConfigJSON)); err != nil {
|
||||
t.Fatalf("Failed to unmarshal server config: %v", err)
|
||||
}
|
||||
// Verify call credentials are processed.
|
||||
callCreds := sc.CallCredsConfigs()
|
||||
if len(callCreds) != 1 {
|
||||
t.Errorf("Got %d call credential configs, want 1", len(callCreds))
|
||||
}
|
||||
dialOpts := sc.DialOptions()
|
||||
if len(dialOpts) != 1 {
|
||||
t.Errorf("Got %d dial options, want 1", len(dialOpts))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user