/* * * Copyright 2021 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 clusterresolver import ( "encoding/json" "testing" "github.com/google/go-cmp/cmp" "google.golang.org/grpc/balancer" internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" "google.golang.org/grpc/xds/internal/balancer/ringhash" "google.golang.org/grpc/xds/internal/xdsclient/bootstrap" ) func TestDiscoveryMechanismTypeMarshalJSON(t *testing.T) { tests := []struct { name string typ DiscoveryMechanismType want string }{ { name: "eds", typ: DiscoveryMechanismTypeEDS, want: `"EDS"`, }, { name: "dns", typ: DiscoveryMechanismTypeLogicalDNS, want: `"LOGICAL_DNS"`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got, err := json.Marshal(tt.typ); err != nil || string(got) != tt.want { t.Fatalf("DiscoveryMechanismTypeEDS.MarshalJSON() = (%v, %v), want (%s, nil)", string(got), err, tt.want) } }) } } func TestDiscoveryMechanismTypeUnmarshalJSON(t *testing.T) { tests := []struct { name string js string want DiscoveryMechanismType wantErr bool }{ { name: "eds", js: `"EDS"`, want: DiscoveryMechanismTypeEDS, }, { name: "dns", js: `"LOGICAL_DNS"`, want: DiscoveryMechanismTypeLogicalDNS, }, { name: "error", js: `"1234"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var got DiscoveryMechanismType err := json.Unmarshal([]byte(tt.js), &got) if (err != nil) != tt.wantErr { t.Fatalf("DiscoveryMechanismTypeEDS.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) } if diff := cmp.Diff(got, tt.want); diff != "" { t.Fatalf("DiscoveryMechanismTypeEDS.UnmarshalJSON() got unexpected output, diff (-got +want): %v", diff) } }) } } const ( testJSONConfig1 = `{ "discoveryMechanisms": [{ "cluster": "test-cluster-name", "lrsLoadReportingServer": { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ] }, "maxConcurrentRequests": 314, "type": "EDS", "edsServiceName": "test-eds-service-name" }] }` testJSONConfig2 = `{ "discoveryMechanisms": [{ "cluster": "test-cluster-name", "lrsLoadReportingServer": { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ] }, "maxConcurrentRequests": 314, "type": "EDS", "edsServiceName": "test-eds-service-name" },{ "type": "LOGICAL_DNS" }] }` testJSONConfig3 = `{ "discoveryMechanisms": [{ "cluster": "test-cluster-name", "lrsLoadReportingServer": { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ] }, "maxConcurrentRequests": 314, "type": "EDS", "edsServiceName": "test-eds-service-name" }], "xdsLbPolicy":[{"ROUND_ROBIN":{}}] }` testJSONConfig4 = `{ "discoveryMechanisms": [{ "cluster": "test-cluster-name", "lrsLoadReportingServer": { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ] }, "maxConcurrentRequests": 314, "type": "EDS", "edsServiceName": "test-eds-service-name" }], "xdsLbPolicy":[{"ring_hash_experimental":{}}] }` testJSONConfig5 = `{ "discoveryMechanisms": [{ "cluster": "test-cluster-name", "lrsLoadReportingServer": { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ] }, "maxConcurrentRequests": 314, "type": "EDS", "edsServiceName": "test-eds-service-name" }], "xdsLbPolicy":[{"pick_first":{}}] }` ) var testLRSServerConfig = &bootstrap.ServerConfig{ ServerURI: "trafficdirector.googleapis.com:443", CredsType: "google_default", } func TestParseConfig(t *testing.T) { tests := []struct { name string js string want *LBConfig wantErr bool }{ { name: "empty json", js: "", want: nil, wantErr: true, }, { name: "OK with one discovery mechanism", js: testJSONConfig1, want: &LBConfig{ DiscoveryMechanisms: []DiscoveryMechanism{ { Cluster: testClusterName, LoadReportingServer: testLRSServerConfig, MaxConcurrentRequests: newUint32(testMaxRequests), Type: DiscoveryMechanismTypeEDS, EDSServiceName: testEDSService, }, }, XDSLBPolicy: nil, }, wantErr: false, }, { name: "OK with multiple discovery mechanisms", js: testJSONConfig2, want: &LBConfig{ DiscoveryMechanisms: []DiscoveryMechanism{ { Cluster: testClusterName, LoadReportingServer: testLRSServerConfig, MaxConcurrentRequests: newUint32(testMaxRequests), Type: DiscoveryMechanismTypeEDS, EDSServiceName: testEDSService, }, { Type: DiscoveryMechanismTypeLogicalDNS, }, }, XDSLBPolicy: nil, }, wantErr: false, }, { name: "OK with picking policy round_robin", js: testJSONConfig3, want: &LBConfig{ DiscoveryMechanisms: []DiscoveryMechanism{ { Cluster: testClusterName, LoadReportingServer: testLRSServerConfig, MaxConcurrentRequests: newUint32(testMaxRequests), Type: DiscoveryMechanismTypeEDS, EDSServiceName: testEDSService, }, }, XDSLBPolicy: &internalserviceconfig.BalancerConfig{ Name: "ROUND_ROBIN", Config: nil, }, }, wantErr: false, }, { name: "OK with picking policy ring_hash", js: testJSONConfig4, want: &LBConfig{ DiscoveryMechanisms: []DiscoveryMechanism{ { Cluster: testClusterName, LoadReportingServer: testLRSServerConfig, MaxConcurrentRequests: newUint32(testMaxRequests), Type: DiscoveryMechanismTypeEDS, EDSServiceName: testEDSService, }, }, XDSLBPolicy: &internalserviceconfig.BalancerConfig{ Name: ringhash.Name, Config: &ringhash.LBConfig{MinRingSize: 1024, MaxRingSize: 4096}, // Ringhash LB config with default min and max. }, }, wantErr: false, }, { name: "unsupported picking policy", js: testJSONConfig5, wantErr: true, }, } for _, tt := range tests { b := balancer.Get(Name) if b == nil { t.Fatalf("LB policy %q not registered", Name) } cfgParser, ok := b.(balancer.ConfigParser) if !ok { t.Fatalf("LB policy %q does not support config parsing", Name) } t.Run(tt.name, func(t *testing.T) { got, err := cfgParser.ParseConfig([]byte(tt.js)) if (err != nil) != tt.wantErr { t.Fatalf("parseConfig() error = %v, wantErr %v", err, tt.wantErr) } if tt.wantErr { return } if diff := cmp.Diff(got, tt.want); diff != "" { t.Errorf("parseConfig() got unexpected output, diff (-got +want): %v", diff) } }) } } func newString(s string) *string { return &s } func newUint32(i uint32) *uint32 { return &i }