dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/utils/serviceconfig/serviceconfig_test.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  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   *
    20   * Copyright 2021 gRPC authors.
    21   *
    22   */
    23  
    24  package serviceconfig
    25  
    26  import (
    27  	"encoding/json"
    28  	"fmt"
    29  	"testing"
    30  )
    31  
    32  import (
    33  	"github.com/google/go-cmp/cmp"
    34  
    35  	"google.golang.org/grpc/balancer"
    36  
    37  	externalserviceconfig "google.golang.org/grpc/serviceconfig"
    38  )
    39  
    40  type testBalancerConfigType struct {
    41  	externalserviceconfig.LoadBalancingConfig `json:"-"`
    42  
    43  	Check bool `json:"check"`
    44  }
    45  
    46  var testBalancerConfig = testBalancerConfigType{Check: true}
    47  
    48  const (
    49  	testBalancerBuilderName          = "test-bb"
    50  	testBalancerBuilderNotParserName = "test-bb-not-parser"
    51  
    52  	testBalancerConfigJSON = `{"check":true}`
    53  )
    54  
    55  type testBalancerBuilder struct {
    56  	balancer.Builder
    57  }
    58  
    59  func (testBalancerBuilder) ParseConfig(js json.RawMessage) (externalserviceconfig.LoadBalancingConfig, error) {
    60  	if string(js) != testBalancerConfigJSON {
    61  		return nil, fmt.Errorf("unexpected config json")
    62  	}
    63  	return testBalancerConfig, nil
    64  }
    65  
    66  func (testBalancerBuilder) Name() string {
    67  	return testBalancerBuilderName
    68  }
    69  
    70  type testBalancerBuilderNotParser struct {
    71  	balancer.Builder
    72  }
    73  
    74  func (testBalancerBuilderNotParser) Name() string {
    75  	return testBalancerBuilderNotParserName
    76  }
    77  
    78  func init() {
    79  	balancer.Register(testBalancerBuilder{})
    80  	balancer.Register(testBalancerBuilderNotParser{})
    81  }
    82  
    83  func TestBalancerConfigUnmarshalJSON(t *testing.T) {
    84  	tests := []struct {
    85  		name    string
    86  		json    string
    87  		want    BalancerConfig
    88  		wantErr bool
    89  	}{
    90  		{
    91  			name:    "empty json",
    92  			json:    "",
    93  			wantErr: true,
    94  		},
    95  		{
    96  			// The config should be a slice of maps, but each map should have
    97  			// exactly one entry.
    98  			name:    "more than one entry for a map",
    99  			json:    `[{"balancer1":"1","balancer2":"2"}]`,
   100  			wantErr: true,
   101  		},
   102  		{
   103  			name:    "no balancer registered",
   104  			json:    `[{"balancer1":"1"},{"balancer2":"2"}]`,
   105  			wantErr: true,
   106  		},
   107  		{
   108  			name: "OK",
   109  			json: fmt.Sprintf("[{%q: %v}]", testBalancerBuilderName, testBalancerConfigJSON),
   110  			want: BalancerConfig{
   111  				Name:   testBalancerBuilderName,
   112  				Config: testBalancerConfig,
   113  			},
   114  			wantErr: false,
   115  		},
   116  		{
   117  			name: "first balancer not registered",
   118  			json: fmt.Sprintf(`[{"balancer1":"1"},{%q: %v}]`, testBalancerBuilderName, testBalancerConfigJSON),
   119  			want: BalancerConfig{
   120  				Name:   testBalancerBuilderName,
   121  				Config: testBalancerConfig,
   122  			},
   123  			wantErr: false,
   124  		},
   125  		{
   126  			name: "balancer registered but builder not parser",
   127  			json: fmt.Sprintf("[{%q: %v}]", testBalancerBuilderNotParserName, testBalancerConfigJSON),
   128  			want: BalancerConfig{
   129  				Name:   testBalancerBuilderNotParserName,
   130  				Config: nil,
   131  			},
   132  			wantErr: false,
   133  		},
   134  	}
   135  	for _, tt := range tests {
   136  		t.Run(tt.name, func(t *testing.T) {
   137  			var bc BalancerConfig
   138  			if err := bc.UnmarshalJSON([]byte(tt.json)); (err != nil) != tt.wantErr {
   139  				t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
   140  			}
   141  			if !cmp.Equal(bc, tt.want) {
   142  				t.Errorf("diff: %v", cmp.Diff(bc, tt.want))
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestBalancerConfigMarshalJSON(t *testing.T) {
   149  	tests := []struct {
   150  		name     string
   151  		bc       BalancerConfig
   152  		wantJSON string
   153  	}{
   154  		{
   155  			name: "OK",
   156  			bc: BalancerConfig{
   157  				Name:   testBalancerBuilderName,
   158  				Config: testBalancerConfig,
   159  			},
   160  			wantJSON: `[{"test-bb": {"check":true}}]`,
   161  		},
   162  		{
   163  			name: "OK config is nil",
   164  			bc: BalancerConfig{
   165  				Name:   testBalancerBuilderNotParserName,
   166  				Config: nil, // nil should be marshaled to an empty config "{}".
   167  			},
   168  			wantJSON: `[{"test-bb-not-parser": {}}]`,
   169  		},
   170  	}
   171  	for _, tt := range tests {
   172  		t.Run(tt.name, func(t *testing.T) {
   173  			b, err := tt.bc.MarshalJSON()
   174  			if err != nil {
   175  				t.Fatalf("failed to marshal: %v", err)
   176  			}
   177  
   178  			if str := string(b); str != tt.wantJSON {
   179  				t.Fatalf("got str %q, want %q", str, tt.wantJSON)
   180  			}
   181  
   182  			var bc BalancerConfig
   183  			if err := bc.UnmarshalJSON(b); err != nil {
   184  				t.Errorf("failed to unmarshal: %v", err)
   185  			}
   186  			if !cmp.Equal(bc, tt.bc) {
   187  				t.Errorf("diff: %v", cmp.Diff(bc, tt.bc))
   188  			}
   189  		})
   190  	}
   191  }