/* * * Copyright 2020 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 serviceconfig import ( "encoding/json" "fmt" "testing" "github.com/google/go-cmp/cmp" "google.golang.org/grpc/balancer" externalserviceconfig "google.golang.org/grpc/serviceconfig" ) type testBalancerConfigType struct { externalserviceconfig.LoadBalancingConfig `json:"-"` Check bool `json:"check"` } var testBalancerConfig = testBalancerConfigType{Check: true} const ( testBalancerBuilderName = "test-bb" testBalancerBuilderNotParserName = "test-bb-not-parser" testBalancerConfigJSON = `{"check":true}` ) type testBalancerBuilder struct { balancer.Builder } func (testBalancerBuilder) ParseConfig(js json.RawMessage) (externalserviceconfig.LoadBalancingConfig, error) { if string(js) != testBalancerConfigJSON { return nil, fmt.Errorf("unexpected config json") } return testBalancerConfig, nil } func (testBalancerBuilder) Name() string { return testBalancerBuilderName } type testBalancerBuilderNotParser struct { balancer.Builder } func (testBalancerBuilderNotParser) Name() string { return testBalancerBuilderNotParserName } func init() { balancer.Register(testBalancerBuilder{}) balancer.Register(testBalancerBuilderNotParser{}) } func TestBalancerConfigUnmarshalJSON(t *testing.T) { tests := []struct { name string json string want BalancerConfig wantErr bool }{ { name: "empty json", json: "", wantErr: true, }, { // The config should be a slice of maps, but each map should have // exactly one entry. name: "more than one entry for a map", json: `[{"balancer1":"1","balancer2":"2"}]`, wantErr: true, }, { name: "no balancer registered", json: `[{"balancer1":"1"},{"balancer2":"2"}]`, wantErr: true, }, { name: "OK", json: fmt.Sprintf("[{%q: %v}]", testBalancerBuilderName, testBalancerConfigJSON), want: BalancerConfig{ Name: testBalancerBuilderName, Config: testBalancerConfig, }, wantErr: false, }, { name: "first balancer not registered", json: fmt.Sprintf(`[{"balancer1":"1"},{%q: %v}]`, testBalancerBuilderName, testBalancerConfigJSON), want: BalancerConfig{ Name: testBalancerBuilderName, Config: testBalancerConfig, }, wantErr: false, }, { name: "balancer registered but builder not parser", json: fmt.Sprintf("[{%q: %v}]", testBalancerBuilderNotParserName, testBalancerConfigJSON), want: BalancerConfig{ Name: testBalancerBuilderNotParserName, Config: nil, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var bc BalancerConfig if err := bc.UnmarshalJSON([]byte(tt.json)); (err != nil) != tt.wantErr { t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) } if !cmp.Equal(bc, tt.want) { t.Errorf("diff: %v", cmp.Diff(bc, tt.want)) } }) } } func TestBalancerConfigMarshalJSON(t *testing.T) { tests := []struct { name string bc BalancerConfig wantJSON string }{ { name: "OK", bc: BalancerConfig{ Name: testBalancerBuilderName, Config: testBalancerConfig, }, wantJSON: fmt.Sprintf(`[{"test-bb": {"check":true}}]`), }, { name: "OK config is nil", bc: BalancerConfig{ Name: testBalancerBuilderNotParserName, Config: nil, // nil should be marshalled to an empty config "{}". }, wantJSON: fmt.Sprintf(`[{"test-bb-not-parser": {}}]`), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b, err := tt.bc.MarshalJSON() if err != nil { t.Fatalf("failed to marshal: %v", err) } if str := string(b); str != tt.wantJSON { t.Fatalf("got str %q, want %q", str, tt.wantJSON) } var bc BalancerConfig if err := bc.UnmarshalJSON(b); err != nil { t.Errorf("failed to mnmarshal: %v", err) } if !cmp.Equal(bc, tt.bc) { t.Errorf("diff: %v", cmp.Diff(bc, tt.bc)) } }) } }