gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/balancer/clusterresolver/priority_test.go (about) 1 /* 2 * 3 * Copyright 2019 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * 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 package clusterresolver 19 20 import ( 21 "context" 22 "net/url" 23 "testing" 24 "time" 25 26 corepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/api/v2/core" 27 "gitee.com/ks-custle/core-gm/grpc/balancer" 28 "gitee.com/ks-custle/core-gm/grpc/connectivity" 29 "gitee.com/ks-custle/core-gm/grpc/internal/testutils" 30 "gitee.com/ks-custle/core-gm/grpc/resolver" 31 "gitee.com/ks-custle/core-gm/grpc/xds/internal/balancer/priority" 32 xdstestutils "gitee.com/ks-custle/core-gm/grpc/xds/internal/testutils" 33 "github.com/google/go-cmp/cmp" 34 ) 35 36 // When a high priority is ready, adding/removing lower locality doesn't cause 37 // changes. 38 // 39 // Init 0 and 1; 0 is up, use 0; add 2, use 0; remove 2, use 0. 40 func (s) TestEDSPriority_HighPriorityReady(t *testing.T) { 41 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 42 defer cleanup() 43 44 // Two localities, with priorities [0, 1], each with one backend. 45 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 46 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 47 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 48 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 49 50 addrs1 := <-cc.NewSubConnAddrsCh 51 if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want { 52 t.Fatalf("sc is created with addr %v, want %v", got, want) 53 } 54 sc1 := <-cc.NewSubConnCh 55 56 // p0 is ready. 57 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 58 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 59 60 // Test roundrobin with only p0 subconns. 61 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 62 t.Fatal(err) 63 } 64 65 // Add p2, it shouldn't cause any updates. 66 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 67 clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 68 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 69 clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil) 70 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 71 72 select { 73 case <-cc.NewPickerCh: 74 t.Fatalf("got unexpected new picker") 75 case <-cc.NewSubConnCh: 76 t.Fatalf("got unexpected new SubConn") 77 case <-cc.RemoveSubConnCh: 78 t.Fatalf("got unexpected remove SubConn") 79 case <-time.After(defaultTestShortTimeout): 80 } 81 82 // Remove p2, no updates. 83 clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 84 clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 85 clab3.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 86 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil) 87 88 select { 89 case <-cc.NewPickerCh: 90 t.Fatalf("got unexpected new picker") 91 case <-cc.NewSubConnCh: 92 t.Fatalf("got unexpected new SubConn") 93 case <-cc.RemoveSubConnCh: 94 t.Fatalf("got unexpected remove SubConn") 95 case <-time.After(defaultTestShortTimeout): 96 } 97 } 98 99 // Lower priority is used when higher priority is not ready. 100 // 101 // Init 0 and 1; 0 is up, use 0; 0 is down, 1 is up, use 1; add 2, use 1; 1 is 102 // down, use 2; remove 2, use 1. 103 func (s) TestEDSPriority_SwitchPriority(t *testing.T) { 104 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 105 defer cleanup() 106 107 // Two localities, with priorities [0, 1], each with one backend. 108 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 109 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 110 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 111 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 112 113 addrs0 := <-cc.NewSubConnAddrsCh 114 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 115 t.Fatalf("sc is created with addr %v, want %v", got, want) 116 } 117 sc0 := <-cc.NewSubConnCh 118 119 // p0 is ready. 120 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 121 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 122 123 // Test roundrobin with only p0 subconns. 124 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 125 t.Fatal(err) 126 } 127 128 // Turn down 0, 1 is used. 129 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 130 addrs1 := <-cc.NewSubConnAddrsCh 131 if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want { 132 t.Fatalf("sc is created with addr %v, want %v", got, want) 133 } 134 sc1 := <-cc.NewSubConnCh 135 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 136 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 137 138 // Test pick with 1. 139 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 140 t.Fatal(err) 141 } 142 143 // Add p2, it shouldn't cause any updates. 144 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 145 clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 146 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 147 clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil) 148 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 149 150 select { 151 case <-cc.NewPickerCh: 152 t.Fatalf("got unexpected new picker") 153 case <-cc.NewSubConnCh: 154 t.Fatalf("got unexpected new SubConn") 155 case <-cc.RemoveSubConnCh: 156 t.Fatalf("got unexpected remove SubConn") 157 case <-time.After(defaultTestShortTimeout): 158 } 159 160 // Turn down 1, use 2 161 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 162 addrs2 := <-cc.NewSubConnAddrsCh 163 if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want { 164 t.Fatalf("sc is created with addr %v, want %v", got, want) 165 } 166 sc2 := <-cc.NewSubConnCh 167 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 168 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 169 170 // Test pick with 2. 171 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil { 172 t.Fatal(err) 173 } 174 175 // Remove 2, use 1. 176 clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 177 clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 178 clab3.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 179 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil) 180 181 // p2 SubConns are removed. 182 scToRemove := <-cc.RemoveSubConnCh 183 if !cmp.Equal(scToRemove, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) { 184 t.Fatalf("RemoveSubConn, want %v, got %v", sc2, scToRemove) 185 } 186 187 // Should get an update with 1's old picker, to override 2's old picker. 188 if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrTransientFailure); err != nil { 189 t.Fatal(err) 190 } 191 192 } 193 194 // Add a lower priority while the higher priority is down. 195 // 196 // Init 0 and 1; 0 and 1 both down; add 2, use 2. 197 func (s) TestEDSPriority_HigherDownWhileAddingLower(t *testing.T) { 198 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 199 defer cleanup() 200 // Two localities, with different priorities, each with one backend. 201 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 202 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 203 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 204 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 205 addrs0 := <-cc.NewSubConnAddrsCh 206 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 207 t.Fatalf("sc is created with addr %v, want %v", got, want) 208 } 209 sc0 := <-cc.NewSubConnCh 210 211 // Turn down 0, 1 is used. 212 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 213 addrs1 := <-cc.NewSubConnAddrsCh 214 if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want { 215 t.Fatalf("sc is created with addr %v, want %v", got, want) 216 } 217 sc1 := <-cc.NewSubConnCh 218 // Turn down 1, pick should error. 219 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 220 221 // Test pick failure. 222 if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrTransientFailure); err != nil { 223 t.Fatal(err) 224 } 225 226 // Add p2, it should create a new SubConn. 227 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 228 clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 229 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 230 clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil) 231 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 232 addrs2 := <-cc.NewSubConnAddrsCh 233 if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want { 234 t.Fatalf("sc is created with addr %v, want %v", got, want) 235 } 236 sc2 := <-cc.NewSubConnCh 237 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 238 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 239 240 // Test pick with 2. 241 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil { 242 t.Fatal(err) 243 } 244 245 } 246 247 // When a higher priority becomes available, all lower priorities are closed. 248 // 249 // Init 0,1,2; 0 and 1 down, use 2; 0 up, close 1 and 2. 250 func (s) TestEDSPriority_HigherReadyCloseAllLower(t *testing.T) { 251 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 252 defer cleanup() 253 // Two localities, with priorities [0,1,2], each with one backend. 254 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 255 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 256 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 257 clab1.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil) 258 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 259 addrs0 := <-cc.NewSubConnAddrsCh 260 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 261 t.Fatalf("sc is created with addr %v, want %v", got, want) 262 } 263 sc0 := <-cc.NewSubConnCh 264 265 // Turn down 0, 1 is used. 266 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 267 addrs1 := <-cc.NewSubConnAddrsCh 268 if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want { 269 t.Fatalf("sc is created with addr %v, want %v", got, want) 270 } 271 sc1 := <-cc.NewSubConnCh 272 // Turn down 1, 2 is used. 273 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 274 addrs2 := <-cc.NewSubConnAddrsCh 275 if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want { 276 t.Fatalf("sc is created with addr %v, want %v", got, want) 277 } 278 sc2 := <-cc.NewSubConnCh 279 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 280 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 281 282 // Test pick with 2. 283 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil { 284 t.Fatal(err) 285 } 286 287 // When 0 becomes ready, 0 should be used, 1 and 2 should all be closed. 288 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 289 var ( 290 scToRemove []balancer.SubConn 291 scToRemoveMap = make(map[balancer.SubConn]struct{}) 292 ) 293 // Each subconn is removed twice. This is OK in production, but it makes 294 // testing harder. 295 // 296 // The sub-balancer to be closed is priority's child, clusterimpl, who has 297 // weightedtarget as children. 298 // 299 // - When clusterimpl is removed from priority's balancergroup, all its 300 // subconns are removed once. 301 // - When clusterimpl is closed, it closes weightedtarget, and this 302 // weightedtarget's balancer removes all the same subconns again. 303 for i := 0; i < 4; i++ { 304 // We expect 2 subconns, so we recv from channel 4 times. 305 scToRemoveMap[<-cc.RemoveSubConnCh] = struct{}{} 306 } 307 for sc := range scToRemoveMap { 308 scToRemove = append(scToRemove, sc) 309 } 310 311 // sc1 and sc2 should be removed. 312 // 313 // With localities caching, the lower priorities are closed after a timeout, 314 // in goroutines. The order is no longer guaranteed. 315 if !(cmp.Equal(scToRemove[0], sc1, cmp.AllowUnexported(testutils.TestSubConn{})) && 316 cmp.Equal(scToRemove[1], sc2, cmp.AllowUnexported(testutils.TestSubConn{}))) && 317 !(cmp.Equal(scToRemove[0], sc2, cmp.AllowUnexported(testutils.TestSubConn{})) && 318 cmp.Equal(scToRemove[1], sc1, cmp.AllowUnexported(testutils.TestSubConn{}))) { 319 t.Errorf("RemoveSubConn, want [%v, %v], got %v", sc1, sc2, scToRemove) 320 } 321 322 // Test pick with 0. 323 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 324 t.Fatal(err) 325 } 326 } 327 328 // At init, start the next lower priority after timeout if the higher priority 329 // doesn't get ready. 330 // 331 // Init 0,1; 0 is not ready (in connecting), after timeout, use 1. 332 func (s) TestEDSPriority_InitTimeout(t *testing.T) { 333 const testPriorityInitTimeout = time.Second 334 defer func() func() { 335 old := priority.DefaultPriorityInitTimeout 336 priority.DefaultPriorityInitTimeout = testPriorityInitTimeout 337 return func() { 338 priority.DefaultPriorityInitTimeout = old 339 } 340 }()() 341 342 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 343 defer cleanup() 344 // Two localities, with different priorities, each with one backend. 345 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 346 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 347 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 348 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 349 addrs0 := <-cc.NewSubConnAddrsCh 350 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 351 t.Fatalf("sc is created with addr %v, want %v", got, want) 352 } 353 sc0 := <-cc.NewSubConnCh 354 355 // Keep 0 in connecting, 1 will be used after init timeout. 356 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 357 358 // Make sure new SubConn is created before timeout. 359 select { 360 case <-time.After(testPriorityInitTimeout * 3 / 4): 361 case <-cc.NewSubConnAddrsCh: 362 t.Fatalf("Got a new SubConn too early (Within timeout). Expect a new SubConn only after timeout") 363 } 364 365 addrs1 := <-cc.NewSubConnAddrsCh 366 if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want { 367 t.Fatalf("sc is created with addr %v, want %v", got, want) 368 } 369 sc1 := <-cc.NewSubConnCh 370 371 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 372 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 373 374 // Test pick with 1. 375 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 376 t.Fatal(err) 377 } 378 } 379 380 // Add localities to existing priorities. 381 // 382 // - start with 2 locality with p0 and p1 383 // - add localities to existing p0 and p1 384 func (s) TestEDSPriority_MultipleLocalities(t *testing.T) { 385 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 386 defer cleanup() 387 // Two localities, with different priorities, each with one backend. 388 clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 389 clab0.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 390 clab0.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 391 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab0.Build()), nil) 392 addrs0 := <-cc.NewSubConnAddrsCh 393 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 394 t.Fatalf("sc is created with addr %v, want %v", got, want) 395 } 396 sc0 := <-cc.NewSubConnCh 397 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 398 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 399 400 // Test roundrobin with only p0 subconns. 401 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 402 t.Fatal(err) 403 } 404 405 // Turn down p0 subconns, p1 subconns will be created. 406 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 407 408 addrs1 := <-cc.NewSubConnAddrsCh 409 if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want { 410 t.Fatalf("sc is created with addr %v, want %v", got, want) 411 } 412 sc1 := <-cc.NewSubConnCh 413 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 414 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 415 416 // Test roundrobin with only p1 subconns. 417 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 418 t.Fatal(err) 419 } 420 421 // Reconnect p0 subconns, p1 subconn will be closed. 422 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 423 424 scToRemove := <-cc.RemoveSubConnCh 425 if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) { 426 t.Fatalf("RemoveSubConn, want %v, got %v", sc1, scToRemove) 427 } 428 429 // Test roundrobin with only p0 subconns. 430 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 431 t.Fatal(err) 432 } 433 434 // Add two localities, with two priorities, with one backend. 435 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 436 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 437 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 438 clab1.AddLocality(testSubZones[2], 1, 0, testEndpointAddrs[2:3], nil) 439 clab1.AddLocality(testSubZones[3], 1, 1, testEndpointAddrs[3:4], nil) 440 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 441 addrs2 := <-cc.NewSubConnAddrsCh 442 if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want { 443 t.Fatalf("sc is created with addr %v, want %v", got, want) 444 } 445 sc2 := <-cc.NewSubConnCh 446 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 447 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 448 449 // Test roundrobin with only two p0 subconns. 450 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0, sc2}); err != nil { 451 t.Fatal(err) 452 } 453 454 // Turn down p0 subconns, p1 subconns will be created. 455 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 456 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 457 458 sc3 := <-cc.NewSubConnCh 459 edsb.UpdateSubConnState(sc3, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 460 edsb.UpdateSubConnState(sc3, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 461 sc4 := <-cc.NewSubConnCh 462 edsb.UpdateSubConnState(sc4, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 463 edsb.UpdateSubConnState(sc4, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 464 465 // Test roundrobin with only p1 subconns. 466 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc3, sc4}); err != nil { 467 t.Fatal(err) 468 } 469 } 470 471 // EDS removes all localities, and re-adds them. 472 func (s) TestEDSPriority_RemovesAllLocalities(t *testing.T) { 473 const testPriorityInitTimeout = time.Second 474 defer func() func() { 475 old := priority.DefaultPriorityInitTimeout 476 priority.DefaultPriorityInitTimeout = testPriorityInitTimeout 477 return func() { 478 priority.DefaultPriorityInitTimeout = old 479 } 480 }()() 481 482 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 483 defer cleanup() 484 // Two localities, with different priorities, each with one backend. 485 clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 486 clab0.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 487 clab0.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 488 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab0.Build()), nil) 489 addrs0 := <-cc.NewSubConnAddrsCh 490 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 491 t.Fatalf("sc is created with addr %v, want %v", got, want) 492 } 493 sc0 := <-cc.NewSubConnCh 494 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 495 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 496 497 // Test roundrobin with only p0 subconns. 498 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 499 t.Fatal(err) 500 } 501 502 // Remove all priorities. 503 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 504 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 505 // p0 subconn should be removed. 506 scToRemove := <-cc.RemoveSubConnCh 507 <-cc.RemoveSubConnCh // Drain the duplicate subconn removed. 508 if !cmp.Equal(scToRemove, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) { 509 t.Fatalf("RemoveSubConn, want %v, got %v", sc0, scToRemove) 510 } 511 512 // time.Sleep(time.Second) 513 514 // Test pick return TransientFailure. 515 if err := testErrPickerFromCh(cc.NewPickerCh, priority.ErrAllPrioritiesRemoved); err != nil { 516 t.Fatal(err) 517 } 518 519 // Re-add two localities, with previous priorities, but different backends. 520 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 521 clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[2:3], nil) 522 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[3:4], nil) 523 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 524 addrs01 := <-cc.NewSubConnAddrsCh 525 if got, want := addrs01[0].Addr, testEndpointAddrs[2]; got != want { 526 t.Fatalf("sc is created with addr %v, want %v", got, want) 527 } 528 sc01 := <-cc.NewSubConnCh 529 530 // Don't send any update to p0, so to not override the old state of p0. 531 // Later, connect to p1 and then remove p1. This will fallback to p0, and 532 // will send p0's old picker if they are not correctly removed. 533 534 // p1 will be used after priority init timeout. 535 addrs11 := <-cc.NewSubConnAddrsCh 536 if got, want := addrs11[0].Addr, testEndpointAddrs[3]; got != want { 537 t.Fatalf("sc is created with addr %v, want %v", got, want) 538 } 539 sc11 := <-cc.NewSubConnCh 540 edsb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 541 edsb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 542 543 // Test roundrobin with only p1 subconns. 544 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc11}); err != nil { 545 t.Fatal(err) 546 } 547 548 // Remove p1 from EDS, to fallback to p0. 549 clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 550 clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[2:3], nil) 551 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil) 552 553 // p1 subconn should be removed. 554 scToRemove1 := <-cc.RemoveSubConnCh 555 <-cc.RemoveSubConnCh // Drain the duplicate subconn removed. 556 if !cmp.Equal(scToRemove1, sc11, cmp.AllowUnexported(testutils.TestSubConn{})) { 557 t.Fatalf("RemoveSubConn, want %v, got %v", sc11, scToRemove1) 558 } 559 560 // Test pick return TransientFailure. 561 if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrNoSubConnAvailable); err != nil { 562 t.Fatal(err) 563 } 564 565 // Send an ready update for the p0 sc that was received when re-adding 566 // localities to EDS. 567 edsb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 568 edsb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 569 570 // Test roundrobin with only p0 subconns. 571 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc01}); err != nil { 572 t.Fatal(err) 573 } 574 575 select { 576 case <-cc.NewPickerCh: 577 t.Fatalf("got unexpected new picker") 578 case <-cc.NewSubConnCh: 579 t.Fatalf("got unexpected new SubConn") 580 case <-cc.RemoveSubConnCh: 581 t.Fatalf("got unexpected remove SubConn") 582 case <-time.After(defaultTestShortTimeout): 583 } 584 } 585 586 // Test the case where the high priority contains no backends. The low priority 587 // will be used. 588 func (s) TestEDSPriority_HighPriorityNoEndpoints(t *testing.T) { 589 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 590 defer cleanup() 591 // Two localities, with priorities [0, 1], each with one backend. 592 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 593 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 594 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 595 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 596 addrs1 := <-cc.NewSubConnAddrsCh 597 if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want { 598 t.Fatalf("sc is created with addr %v, want %v", got, want) 599 } 600 sc1 := <-cc.NewSubConnCh 601 602 // p0 is ready. 603 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 604 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 605 606 // Test roundrobin with only p0 subconns. 607 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 608 t.Fatal(err) 609 } 610 611 // Remove addresses from priority 0, should use p1. 612 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 613 clab2.AddLocality(testSubZones[0], 1, 0, nil, nil) 614 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 615 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 616 // p0 will remove the subconn, and ClientConn will send a sc update to 617 // shutdown. 618 scToRemove := <-cc.RemoveSubConnCh 619 edsb.UpdateSubConnState(scToRemove, balancer.SubConnState{ConnectivityState: connectivity.Shutdown}) 620 621 addrs2 := <-cc.NewSubConnAddrsCh 622 if got, want := addrs2[0].Addr, testEndpointAddrs[1]; got != want { 623 t.Fatalf("sc is created with addr %v, want %v", got, want) 624 } 625 sc2 := <-cc.NewSubConnCh 626 627 // p1 is ready. 628 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 629 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 630 631 // Test roundrobin with only p1 subconns. 632 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil { 633 t.Fatal(err) 634 } 635 } 636 637 // Test the case where the high priority contains no healthy backends. The low 638 // priority will be used. 639 func (s) TestEDSPriority_HighPriorityAllUnhealthy(t *testing.T) { 640 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 641 defer cleanup() 642 // Two localities, with priorities [0, 1], each with one backend. 643 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 644 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 645 clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 646 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 647 addrs1 := <-cc.NewSubConnAddrsCh 648 if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want { 649 t.Fatalf("sc is created with addr %v, want %v", got, want) 650 } 651 sc1 := <-cc.NewSubConnCh 652 653 // p0 is ready. 654 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 655 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 656 657 // Test roundrobin with only p0 subconns. 658 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 659 t.Fatal(err) 660 } 661 662 // Set priority 0 endpoints to all unhealthy, should use p1. 663 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 664 clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], &xdstestutils.AddLocalityOptions{ 665 Health: []corepb.HealthStatus{corepb.HealthStatus_UNHEALTHY}, 666 }) 667 clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil) 668 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 669 // p0 will remove the subconn, and ClientConn will send a sc update to 670 // transient failure. 671 scToRemove := <-cc.RemoveSubConnCh 672 edsb.UpdateSubConnState(scToRemove, balancer.SubConnState{ConnectivityState: connectivity.Shutdown}) 673 674 addrs2 := <-cc.NewSubConnAddrsCh 675 if got, want := addrs2[0].Addr, testEndpointAddrs[1]; got != want { 676 t.Fatalf("sc is created with addr %v, want %v", got, want) 677 } 678 sc2 := <-cc.NewSubConnCh 679 680 // p1 is ready. 681 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 682 edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 683 684 // Test roundrobin with only p1 subconns. 685 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil { 686 t.Fatal(err) 687 } 688 } 689 690 // Test the case where the first and only priority is removed. 691 func (s) TestEDSPriority_FirstPriorityRemoved(t *testing.T) { 692 const testPriorityInitTimeout = time.Second 693 defer func() func() { 694 old := priority.DefaultPriorityInitTimeout 695 priority.DefaultPriorityInitTimeout = testPriorityInitTimeout 696 return func() { 697 priority.DefaultPriorityInitTimeout = old 698 } 699 }()() 700 701 _, cc, xdsC, cleanup := setupTestEDS(t, nil) 702 defer cleanup() 703 // One localities, with priorities [0], each with one backend. 704 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 705 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 706 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 707 // Remove the only localities. 708 clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 709 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil) 710 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 711 defer cancel() 712 if err := cc.WaitForErrPicker(ctx); err != nil { 713 t.Fatal(err) 714 } 715 } 716 717 // Watch resources from EDS and DNS, with EDS as the higher priority. Lower 718 // priority is used when higher priority is not ready. 719 func (s) TestFallbackToDNS(t *testing.T) { 720 const testDNSEndpointAddr = "3.1.4.1:5" 721 // dnsTargetCh, dnsCloseCh, resolveNowCh, dnsR, cleanup := setupDNS() 722 dnsTargetCh, _, resolveNowCh, dnsR, cleanupDNS := setupDNS() 723 defer cleanupDNS() 724 edsb, cc, xdsC, cleanup := setupTestEDS(t, nil) 725 defer cleanup() 726 727 if err := edsb.UpdateClientConnState(balancer.ClientConnState{ 728 BalancerConfig: &LBConfig{ 729 DiscoveryMechanisms: []DiscoveryMechanism{ 730 { 731 Type: DiscoveryMechanismTypeEDS, 732 Cluster: testClusterName, 733 }, 734 { 735 Type: DiscoveryMechanismTypeLogicalDNS, 736 DNSHostname: testDNSTarget, 737 }, 738 }, 739 }, 740 }); err != nil { 741 t.Fatal(err) 742 } 743 744 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 745 defer ctxCancel() 746 select { 747 case target := <-dnsTargetCh: 748 // Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead. 749 //if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" { 750 if diff := cmp.Diff(target, resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}}); diff != "" { 751 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 752 } 753 case <-ctx.Done(): 754 t.Fatal("Timed out waiting for building DNS resolver") 755 } 756 757 // One locality with one backend. 758 clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 759 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 760 xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil) 761 762 // Also send a DNS update, because the balancer needs both updates from all 763 // resources to move on. 764 dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: testDNSEndpointAddr}}}) 765 766 addrs0 := <-cc.NewSubConnAddrsCh 767 if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want { 768 t.Fatalf("sc is created with addr %v, want %v", got, want) 769 } 770 sc0 := <-cc.NewSubConnCh 771 772 // p0 is ready. 773 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 774 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 775 776 // Test roundrobin with only p0 subconns. 777 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil { 778 t.Fatal(err) 779 } 780 781 // Turn down 0, p1 (DNS) will be used. 782 edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 783 784 // The transient failure above should not trigger a re-resolve to the DNS 785 // resolver. Need to read to clear the channel, to avoid potential deadlock 786 // writing to the channel later. 787 shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 788 defer shortCancel() 789 select { 790 case <-resolveNowCh: 791 t.Fatal("unexpected re-resolve trigger by transient failure from EDS endpoint") 792 case <-shortCtx.Done(): 793 } 794 795 // The addresses used to create new SubConn should be the DNS endpoint. 796 addrs1 := <-cc.NewSubConnAddrsCh 797 if got, want := addrs1[0].Addr, testDNSEndpointAddr; got != want { 798 t.Fatalf("sc is created with addr %v, want %v", got, want) 799 } 800 sc1 := <-cc.NewSubConnCh 801 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting}) 802 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready}) 803 804 // Test pick with 1. 805 if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil { 806 t.Fatal(err) 807 } 808 809 // Turn down the DNS endpoint, this should trigger an re-resolve in the DNS 810 // resolver. 811 edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) 812 813 // The transient failure above should trigger a re-resolve to the DNS 814 // resolver. Need to read to clear the channel, to avoid potential deadlock 815 // writing to the channel later. 816 select { 817 case <-resolveNowCh: 818 case <-ctx.Done(): 819 t.Fatal("Timed out waiting for re-resolve") 820 } 821 }