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 }