dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/utils/hierarchy/hierarchy_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 2020 gRPC authors.
    21   *
    22   */
    23  
    24  package hierarchy
    25  
    26  import (
    27  	"testing"
    28  )
    29  
    30  import (
    31  	"github.com/google/go-cmp/cmp"
    32  
    33  	"google.golang.org/grpc/attributes"
    34  
    35  	"google.golang.org/grpc/resolver"
    36  )
    37  
    38  func TestGet(t *testing.T) {
    39  	tests := []struct {
    40  		name string
    41  		addr resolver.Address
    42  		want []string
    43  	}{
    44  		{
    45  			name: "not set",
    46  			addr: resolver.Address{},
    47  			want: nil,
    48  		},
    49  		{
    50  			name: "set",
    51  			addr: resolver.Address{
    52  				BalancerAttributes: attributes.New(pathKey, pathValue{"a", "b"}),
    53  			},
    54  			want: []string{"a", "b"},
    55  		},
    56  	}
    57  	for _, tt := range tests {
    58  		t.Run(tt.name, func(t *testing.T) {
    59  			if got := Get(tt.addr); !cmp.Equal(got, tt.want) {
    60  				t.Errorf("Get() = %v, want %v", got, tt.want)
    61  			}
    62  		})
    63  	}
    64  }
    65  
    66  func TestSet(t *testing.T) {
    67  	tests := []struct {
    68  		name string
    69  		addr resolver.Address
    70  		path []string
    71  	}{
    72  		{
    73  			name: "before is not set",
    74  			addr: resolver.Address{},
    75  			path: []string{"a", "b"},
    76  		},
    77  		{
    78  			name: "before is set",
    79  			addr: resolver.Address{
    80  				BalancerAttributes: attributes.New(pathKey, pathValue{"before", "a", "b"}),
    81  			},
    82  			path: []string{"a", "b"},
    83  		},
    84  	}
    85  	for _, tt := range tests {
    86  		t.Run(tt.name, func(t *testing.T) {
    87  			newAddr := Set(tt.addr, tt.path)
    88  			newPath := Get(newAddr)
    89  			if !cmp.Equal(newPath, tt.path) {
    90  				t.Errorf("path after Set() = %v, want %v", newPath, tt.path)
    91  			}
    92  		})
    93  	}
    94  }
    95  
    96  func TestGroup(t *testing.T) {
    97  	tests := []struct {
    98  		name  string
    99  		addrs []resolver.Address
   100  		want  map[string][]resolver.Address
   101  	}{
   102  		{
   103  			name: "all with hierarchy",
   104  			addrs: []resolver.Address{
   105  				{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   106  				{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   107  				{Addr: "b0", BalancerAttributes: attributes.New(pathKey, pathValue{"b"})},
   108  				{Addr: "b1", BalancerAttributes: attributes.New(pathKey, pathValue{"b"})},
   109  			},
   110  			want: map[string][]resolver.Address{
   111  				"a": {
   112  					{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   113  					{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   114  				},
   115  				"b": {
   116  					{Addr: "b0", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   117  					{Addr: "b1", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   118  				},
   119  			},
   120  		},
   121  		{
   122  			// Addresses without hierarchy are ignored.
   123  			name: "without hierarchy",
   124  			addrs: []resolver.Address{
   125  				{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   126  				{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   127  				{Addr: "b0", BalancerAttributes: nil},
   128  				{Addr: "b1", BalancerAttributes: nil},
   129  			},
   130  			want: map[string][]resolver.Address{
   131  				"a": {
   132  					{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   133  					{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   134  				},
   135  			},
   136  		},
   137  		{
   138  			// If hierarchy is set to a wrong type (which should never happen),
   139  			// the address is ignored.
   140  			name: "wrong type",
   141  			addrs: []resolver.Address{
   142  				{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   143  				{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{"a"})},
   144  				{Addr: "b0", BalancerAttributes: attributes.New(pathKey, "b")},
   145  				{Addr: "b1", BalancerAttributes: attributes.New(pathKey, 314)},
   146  			},
   147  			want: map[string][]resolver.Address{
   148  				"a": {
   149  					{Addr: "a0", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   150  					{Addr: "a1", BalancerAttributes: attributes.New(pathKey, pathValue{})},
   151  				},
   152  			},
   153  		},
   154  	}
   155  	for _, tt := range tests {
   156  		t.Run(tt.name, func(t *testing.T) {
   157  			if got := Group(tt.addrs); !cmp.Equal(got, tt.want, cmp.AllowUnexported(attributes.Attributes{})) {
   158  				t.Errorf("Group() = %v, want %v", got, tt.want)
   159  				t.Errorf("diff: %v", cmp.Diff(got, tt.want, cmp.AllowUnexported(attributes.Attributes{})))
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  func TestGroupE2E(t *testing.T) {
   166  	hierarchy := map[string]map[string][]string{
   167  		"p0": {
   168  			"wt0": {"addr0", "addr1"},
   169  			"wt1": {"addr2", "addr3"},
   170  		},
   171  		"p1": {
   172  			"wt10": {"addr10", "addr11"},
   173  			"wt11": {"addr12", "addr13"},
   174  		},
   175  	}
   176  
   177  	var addrsWithHierarchy []resolver.Address
   178  	for p, wts := range hierarchy {
   179  		path1 := pathValue{p}
   180  		for wt, addrs := range wts {
   181  			path2 := append(pathValue(nil), path1...)
   182  			path2 = append(path2, wt)
   183  			for _, addr := range addrs {
   184  				a := resolver.Address{
   185  					Addr:               addr,
   186  					BalancerAttributes: attributes.New(pathKey, path2),
   187  				}
   188  				addrsWithHierarchy = append(addrsWithHierarchy, a)
   189  			}
   190  		}
   191  	}
   192  
   193  	gotHierarchy := make(map[string]map[string][]string)
   194  	for p1, wts := range Group(addrsWithHierarchy) {
   195  		gotHierarchy[p1] = make(map[string][]string)
   196  		for p2, addrs := range Group(wts) {
   197  			for _, addr := range addrs {
   198  				gotHierarchy[p1][p2] = append(gotHierarchy[p1][p2], addr.Addr)
   199  			}
   200  		}
   201  	}
   202  
   203  	if !cmp.Equal(gotHierarchy, hierarchy) {
   204  		t.Errorf("diff: %v", cmp.Diff(gotHierarchy, hierarchy))
   205  	}
   206  }