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 / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
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
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
364 lines
21 KiB
Go
364 lines
21 KiB
Go
/*
|
|
*
|
|
* 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))
|
|
}
|
|
}
|