...

Source file src/google.golang.org/grpc/xds/internal/xdsclient/xdsresource/tests/unmarshal_cds_test.go

Documentation: google.golang.org/grpc/xds/internal/xdsclient/xdsresource/tests

     1  /*
     2   *
     3   * Copyright 2023 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // Package tests_test contains test cases for unmarshalling of CDS resources.
    20  package tests_test
    21  
    22  import (
    23  	"encoding/json"
    24  	"testing"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/google/go-cmp/cmp/cmpopts"
    28  	"google.golang.org/grpc/balancer/leastrequest"
    29  	"google.golang.org/grpc/internal/balancer/stub"
    30  	"google.golang.org/grpc/internal/envconfig"
    31  	"google.golang.org/grpc/internal/grpctest"
    32  	iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
    33  	"google.golang.org/grpc/internal/testutils"
    34  	"google.golang.org/grpc/internal/testutils/xds/e2e"
    35  	"google.golang.org/grpc/internal/xds/bootstrap"
    36  	"google.golang.org/grpc/serviceconfig"
    37  	"google.golang.org/grpc/xds/internal/balancer/ringhash"
    38  	"google.golang.org/grpc/xds/internal/balancer/wrrlocality"
    39  	"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
    40  	"google.golang.org/protobuf/proto"
    41  	"google.golang.org/protobuf/types/known/anypb"
    42  	"google.golang.org/protobuf/types/known/structpb"
    43  	"google.golang.org/protobuf/types/known/wrapperspb"
    44  
    45  	v3xdsxdstypepb "github.com/cncf/xds/go/xds/type/v3"
    46  	v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
    47  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    48  	v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
    49  	v3aggregateclusterpb "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/aggregate/v3"
    50  	v3ringhashpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/ring_hash/v3"
    51  	v3roundrobinpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/round_robin/v3"
    52  	v3wrrlocalitypb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/wrr_locality/v3"
    53  
    54  	_ "google.golang.org/grpc/balancer/roundrobin" // To register round_robin load balancer.
    55  	_ "google.golang.org/grpc/xds"                 // Register the xDS LB Registry Converters.
    56  )
    57  
    58  type s struct {
    59  	grpctest.Tester
    60  }
    61  
    62  func Test(t *testing.T) {
    63  	grpctest.RunSubTests(t, s{})
    64  }
    65  
    66  const (
    67  	clusterName = "clusterName"
    68  	serviceName = "service"
    69  )
    70  
    71  func wrrLocality(t *testing.T, m proto.Message) *v3wrrlocalitypb.WrrLocality {
    72  	return &v3wrrlocalitypb.WrrLocality{
    73  		EndpointPickingPolicy: &v3clusterpb.LoadBalancingPolicy{
    74  			Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
    75  				{
    76  					TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
    77  						TypedConfig: testutils.MarshalAny(t, m),
    78  					},
    79  				},
    80  			},
    81  		},
    82  	}
    83  }
    84  
    85  func wrrLocalityAny(t *testing.T, m proto.Message) *anypb.Any {
    86  	return testutils.MarshalAny(t, wrrLocality(t, m))
    87  }
    88  
    89  type customLBConfig struct {
    90  	serviceconfig.LoadBalancingConfig
    91  }
    92  
    93  // We have this test in a separate test package in order to not take a
    94  // dependency on the internal xDS balancer packages within the xDS Client.
    95  func (s) TestValidateCluster_Success(t *testing.T) {
    96  	const customLBPolicyName = "myorg.MyCustomLeastRequestPolicy"
    97  	stub.Register(customLBPolicyName, stub.BalancerFuncs{
    98  		ParseConfig: func(json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
    99  			return customLBConfig{}, nil
   100  		},
   101  	})
   102  
   103  	defer func(old bool) { envconfig.LeastRequestLB = old }(envconfig.LeastRequestLB)
   104  	envconfig.LeastRequestLB = true
   105  	tests := []struct {
   106  		name         string
   107  		cluster      *v3clusterpb.Cluster
   108  		serverCfg    *bootstrap.ServerConfig
   109  		wantUpdate   xdsresource.ClusterUpdate
   110  		wantLBConfig *iserviceconfig.BalancerConfig
   111  	}{
   112  		{
   113  			name: "happy-case-logical-dns",
   114  			cluster: &v3clusterpb.Cluster{
   115  				Name:                 clusterName,
   116  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_LOGICAL_DNS},
   117  				LbPolicy:             v3clusterpb.Cluster_ROUND_ROBIN,
   118  				LoadAssignment: &v3endpointpb.ClusterLoadAssignment{
   119  					Endpoints: []*v3endpointpb.LocalityLbEndpoints{{
   120  						LbEndpoints: []*v3endpointpb.LbEndpoint{{
   121  							HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{
   122  								Endpoint: &v3endpointpb.Endpoint{
   123  									Address: &v3corepb.Address{
   124  										Address: &v3corepb.Address_SocketAddress{
   125  											SocketAddress: &v3corepb.SocketAddress{
   126  												Address: "dns_host",
   127  												PortSpecifier: &v3corepb.SocketAddress_PortValue{
   128  													PortValue: 8080,
   129  												},
   130  											},
   131  										},
   132  									},
   133  								},
   134  							},
   135  						}},
   136  					}},
   137  				},
   138  			},
   139  			wantUpdate: xdsresource.ClusterUpdate{
   140  				ClusterName: clusterName,
   141  				ClusterType: xdsresource.ClusterTypeLogicalDNS,
   142  				DNSHostName: "dns_host:8080",
   143  			},
   144  			wantLBConfig: &iserviceconfig.BalancerConfig{
   145  				Name: wrrlocality.Name,
   146  				Config: &wrrlocality.LBConfig{
   147  					ChildPolicy: &iserviceconfig.BalancerConfig{
   148  						Name: "round_robin",
   149  					},
   150  				},
   151  			},
   152  		},
   153  		{
   154  			name: "happy-case-aggregate-v3",
   155  			cluster: &v3clusterpb.Cluster{
   156  				Name: clusterName,
   157  				ClusterDiscoveryType: &v3clusterpb.Cluster_ClusterType{
   158  					ClusterType: &v3clusterpb.Cluster_CustomClusterType{
   159  						Name: "envoy.clusters.aggregate",
   160  						TypedConfig: testutils.MarshalAny(t, &v3aggregateclusterpb.ClusterConfig{
   161  							Clusters: []string{"a", "b", "c"},
   162  						}),
   163  					},
   164  				},
   165  				LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
   166  			},
   167  			wantUpdate: xdsresource.ClusterUpdate{
   168  				ClusterName:             clusterName,
   169  				ClusterType:             xdsresource.ClusterTypeAggregate,
   170  				PrioritizedClusterNames: []string{"a", "b", "c"},
   171  			},
   172  			wantLBConfig: &iserviceconfig.BalancerConfig{
   173  				Name: wrrlocality.Name,
   174  				Config: &wrrlocality.LBConfig{
   175  					ChildPolicy: &iserviceconfig.BalancerConfig{
   176  						Name: "round_robin",
   177  					},
   178  				},
   179  			},
   180  		},
   181  		{
   182  			name:       "happy-case-no-service-name-no-lrs",
   183  			cluster:    e2e.DefaultCluster(clusterName, "", e2e.SecurityLevelNone),
   184  			wantUpdate: xdsresource.ClusterUpdate{ClusterName: clusterName},
   185  			wantLBConfig: &iserviceconfig.BalancerConfig{
   186  				Name: wrrlocality.Name,
   187  				Config: &wrrlocality.LBConfig{
   188  					ChildPolicy: &iserviceconfig.BalancerConfig{
   189  						Name: "round_robin",
   190  					},
   191  				},
   192  			},
   193  		},
   194  		{
   195  			name:    "happy-case-no-lrs",
   196  			cluster: e2e.DefaultCluster(clusterName, serviceName, e2e.SecurityLevelNone),
   197  			wantUpdate: xdsresource.ClusterUpdate{
   198  				ClusterName:    clusterName,
   199  				EDSServiceName: serviceName,
   200  			},
   201  			wantLBConfig: &iserviceconfig.BalancerConfig{
   202  				Name: wrrlocality.Name,
   203  				Config: &wrrlocality.LBConfig{
   204  					ChildPolicy: &iserviceconfig.BalancerConfig{
   205  						Name: "round_robin",
   206  					},
   207  				},
   208  			},
   209  		},
   210  		{
   211  			name: "happiest-case-with-lrs",
   212  			cluster: e2e.ClusterResourceWithOptions(e2e.ClusterOptions{
   213  				ClusterName: clusterName,
   214  				ServiceName: serviceName,
   215  				EnableLRS:   true,
   216  			}),
   217  			serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
   218  			wantUpdate: xdsresource.ClusterUpdate{
   219  				ClusterName:     clusterName,
   220  				EDSServiceName:  serviceName,
   221  				LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
   222  			},
   223  			wantLBConfig: &iserviceconfig.BalancerConfig{
   224  				Name: wrrlocality.Name,
   225  				Config: &wrrlocality.LBConfig{
   226  					ChildPolicy: &iserviceconfig.BalancerConfig{
   227  						Name: "round_robin",
   228  					},
   229  				},
   230  			},
   231  		},
   232  		{
   233  			name: "happiest-case-with-circuitbreakers",
   234  			cluster: func() *v3clusterpb.Cluster {
   235  				c := e2e.ClusterResourceWithOptions(e2e.ClusterOptions{
   236  					ClusterName: clusterName,
   237  					ServiceName: serviceName,
   238  					EnableLRS:   true,
   239  				})
   240  				c.CircuitBreakers = &v3clusterpb.CircuitBreakers{
   241  					Thresholds: []*v3clusterpb.CircuitBreakers_Thresholds{
   242  						{
   243  							Priority:    v3corepb.RoutingPriority_DEFAULT,
   244  							MaxRequests: wrapperspb.UInt32(512),
   245  						},
   246  						{
   247  							Priority:    v3corepb.RoutingPriority_HIGH,
   248  							MaxRequests: nil,
   249  						},
   250  					},
   251  				}
   252  				return c
   253  			}(),
   254  			serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
   255  			wantUpdate: xdsresource.ClusterUpdate{
   256  				ClusterName:     clusterName,
   257  				EDSServiceName:  serviceName,
   258  				LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
   259  				MaxRequests:     func() *uint32 { i := uint32(512); return &i }(),
   260  			},
   261  			wantLBConfig: &iserviceconfig.BalancerConfig{
   262  				Name: wrrlocality.Name,
   263  				Config: &wrrlocality.LBConfig{
   264  					ChildPolicy: &iserviceconfig.BalancerConfig{
   265  						Name: "round_robin",
   266  					},
   267  				},
   268  			},
   269  		},
   270  		{
   271  			name: "happiest-case-with-ring-hash-lb-policy-with-default-config",
   272  			cluster: func() *v3clusterpb.Cluster {
   273  				c := e2e.DefaultCluster(clusterName, serviceName, e2e.SecurityLevelNone)
   274  				c.LbPolicy = v3clusterpb.Cluster_RING_HASH
   275  				return c
   276  			}(),
   277  			wantUpdate: xdsresource.ClusterUpdate{
   278  				ClusterName:    clusterName,
   279  				EDSServiceName: serviceName,
   280  			},
   281  			wantLBConfig: &iserviceconfig.BalancerConfig{
   282  				Name: "ring_hash_experimental",
   283  				Config: &ringhash.LBConfig{
   284  					MinRingSize: 1024,
   285  					MaxRingSize: 4096,
   286  				},
   287  			},
   288  		},
   289  		{
   290  			name: "happiest-case-with-least-request-lb-policy-with-default-config",
   291  			cluster: &v3clusterpb.Cluster{
   292  				Name:                 clusterName,
   293  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   294  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   295  					EdsConfig: &v3corepb.ConfigSource{
   296  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   297  							Ads: &v3corepb.AggregatedConfigSource{},
   298  						},
   299  					},
   300  					ServiceName: serviceName,
   301  				},
   302  				LbPolicy: v3clusterpb.Cluster_LEAST_REQUEST,
   303  			},
   304  			wantUpdate: xdsresource.ClusterUpdate{
   305  				ClusterName:    clusterName,
   306  				EDSServiceName: serviceName,
   307  			},
   308  			wantLBConfig: &iserviceconfig.BalancerConfig{
   309  				Name: "least_request_experimental",
   310  				Config: &leastrequest.LBConfig{
   311  					ChoiceCount: 2,
   312  				},
   313  			},
   314  		},
   315  		{
   316  			name: "happiest-case-with-ring-hash-lb-policy-with-none-default-config",
   317  			cluster: func() *v3clusterpb.Cluster {
   318  				c := e2e.DefaultCluster(clusterName, serviceName, e2e.SecurityLevelNone)
   319  				c.LbPolicy = v3clusterpb.Cluster_RING_HASH
   320  				c.LbConfig = &v3clusterpb.Cluster_RingHashLbConfig_{
   321  					RingHashLbConfig: &v3clusterpb.Cluster_RingHashLbConfig{
   322  						MinimumRingSize: wrapperspb.UInt64(10),
   323  						MaximumRingSize: wrapperspb.UInt64(100),
   324  					},
   325  				}
   326  				return c
   327  			}(),
   328  			wantUpdate: xdsresource.ClusterUpdate{
   329  				ClusterName:    clusterName,
   330  				EDSServiceName: serviceName,
   331  			},
   332  			wantLBConfig: &iserviceconfig.BalancerConfig{
   333  				Name: "ring_hash_experimental",
   334  				Config: &ringhash.LBConfig{
   335  					MinRingSize: 10,
   336  					MaxRingSize: 100,
   337  				},
   338  			},
   339  		},
   340  		{
   341  			name: "happiest-case-with-least-request-lb-policy-with-none-default-config",
   342  			cluster: &v3clusterpb.Cluster{
   343  				Name:                 clusterName,
   344  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   345  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   346  					EdsConfig: &v3corepb.ConfigSource{
   347  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   348  							Ads: &v3corepb.AggregatedConfigSource{},
   349  						},
   350  					},
   351  					ServiceName: serviceName,
   352  				},
   353  				LbPolicy: v3clusterpb.Cluster_LEAST_REQUEST,
   354  				LbConfig: &v3clusterpb.Cluster_LeastRequestLbConfig_{
   355  					LeastRequestLbConfig: &v3clusterpb.Cluster_LeastRequestLbConfig{
   356  						ChoiceCount: wrapperspb.UInt32(3),
   357  					},
   358  				},
   359  			},
   360  			wantUpdate: xdsresource.ClusterUpdate{
   361  				ClusterName:    clusterName,
   362  				EDSServiceName: serviceName,
   363  			},
   364  			wantLBConfig: &iserviceconfig.BalancerConfig{
   365  				Name: "least_request_experimental",
   366  				Config: &leastrequest.LBConfig{
   367  					ChoiceCount: 3,
   368  				},
   369  			},
   370  		},
   371  		{
   372  			name: "happiest-case-with-ring-hash-lb-policy-configured-through-LoadBalancingPolicy",
   373  			cluster: &v3clusterpb.Cluster{
   374  				Name:                 clusterName,
   375  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   376  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   377  					EdsConfig: &v3corepb.ConfigSource{
   378  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   379  							Ads: &v3corepb.AggregatedConfigSource{},
   380  						},
   381  					},
   382  					ServiceName: serviceName,
   383  				},
   384  				LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
   385  					Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
   386  						{
   387  							TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
   388  								TypedConfig: testutils.MarshalAny(t, &v3ringhashpb.RingHash{
   389  									HashFunction:    v3ringhashpb.RingHash_XX_HASH,
   390  									MinimumRingSize: wrapperspb.UInt64(10),
   391  									MaximumRingSize: wrapperspb.UInt64(100),
   392  								}),
   393  							},
   394  						},
   395  					},
   396  				},
   397  			},
   398  			wantUpdate: xdsresource.ClusterUpdate{
   399  				ClusterName:    clusterName,
   400  				EDSServiceName: serviceName,
   401  			},
   402  			wantLBConfig: &iserviceconfig.BalancerConfig{
   403  				Name: "ring_hash_experimental",
   404  				Config: &ringhash.LBConfig{
   405  					MinRingSize: 10,
   406  					MaxRingSize: 100,
   407  				},
   408  			},
   409  		},
   410  		{
   411  			name: "happiest-case-with-wrrlocality-rr-child-configured-through-LoadBalancingPolicy",
   412  			cluster: &v3clusterpb.Cluster{
   413  				Name:                 clusterName,
   414  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   415  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   416  					EdsConfig: &v3corepb.ConfigSource{
   417  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   418  							Ads: &v3corepb.AggregatedConfigSource{},
   419  						},
   420  					},
   421  					ServiceName: serviceName,
   422  				},
   423  				LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
   424  					Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
   425  						{
   426  							TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
   427  								TypedConfig: wrrLocalityAny(t, &v3roundrobinpb.RoundRobin{}),
   428  							},
   429  						},
   430  					},
   431  				},
   432  			},
   433  			wantUpdate: xdsresource.ClusterUpdate{
   434  				ClusterName:    clusterName,
   435  				EDSServiceName: serviceName,
   436  			},
   437  			wantLBConfig: &iserviceconfig.BalancerConfig{
   438  				Name: wrrlocality.Name,
   439  				Config: &wrrlocality.LBConfig{
   440  					ChildPolicy: &iserviceconfig.BalancerConfig{
   441  						Name: "round_robin",
   442  					},
   443  				},
   444  			},
   445  		},
   446  		{
   447  			name: "happiest-case-with-custom-lb-configured-through-LoadBalancingPolicy",
   448  			cluster: &v3clusterpb.Cluster{
   449  				Name:                 clusterName,
   450  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   451  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   452  					EdsConfig: &v3corepb.ConfigSource{
   453  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   454  							Ads: &v3corepb.AggregatedConfigSource{},
   455  						},
   456  					},
   457  					ServiceName: serviceName,
   458  				},
   459  				LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
   460  					Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
   461  						{
   462  							TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
   463  								TypedConfig: wrrLocalityAny(t, &v3xdsxdstypepb.TypedStruct{
   464  									TypeUrl: "type.googleapis.com/myorg.MyCustomLeastRequestPolicy",
   465  									Value:   &structpb.Struct{},
   466  								}),
   467  							},
   468  						},
   469  					},
   470  				},
   471  			},
   472  			wantUpdate: xdsresource.ClusterUpdate{
   473  				ClusterName:    clusterName,
   474  				EDSServiceName: serviceName,
   475  			},
   476  			wantLBConfig: &iserviceconfig.BalancerConfig{
   477  				Name: wrrlocality.Name,
   478  				Config: &wrrlocality.LBConfig{
   479  					ChildPolicy: &iserviceconfig.BalancerConfig{
   480  						Name:   "myorg.MyCustomLeastRequestPolicy",
   481  						Config: customLBConfig{},
   482  					},
   483  				},
   484  			},
   485  		},
   486  		{
   487  			name: "load-balancing-policy-takes-precedence-over-lb-policy-and-enum",
   488  			cluster: &v3clusterpb.Cluster{
   489  				Name:                 clusterName,
   490  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   491  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   492  					EdsConfig: &v3corepb.ConfigSource{
   493  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   494  							Ads: &v3corepb.AggregatedConfigSource{},
   495  						},
   496  					},
   497  					ServiceName: serviceName,
   498  				},
   499  				LbPolicy: v3clusterpb.Cluster_RING_HASH,
   500  				LbConfig: &v3clusterpb.Cluster_RingHashLbConfig_{
   501  					RingHashLbConfig: &v3clusterpb.Cluster_RingHashLbConfig{
   502  						MinimumRingSize: wrapperspb.UInt64(20),
   503  						MaximumRingSize: wrapperspb.UInt64(200),
   504  					},
   505  				},
   506  				LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
   507  					Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
   508  						{
   509  							TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
   510  								TypedConfig: testutils.MarshalAny(t, &v3ringhashpb.RingHash{
   511  									HashFunction:    v3ringhashpb.RingHash_XX_HASH,
   512  									MinimumRingSize: wrapperspb.UInt64(10),
   513  									MaximumRingSize: wrapperspb.UInt64(100),
   514  								}),
   515  							},
   516  						},
   517  					},
   518  				},
   519  			},
   520  			wantUpdate: xdsresource.ClusterUpdate{
   521  				ClusterName:    clusterName,
   522  				EDSServiceName: serviceName,
   523  			},
   524  			wantLBConfig: &iserviceconfig.BalancerConfig{
   525  				Name: "ring_hash_experimental",
   526  				Config: &ringhash.LBConfig{
   527  					MinRingSize: 10,
   528  					MaxRingSize: 100,
   529  				},
   530  			},
   531  		},
   532  	}
   533  
   534  	for _, test := range tests {
   535  		t.Run(test.name, func(t *testing.T) {
   536  			update, err := xdsresource.ValidateClusterAndConstructClusterUpdateForTesting(test.cluster, test.serverCfg)
   537  			if err != nil {
   538  				t.Errorf("validateClusterAndConstructClusterUpdate(%+v) failed: %v", test.cluster, err)
   539  			}
   540  			// Ignore the raw JSON string into the cluster update. JSON bytes
   541  			// are nondeterministic (whitespace etc.) so we cannot reliably
   542  			// compare JSON bytes in a test. Thus, marshal into a Balancer
   543  			// Config struct and compare on that. Only need to test this JSON
   544  			// emission here, as this covers the possible output space.
   545  			if diff := cmp.Diff(update, test.wantUpdate, cmpopts.EquateEmpty(), cmpopts.IgnoreFields(xdsresource.ClusterUpdate{}, "LBPolicy")); diff != "" {
   546  				t.Errorf("validateClusterAndConstructClusterUpdate(%+v) got diff: %v (-got, +want)", test.cluster, diff)
   547  			}
   548  			bc := &iserviceconfig.BalancerConfig{}
   549  			if err := json.Unmarshal(update.LBPolicy, bc); err != nil {
   550  				t.Fatalf("failed to unmarshal JSON: %v", err)
   551  			}
   552  			if diff := cmp.Diff(bc, test.wantLBConfig); diff != "" {
   553  				t.Fatalf("update.LBConfig got unexpected output, diff (-got +want): %v", diff)
   554  			}
   555  		})
   556  	}
   557  }
   558  

View as plain text