google.golang.org/grpc@v1.62.1/internal/balancer/gracefulswitch/gracefulswitch_test.go (about) 1 /* 2 * 3 * Copyright 2022 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 19 package gracefulswitch 20 21 import ( 22 "context" 23 "fmt" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/google/go-cmp/cmp" 29 "github.com/google/go-cmp/cmp/cmpopts" 30 "google.golang.org/grpc/balancer" 31 "google.golang.org/grpc/connectivity" 32 "google.golang.org/grpc/internal/grpcsync" 33 "google.golang.org/grpc/internal/grpctest" 34 "google.golang.org/grpc/internal/testutils" 35 "google.golang.org/grpc/resolver" 36 "google.golang.org/grpc/serviceconfig" 37 ) 38 39 const ( 40 defaultTestTimeout = 5 * time.Second 41 defaultTestShortTimeout = 10 * time.Millisecond 42 ) 43 44 type s struct { 45 grpctest.Tester 46 } 47 48 func Test(t *testing.T) { 49 grpctest.RunSubTests(t, s{}) 50 } 51 52 func setup(t *testing.T) (*testutils.BalancerClientConn, *Balancer) { 53 tcc := testutils.NewBalancerClientConn(t) 54 return tcc, NewBalancer(tcc, balancer.BuildOptions{}) 55 } 56 57 // TestSuccessfulFirstUpdate tests a basic scenario for the graceful switch load 58 // balancer, where it is setup with a balancer which should populate the current 59 // load balancer. Any ClientConn updates should then be forwarded to this 60 // current load balancer. 61 func (s) TestSuccessfulFirstUpdate(t *testing.T) { 62 _, gsb := setup(t) 63 if err := gsb.SwitchTo(mockBalancerBuilder1{}); err != nil { 64 t.Fatalf("Balancer.SwitchTo failed with error: %v", err) 65 } 66 if gsb.balancerCurrent == nil { 67 t.Fatal("current balancer not populated after a successful call to SwitchTo()") 68 } 69 // This will be used to update the graceful switch balancer. This update 70 // should simply be forwarded down to the current load balancing policy. 71 ccs := balancer.ClientConnState{ 72 BalancerConfig: mockBalancerConfig{}, 73 } 74 75 // Updating ClientConnState should forward the update exactly as is to the 76 // current balancer. 77 if err := gsb.UpdateClientConnState(ccs); err != nil { 78 t.Fatalf("Balancer.UpdateClientConnState(%v) failed: %v", ccs, err) 79 } 80 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 81 defer cancel() 82 if err := gsb.balancerCurrent.Balancer.(*mockBalancer).waitForClientConnUpdate(ctx, ccs); err != nil { 83 t.Fatal(err) 84 } 85 } 86 87 // TestTwoBalancersSameType tests the scenario where there is a graceful switch 88 // load balancer setup with a current and pending load balancer of the same 89 // type. Any ClientConn update should be forwarded to the current lb if there is 90 // a current lb and no pending lb, and the only the pending lb if the graceful 91 // switch balancer contains both a current lb and a pending lb. The pending load 92 // balancer should also swap into current whenever it updates with a 93 // connectivity state other than CONNECTING. 94 func (s) TestTwoBalancersSameType(t *testing.T) { 95 tcc, gsb := setup(t) 96 // This will be used to update the graceful switch balancer. This update 97 // should simply be forwarded down to either the current or pending load 98 // balancing policy. 99 ccs := balancer.ClientConnState{ 100 BalancerConfig: mockBalancerConfig{}, 101 } 102 103 gsb.SwitchTo(mockBalancerBuilder1{}) 104 gsb.UpdateClientConnState(ccs) 105 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 106 defer cancel() 107 if err := gsb.balancerCurrent.Balancer.(*mockBalancer).waitForClientConnUpdate(ctx, ccs); err != nil { 108 t.Fatal(err) 109 } 110 111 // The current balancer reporting READY should cause this state 112 // to be forwarded to the ClientConn. 113 gsb.balancerCurrent.Balancer.(*mockBalancer).updateState(balancer.State{ 114 ConnectivityState: connectivity.Ready, 115 Picker: &neverErrPicker{}, 116 }) 117 118 select { 119 case <-ctx.Done(): 120 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 121 case state := <-tcc.NewStateCh: 122 if state != connectivity.Ready { 123 t.Fatalf("current balancer reports connectivity state %v, want %v", state, connectivity.Ready) 124 } 125 } 126 127 select { 128 case <-ctx.Done(): 129 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 130 case picker := <-tcc.NewPickerCh: 131 // Should receive a never err picker. 132 if _, err := picker.Pick(balancer.PickInfo{}); err != nil { 133 t.Fatalf("ClientConn should have received a never err picker from an UpdateState call") 134 } 135 } 136 137 // An explicit call to switchTo, even if the same type, should cause the 138 // balancer to build a new balancer for pending. 139 gsb.SwitchTo(mockBalancerBuilder1{}) 140 if gsb.balancerPending == nil { 141 t.Fatal("pending balancer not populated after another call to SwitchTo()") 142 } 143 144 // A ClientConn update received should be forwarded to the new pending LB 145 // policy, and not the current one. 146 gsb.UpdateClientConnState(ccs) 147 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 148 defer sCancel() 149 if err := gsb.balancerCurrent.Balancer.(*mockBalancer).waitForClientConnUpdate(sCtx, ccs); err == nil { 150 t.Fatal("current balancer received a ClientConn update when there is a pending balancer") 151 } 152 if err := gsb.balancerPending.Balancer.(*mockBalancer).waitForClientConnUpdate(ctx, ccs); err != nil { 153 t.Fatal(err) 154 } 155 156 // If the pending load balancer reports that is CONNECTING, no update should 157 // be sent to the ClientConn. 158 gsb.balancerPending.Balancer.(*mockBalancer).updateState(balancer.State{ 159 ConnectivityState: connectivity.Connecting, 160 }) 161 sCtx, sCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 162 defer sCancel() 163 select { 164 case <-tcc.NewStateCh: 165 t.Fatal("balancerPending reporting CONNECTING should not forward up to the ClientConn") 166 case <-sCtx.Done(): 167 } 168 169 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 170 // If the pending load balancer reports a state other than CONNECTING, the 171 // pending load balancer is logically warmed up, and the ClientConn should 172 // be updated with the State and Picker to start using the new policy. The 173 // pending load balancing policy should also be switched into the current 174 // load balancer. 175 gsb.balancerPending.Balancer.(*mockBalancer).updateState(balancer.State{ 176 ConnectivityState: connectivity.Ready, 177 Picker: &neverErrPicker{}, 178 }) 179 180 select { 181 case <-ctx.Done(): 182 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 183 case state := <-tcc.NewStateCh: 184 if state != connectivity.Ready { 185 t.Fatalf("pending balancer reports connectivity state %v, want %v", state, connectivity.Ready) 186 } 187 } 188 189 select { 190 case <-ctx.Done(): 191 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 192 case picker := <-tcc.NewPickerCh: 193 // This picker should be the recent one sent from UpdateState(), a never 194 // err picker, not the nil picker from two updateState() calls previous. 195 if picker == nil { 196 t.Fatalf("ClientConn should have received a never err picker, which is the most recent picker, from an UpdateState call") 197 } 198 if _, err := picker.Pick(balancer.PickInfo{}); err != nil { 199 t.Fatalf("ClientConn should have received a never err picker, which is the most recent picker, from an UpdateState call") 200 } 201 } 202 // The current balancer should be closed as a result of the swap. 203 if err := currBal.waitForClose(ctx); err != nil { 204 t.Fatal(err) 205 } 206 } 207 208 // TestCurrentNotReadyPendingUpdate tests the scenario where there is a current 209 // and pending load balancer setup in the graceful switch load balancer, and the 210 // current LB is not in the connectivity state READY. Any update from the 211 // pending load balancer should cause the graceful switch load balancer to swap 212 // the pending into current, and update the ClientConn with the pending load 213 // balancers state. 214 func (s) TestCurrentNotReadyPendingUpdate(t *testing.T) { 215 tcc, gsb := setup(t) 216 gsb.SwitchTo(mockBalancerBuilder1{}) 217 gsb.SwitchTo(mockBalancerBuilder1{}) 218 if gsb.balancerPending == nil { 219 t.Fatal("pending balancer not populated after another call to SwitchTo()") 220 } 221 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 222 // Due to the current load balancer not being in state READY, any update 223 // from the pending load balancer should cause that update to be forwarded 224 // to the ClientConn and also cause the pending load balancer to swap into 225 // the current one. 226 gsb.balancerPending.Balancer.(*mockBalancer).updateState(balancer.State{ 227 ConnectivityState: connectivity.Connecting, 228 Picker: &neverErrPicker{}, 229 }) 230 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 231 defer cancel() 232 select { 233 case <-ctx.Done(): 234 t.Fatalf("timeout waiting for an UpdateState call on the ClientConn") 235 case state := <-tcc.NewStateCh: 236 if state != connectivity.Connecting { 237 t.Fatalf("ClientConn received connectivity state %v, want %v (from pending)", state, connectivity.Connecting) 238 } 239 } 240 select { 241 case <-ctx.Done(): 242 t.Fatalf("timeout waiting for an UpdateState call on the ClientConn") 243 case picker := <-tcc.NewPickerCh: 244 // Should receive a never err picker. 245 if _, err := picker.Pick(balancer.PickInfo{}); err != nil { 246 t.Fatalf("ClientConn should have received a never err picker from an UpdateState call") 247 } 248 } 249 250 // The current balancer should be closed as a result of the swap. 251 if err := currBal.waitForClose(ctx); err != nil { 252 t.Fatal(err) 253 } 254 } 255 256 // TestCurrentLeavingReady tests the scenario where there is a current and 257 // pending load balancer setup in the graceful switch load balancer, with the 258 // current load balancer being in the state READY, and the current load balancer 259 // then transitions into a state other than READY. This should cause the pending 260 // load balancer to swap into the current load balancer, and the ClientConn to 261 // be updated with the cached pending load balancing state. Also, once the 262 // current is cleared from the graceful switch load balancer, any updates sent 263 // should be intercepted and not forwarded to the ClientConn, as the balancer 264 // has already been cleared. 265 func (s) TestCurrentLeavingReady(t *testing.T) { 266 tcc, gsb := setup(t) 267 gsb.SwitchTo(mockBalancerBuilder1{}) 268 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 269 currBal.updateState(balancer.State{ 270 ConnectivityState: connectivity.Ready, 271 }) 272 273 gsb.SwitchTo(mockBalancerBuilder2{}) 274 // Sends CONNECTING, shouldn't make it's way to ClientConn. 275 gsb.balancerPending.Balancer.(*mockBalancer).updateState(balancer.State{ 276 ConnectivityState: connectivity.Connecting, 277 Picker: &neverErrPicker{}, 278 }) 279 280 // The current balancer leaving READY should cause the pending balancer to 281 // swap to the current balancer. This swap from current to pending should 282 // also update the ClientConn with the pending balancers cached state and 283 // picker. 284 currBal.updateState(balancer.State{ 285 ConnectivityState: connectivity.Idle, 286 }) 287 288 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 289 defer cancel() 290 select { 291 case <-ctx.Done(): 292 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 293 case state := <-tcc.NewStateCh: 294 if state != connectivity.Connecting { 295 t.Fatalf("current balancer reports connectivity state %v, want %v", state, connectivity.Connecting) 296 } 297 } 298 299 select { 300 case <-ctx.Done(): 301 t.Fatalf("timeout while waiting for a UpdateState call on the ClientConn") 302 case picker := <-tcc.NewPickerCh: 303 // Should receive a never err picker cached from pending LB's updateState() call, which 304 // was cached. 305 if _, err := picker.Pick(balancer.PickInfo{}); err != nil { 306 t.Fatalf("ClientConn should have received a never err picker, the cached picker, from an UpdateState call") 307 } 308 } 309 310 // The current balancer should be closed as a result of the swap. 311 if err := currBal.waitForClose(ctx); err != nil { 312 t.Fatal(err) 313 } 314 315 // The current balancer is now cleared from the graceful switch load 316 // balancer. Thus, any update from the old current should be intercepted by 317 // the graceful switch load balancer and not forward up to the ClientConn. 318 currBal.updateState(balancer.State{ 319 ConnectivityState: connectivity.Ready, 320 Picker: &neverErrPicker{}, 321 }) 322 323 // This update should not be forwarded to the ClientConn. 324 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 325 defer sCancel() 326 select { 327 case <-sCtx.Done(): 328 case <-tcc.NewStateCh: 329 t.Fatal("UpdateState() from a cleared balancer should not make it's way to ClientConn") 330 } 331 332 if _, err := currBal.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}); err == nil { 333 t.Fatal("newSubConn() from a cleared balancer should have returned an error") 334 } 335 336 // This newSubConn call should also not reach the ClientConn. 337 sCtx, sCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 338 defer sCancel() 339 select { 340 case <-sCtx.Done(): 341 case <-tcc.NewSubConnCh: 342 t.Fatal("newSubConn() from a cleared balancer should not make it's way to ClientConn") 343 } 344 } 345 346 // TestBalancerSubconns tests the SubConn functionality of the graceful switch 347 // load balancer. This tests the SubConn update flow in both directions, and 348 // make sure updates end up at the correct component. 349 func (s) TestBalancerSubconns(t *testing.T) { 350 tcc, gsb := setup(t) 351 gsb.SwitchTo(mockBalancerBuilder1{}) 352 gsb.SwitchTo(mockBalancerBuilder2{}) 353 354 // A child balancer creating a new SubConn should eventually be forwarded to 355 // the ClientConn held by the graceful switch load balancer. 356 sc1, err := gsb.balancerCurrent.Balancer.(*mockBalancer).newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 357 if err != nil { 358 t.Fatalf("error constructing newSubConn in gsb: %v", err) 359 } 360 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 361 defer cancel() 362 select { 363 case <-ctx.Done(): 364 t.Fatalf("timeout while waiting for an NewSubConn call on the ClientConn") 365 case sc := <-tcc.NewSubConnCh: 366 if sc != sc1 { 367 t.Fatalf("NewSubConn, want %v, got %v", sc1, sc) 368 } 369 } 370 371 // The other child balancer creating a new SubConn should also be eventually 372 // be forwarded to the ClientConn held by the graceful switch load balancer. 373 sc2, err := gsb.balancerPending.Balancer.(*mockBalancer).newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 374 if err != nil { 375 t.Fatalf("error constructing newSubConn in gsb: %v", err) 376 } 377 select { 378 case <-ctx.Done(): 379 t.Fatalf("timeout while waiting for an NewSubConn call on the ClientConn") 380 case sc := <-tcc.NewSubConnCh: 381 if sc != sc2 { 382 t.Fatalf("NewSubConn, want %v, got %v", sc2, sc) 383 } 384 } 385 scState := balancer.SubConnState{ConnectivityState: connectivity.Ready} 386 // Updating the SubConnState for sc1 should cause the graceful switch 387 // balancer to forward the Update to balancerCurrent for sc1, as that is the 388 // balancer that created this SubConn. 389 sc1.(*testutils.TestSubConn).UpdateState(scState) 390 391 // Updating the SubConnState for sc2 should cause the graceful switch 392 // balancer to forward the Update to balancerPending for sc2, as that is the 393 // balancer that created this SubConn. 394 sc2.(*testutils.TestSubConn).UpdateState(scState) 395 396 // Updating the addresses for both SubConns and removing both SubConns 397 // should get forwarded to the ClientConn. 398 399 // Updating the addresses for sc1 should get forwarded to the ClientConn. 400 gsb.balancerCurrent.Balancer.(*mockBalancer).updateAddresses(sc1, []resolver.Address{}) 401 402 select { 403 case <-ctx.Done(): 404 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 405 case <-tcc.UpdateAddressesAddrsCh: 406 } 407 408 // Updating the addresses for sc2 should also get forwarded to the ClientConn. 409 gsb.balancerPending.Balancer.(*mockBalancer).updateAddresses(sc2, []resolver.Address{}) 410 select { 411 case <-ctx.Done(): 412 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 413 case <-tcc.UpdateAddressesAddrsCh: 414 } 415 416 // balancerCurrent removing sc1 should get forwarded to the ClientConn. 417 sc1.Shutdown() 418 select { 419 case <-ctx.Done(): 420 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 421 case sc := <-tcc.ShutdownSubConnCh: 422 if sc != sc1 { 423 t.Fatalf("ShutdownSubConn, want %v, got %v", sc1, sc) 424 } 425 } 426 // balancerPending removing sc2 should get forwarded to the ClientConn. 427 sc2.Shutdown() 428 select { 429 case <-ctx.Done(): 430 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 431 case sc := <-tcc.ShutdownSubConnCh: 432 if sc != sc2 { 433 t.Fatalf("ShutdownSubConn, want %v, got %v", sc2, sc) 434 } 435 } 436 } 437 438 // TestBalancerClose tests the graceful switch balancer's Close() 439 // functionality. From the Close() call, the graceful switch balancer should 440 // shut down any created Subconns and Close() the current and pending load 441 // balancers. This Close() call should also cause any other events (calls to 442 // entrance functions) to be no-ops. 443 func (s) TestBalancerClose(t *testing.T) { 444 // Setup gsb balancer with current, pending, and one created SubConn on both 445 // current and pending. 446 tcc, gsb := setup(t) 447 gsb.SwitchTo(mockBalancerBuilder1{}) 448 gsb.SwitchTo(mockBalancerBuilder2{}) 449 450 sc1, err := gsb.balancerCurrent.Balancer.(*mockBalancer).newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 451 // Will eventually get back a SubConn with an identifying property id 1 452 if err != nil { 453 t.Fatalf("error constructing newSubConn in gsb: %v", err) 454 } 455 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 456 defer cancel() 457 select { 458 case <-ctx.Done(): 459 t.Fatalf("timeout while waiting for an NewSubConn call on the ClientConn") 460 case <-tcc.NewSubConnCh: 461 } 462 463 sc2, err := gsb.balancerPending.Balancer.(*mockBalancer).newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 464 // Will eventually get back a SubConn with an identifying property id 2 465 if err != nil { 466 t.Fatalf("error constructing newSubConn in gsb: %v", err) 467 } 468 select { 469 case <-ctx.Done(): 470 t.Fatalf("timeout while waiting for an NewSubConn call on the ClientConn") 471 case <-tcc.NewSubConnCh: 472 } 473 474 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 475 pendBal := gsb.balancerPending.Balancer.(*mockBalancer) 476 477 // Closing the graceful switch load balancer should lead to removing any 478 // created SubConns, and closing both the current and pending load balancer. 479 gsb.Close() 480 481 // The order of SubConns the graceful switch load balancer tells the Client 482 // Conn to shut down is non deterministic, as it is stored in a 483 // map. However, the first SubConn shut down should be either sc1 or sc2. 484 select { 485 case <-ctx.Done(): 486 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 487 case sc := <-tcc.ShutdownSubConnCh: 488 if sc != sc1 && sc != sc2 { 489 t.Fatalf("ShutdownSubConn, want either %v or %v, got %v", sc1, sc2, sc) 490 } 491 } 492 493 // The graceful switch load balancer should then tell the ClientConn to 494 // shut down the other SubConn. 495 select { 496 case <-ctx.Done(): 497 t.Fatalf("timeout while waiting for an UpdateAddresses call on the ClientConn") 498 case sc := <-tcc.ShutdownSubConnCh: 499 if sc != sc1 && sc != sc2 { 500 t.Fatalf("ShutdownSubConn, want either %v or %v, got %v", sc1, sc2, sc) 501 } 502 } 503 504 // The current balancer should get closed as a result of the graceful switch balancer being closed. 505 if err := currBal.waitForClose(ctx); err != nil { 506 t.Fatal(err) 507 } 508 // The pending balancer should also get closed as a result of the graceful switch balancer being closed. 509 if err := pendBal.waitForClose(ctx); err != nil { 510 t.Fatal(err) 511 } 512 513 // Once the graceful switch load balancer has been closed, any entrance 514 // function should be a no-op and return errBalancerClosed if the function 515 // returns an error. 516 517 // SwitchTo() should return an error due to the graceful switch load 518 // balancer having been closed already. 519 if err := gsb.SwitchTo(mockBalancerBuilder1{}); err != errBalancerClosed { 520 t.Fatalf("gsb.SwitchTo(%v) returned error %v, want %v", mockBalancerBuilder1{}, err, errBalancerClosed) 521 } 522 523 // UpdateClientConnState() should return an error due to the graceful switch 524 // load balancer having been closed already. 525 ccs := balancer.ClientConnState{ 526 BalancerConfig: mockBalancerConfig{}, 527 } 528 if err := gsb.UpdateClientConnState(ccs); err != errBalancerClosed { 529 t.Fatalf("gsb.UpdateCLientConnState(%v) returned error %v, want %v", ccs, err, errBalancerClosed) 530 } 531 532 // After the graceful switch load balancer has been closed, any resolver error 533 // shouldn't forward to either balancer, as the resolver error is a no-op 534 // and also even if not, the balancers should have been cleared from the 535 // graceful switch load balancer. 536 gsb.ResolverError(balancer.ErrBadResolverState) 537 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 538 defer sCancel() 539 if err := currBal.waitForResolverError(sCtx, balancer.ErrBadResolverState); !strings.Contains(err.Error(), sCtx.Err().Error()) { 540 t.Fatal("the current balancer should not have received the resolver error after close") 541 } 542 sCtx, sCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 543 defer sCancel() 544 if err := pendBal.waitForResolverError(sCtx, balancer.ErrBadResolverState); !strings.Contains(err.Error(), sCtx.Err().Error()) { 545 t.Fatal("the pending balancer should not have received the resolver error after close") 546 } 547 } 548 549 // TestResolverError tests the functionality of a Resolver Error. If there is a 550 // current balancer, but no pending, the error should be forwarded to the 551 // current balancer. If there is both a current and pending balancer, the error 552 // should be forwarded to only the pending balancer. 553 func (s) TestResolverError(t *testing.T) { 554 _, gsb := setup(t) 555 gsb.SwitchTo(mockBalancerBuilder1{}) 556 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 557 // If there is only a current balancer present, the resolver error should be 558 // forwarded to the current balancer. 559 gsb.ResolverError(balancer.ErrBadResolverState) 560 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 561 defer cancel() 562 if err := currBal.waitForResolverError(ctx, balancer.ErrBadResolverState); err != nil { 563 t.Fatal(err) 564 } 565 566 gsb.SwitchTo(mockBalancerBuilder1{}) 567 568 // If there is a pending balancer present, then a resolver error should be 569 // forwarded to only the pending balancer, not the current. 570 pendBal := gsb.balancerPending.Balancer.(*mockBalancer) 571 gsb.ResolverError(balancer.ErrBadResolverState) 572 573 // The Resolver Error should not be forwarded to the current load balancer. 574 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 575 defer sCancel() 576 if err := currBal.waitForResolverError(sCtx, balancer.ErrBadResolverState); !strings.Contains(err.Error(), sCtx.Err().Error()) { 577 t.Fatal("the current balancer should not have received the resolver error after close") 578 } 579 580 // The Resolver Error should be forwarded to the pending load balancer. 581 if err := pendBal.waitForResolverError(ctx, balancer.ErrBadResolverState); err != nil { 582 t.Fatal(err) 583 } 584 } 585 586 // TestPendingReplacedByAnotherPending tests the scenario where a graceful 587 // switch balancer has a current and pending load balancer, and receives a 588 // SwitchTo() call, which then replaces the pending. This should cause the 589 // graceful switch balancer to clear pending state, close old pending SubConns, 590 // and Close() the pending balancer being replaced. 591 func (s) TestPendingReplacedByAnotherPending(t *testing.T) { 592 tcc, gsb := setup(t) 593 gsb.SwitchTo(mockBalancerBuilder1{}) 594 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 595 currBal.updateState(balancer.State{ 596 ConnectivityState: connectivity.Ready, 597 }) 598 599 // Populate pending with a SwitchTo() call. 600 gsb.SwitchTo(mockBalancerBuilder2{}) 601 602 pendBal := gsb.balancerPending.Balancer.(*mockBalancer) 603 sc1, err := pendBal.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 604 if err != nil { 605 t.Fatalf("error constructing newSubConn in gsb: %v", err) 606 } 607 // This picker never returns an error, which can help this this test verify 608 // whether this cached state will get cleared on a new pending balancer 609 // (will replace it with a picker that always errors). 610 pendBal.updateState(balancer.State{ 611 ConnectivityState: connectivity.Connecting, 612 Picker: &neverErrPicker{}, 613 }) 614 615 // Replace pending with a SwitchTo() call. 616 gsb.SwitchTo(mockBalancerBuilder2{}) 617 // The pending balancer being replaced should cause the graceful switch 618 // balancer to Shutdown() any created SubConns for the old pending balancer 619 // and also Close() the old pending balancer. 620 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 621 defer cancel() 622 select { 623 case <-ctx.Done(): 624 t.Fatalf("timeout while waiting for a SubConn.Shutdown") 625 case sc := <-tcc.ShutdownSubConnCh: 626 if sc != sc1 { 627 t.Fatalf("ShutdownSubConn, want %v, got %v", sc1, sc) 628 } 629 } 630 631 if err := pendBal.waitForClose(ctx); err != nil { 632 t.Fatal(err) 633 } 634 635 // Switching the current out of READY should cause the pending LB to swap 636 // into current, causing the graceful switch balancer to update the 637 // ClientConn with the cached pending state. Since the new pending hasn't 638 // sent an Update, the default state with connectivity state CONNECTING and 639 // an errPicker should be sent to the ClientConn. 640 currBal.updateState(balancer.State{ 641 ConnectivityState: connectivity.Idle, 642 }) 643 644 // The update should contain a default connectivity state CONNECTING for the 645 // state of the new pending LB policy. 646 select { 647 case <-ctx.Done(): 648 t.Fatalf("timeout while waiting for an UpdateState() call on the ClientConn") 649 case state := <-tcc.NewStateCh: 650 if state != connectivity.Connecting { 651 t.Fatalf("UpdateState(), want connectivity state %v, got %v", connectivity.Connecting, state) 652 } 653 } 654 // The update should contain a default picker ErrPicker in the picker sent 655 // for the state of the new pending LB policy. 656 select { 657 case <-ctx.Done(): 658 t.Fatalf("timeout while waiting for an UpdateState() call on the ClientConn") 659 case picker := <-tcc.NewPickerCh: 660 if _, err := picker.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable { 661 t.Fatalf("ClientConn should have received a never err picker from an UpdateState call") 662 } 663 } 664 } 665 666 // Picker which never errors here for test purposes (can fill up tests further up with this) 667 type neverErrPicker struct{} 668 669 func (p *neverErrPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { 670 return balancer.PickResult{}, nil 671 } 672 673 // TestUpdateSubConnStateRace tests the race condition when the graceful switch 674 // load balancer receives a SubConnUpdate concurrently with an UpdateState() 675 // call, which can cause the balancer to forward the update to to be closed and 676 // cleared. The balancer API guarantees to never call any method the balancer 677 // after a Close() call, and the test verifies that doesn't happen within the 678 // graceful switch load balancer. 679 func (s) TestUpdateSubConnStateRace(t *testing.T) { 680 tcc, gsb := setup(t) 681 gsb.SwitchTo(verifyBalancerBuilder{}) 682 gsb.SwitchTo(mockBalancerBuilder1{}) 683 currBal := gsb.balancerCurrent.Balancer.(*verifyBalancer) 684 currBal.t = t 685 pendBal := gsb.balancerPending.Balancer.(*mockBalancer) 686 sc, err := currBal.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 687 if err != nil { 688 t.Fatalf("error constructing newSubConn in gsb: %v", err) 689 } 690 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 691 defer cancel() 692 select { 693 case <-ctx.Done(): 694 t.Fatalf("timeout while waiting for an NewSubConn call on the ClientConn") 695 case <-tcc.NewSubConnCh: 696 } 697 // Spawn a goroutine that constantly calls UpdateSubConn for the current 698 // balancer, which will get deleted in this testing goroutine. 699 finished := make(chan struct{}) 700 go func() { 701 for { 702 select { 703 case <-finished: 704 return 705 default: 706 } 707 sc.(*testutils.TestSubConn).UpdateState(balancer.SubConnState{ 708 ConnectivityState: connectivity.Ready, 709 }) 710 } 711 }() 712 time.Sleep(time.Millisecond) 713 // This UpdateState call causes current to be closed/cleared. 714 pendBal.updateState(balancer.State{ 715 ConnectivityState: connectivity.Ready, 716 }) 717 // From this, either one of two things happen. Either the graceful switch 718 // load balancer doesn't Close() the current balancer before it forwards the 719 // SubConn update to the child, and the call gets forwarded down to the 720 // current balancer, or it can Close() the current balancer in between 721 // reading the balancer pointer and writing to it, and in that case the old 722 // current balancer should not be updated, as the balancer has already been 723 // closed and the balancer API guarantees it. 724 close(finished) 725 } 726 727 // TestInlineCallbackInBuild tests the scenario where a balancer calls back into 728 // the balancer.ClientConn API inline from it's build function. 729 func (s) TestInlineCallbackInBuild(t *testing.T) { 730 tcc, gsb := setup(t) 731 // This build call should cause all of the inline updates to forward to the 732 // ClientConn. 733 gsb.SwitchTo(buildCallbackBalancerBuilder{}) 734 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 735 defer cancel() 736 select { 737 case <-ctx.Done(): 738 t.Fatalf("timeout while waiting for an UpdateState() call on the ClientConn") 739 case <-tcc.NewStateCh: 740 } 741 select { 742 case <-ctx.Done(): 743 t.Fatalf("timeout while waiting for a NewSubConn() call on the ClientConn") 744 case <-tcc.NewSubConnCh: 745 } 746 select { 747 case <-ctx.Done(): 748 t.Fatalf("timeout while waiting for an UpdateAddresses() call on the ClientConn") 749 case <-tcc.UpdateAddressesAddrsCh: 750 } 751 select { 752 case <-ctx.Done(): 753 t.Fatalf("timeout while waiting for a Shutdown() call on the SubConn") 754 case <-tcc.ShutdownSubConnCh: 755 } 756 oldCurrent := gsb.balancerCurrent.Balancer.(*buildCallbackBal) 757 758 // Since the callback reports a state READY, this new inline balancer should 759 // be swapped to the current. 760 gsb.SwitchTo(buildCallbackBalancerBuilder{}) 761 select { 762 case <-ctx.Done(): 763 t.Fatalf("timeout while waiting for an UpdateState() call on the ClientConn") 764 case <-tcc.NewStateCh: 765 } 766 select { 767 case <-ctx.Done(): 768 t.Fatalf("timeout while waiting for a NewSubConn() call on the ClientConn") 769 case <-tcc.NewSubConnCh: 770 } 771 select { 772 case <-ctx.Done(): 773 t.Fatalf("timeout while waiting for an UpdateAddresses() call on the ClientConn") 774 case <-tcc.UpdateAddressesAddrsCh: 775 } 776 select { 777 case <-ctx.Done(): 778 t.Fatalf("timeout while waiting for a Shutdown() call on the SubConn") 779 case <-tcc.ShutdownSubConnCh: 780 } 781 782 // The current balancer should be closed as a result of the swap. 783 if err := oldCurrent.waitForClose(ctx); err != nil { 784 t.Fatalf("error waiting for balancer close: %v", err) 785 } 786 787 // The old balancer should be deprecated and any calls from it should be a no-op. 788 oldCurrent.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 789 sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 790 defer sCancel() 791 select { 792 case <-tcc.NewSubConnCh: 793 t.Fatal("Deprecated LB calling NewSubConn() should not forward up to the ClientConn") 794 case <-sCtx.Done(): 795 } 796 } 797 798 // TestExitIdle tests the ExitIdle operation on the Graceful Switch Balancer for 799 // both possible codepaths, one where the child implements ExitIdler interface 800 // and one where the child doesn't implement ExitIdler interface. 801 func (s) TestExitIdle(t *testing.T) { 802 _, gsb := setup(t) 803 // switch to a balancer that implements ExitIdle{} (will populate current). 804 gsb.SwitchTo(mockBalancerBuilder1{}) 805 currBal := gsb.balancerCurrent.Balancer.(*mockBalancer) 806 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 807 defer cancel() 808 // exitIdle on the Graceful Switch Balancer should get forwarded to the 809 // current child as it implements exitIdle. 810 gsb.ExitIdle() 811 if err := currBal.waitForExitIdle(ctx); err != nil { 812 t.Fatal(err) 813 } 814 815 // switch to a balancer that doesn't implement ExitIdle{} (will populate 816 // pending). 817 gsb.SwitchTo(verifyBalancerBuilder{}) 818 // call exitIdle concurrently with newSubConn to make sure there is not a 819 // data race. 820 done := make(chan struct{}) 821 go func() { 822 gsb.ExitIdle() 823 close(done) 824 }() 825 pendBal := gsb.balancerPending.Balancer.(*verifyBalancer) 826 for i := 0; i < 10; i++ { 827 pendBal.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 828 } 829 <-done 830 } 831 832 const balancerName1 = "mock_balancer_1" 833 const balancerName2 = "mock_balancer_2" 834 const verifyBalName = "verifyNoSubConnUpdateAfterCloseBalancer" 835 const buildCallbackBalName = "callbackInBuildBalancer" 836 837 type mockBalancerBuilder1 struct{} 838 839 func (mockBalancerBuilder1) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { 840 return &mockBalancer{ 841 ccsCh: testutils.NewChannel(), 842 scStateCh: testutils.NewChannel(), 843 resolverErrCh: testutils.NewChannel(), 844 closeCh: testutils.NewChannel(), 845 exitIdleCh: testutils.NewChannel(), 846 cc: cc, 847 } 848 } 849 850 func (mockBalancerBuilder1) Name() string { 851 return balancerName1 852 } 853 854 type mockBalancerConfig struct { 855 serviceconfig.LoadBalancingConfig 856 } 857 858 // mockBalancer is a fake balancer used to verify different actions from 859 // the gracefulswitch. It contains a bunch of channels to signal different events 860 // to the test. 861 type mockBalancer struct { 862 // ccsCh is a channel used to signal the receipt of a ClientConn update. 863 ccsCh *testutils.Channel 864 // scStateCh is a channel used to signal the receipt of a SubConn update. 865 scStateCh *testutils.Channel 866 // resolverErrCh is a channel used to signal a resolver error. 867 resolverErrCh *testutils.Channel 868 // closeCh is a channel used to signal the closing of this balancer. 869 closeCh *testutils.Channel 870 // exitIdleCh is a channel used to signal the receipt of an ExitIdle call. 871 exitIdleCh *testutils.Channel 872 // Hold onto ClientConn wrapper to communicate with it 873 cc balancer.ClientConn 874 } 875 876 type subConnWithState struct { 877 sc balancer.SubConn 878 state balancer.SubConnState 879 } 880 881 func (mb1 *mockBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error { 882 // Need to verify this call...use a channel?...all of these will need verification 883 mb1.ccsCh.Send(ccs) 884 return nil 885 } 886 887 func (mb1 *mockBalancer) ResolverError(err error) { 888 mb1.resolverErrCh.Send(err) 889 } 890 891 func (mb1 *mockBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { 892 panic(fmt.Sprintf("UpdateSubConnState(%v, %+v) called unexpectedly", sc, state)) 893 } 894 895 func (mb1 *mockBalancer) Close() { 896 mb1.closeCh.Send(struct{}{}) 897 } 898 899 func (mb1 *mockBalancer) ExitIdle() { 900 mb1.exitIdleCh.Send(struct{}{}) 901 } 902 903 // waitForClientConnUpdate verifies if the mockBalancer receives the 904 // provided ClientConnState within a reasonable amount of time. 905 func (mb1 *mockBalancer) waitForClientConnUpdate(ctx context.Context, wantCCS balancer.ClientConnState) error { 906 ccs, err := mb1.ccsCh.Receive(ctx) 907 if err != nil { 908 return fmt.Errorf("error waiting for ClientConnUpdate: %v", err) 909 } 910 gotCCS := ccs.(balancer.ClientConnState) 911 if diff := cmp.Diff(gotCCS, wantCCS, cmpopts.IgnoreFields(resolver.State{}, "Attributes")); diff != "" { 912 return fmt.Errorf("error in ClientConnUpdate: received unexpected ClientConnState, diff (-got +want): %v", diff) 913 } 914 return nil 915 } 916 917 // waitForResolverError verifies if the mockBalancer receives the provided 918 // resolver error before the context expires. 919 func (mb1 *mockBalancer) waitForResolverError(ctx context.Context, wantErr error) error { 920 gotErr, err := mb1.resolverErrCh.Receive(ctx) 921 if err != nil { 922 return fmt.Errorf("error waiting for resolver error: %v", err) 923 } 924 if gotErr != wantErr { 925 return fmt.Errorf("received resolver error: %v, want %v", gotErr, wantErr) 926 } 927 return nil 928 } 929 930 // waitForClose verifies that the mockBalancer is closed before the context 931 // expires. 932 func (mb1 *mockBalancer) waitForClose(ctx context.Context) error { 933 if _, err := mb1.closeCh.Receive(ctx); err != nil { 934 return fmt.Errorf("error waiting for Close(): %v", err) 935 } 936 return nil 937 } 938 939 // waitForExitIdle verifies that ExitIdle gets called on the mockBalancer before 940 // the context expires. 941 func (mb1 *mockBalancer) waitForExitIdle(ctx context.Context) error { 942 if _, err := mb1.exitIdleCh.Receive(ctx); err != nil { 943 return fmt.Errorf("error waiting for ExitIdle(): %v", err) 944 } 945 return nil 946 } 947 948 func (mb1 *mockBalancer) updateState(state balancer.State) { 949 mb1.cc.UpdateState(state) 950 } 951 952 func (mb1 *mockBalancer) newSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (sc balancer.SubConn, err error) { 953 if opts.StateListener == nil { 954 opts.StateListener = func(state balancer.SubConnState) { 955 mb1.scStateCh.Send(subConnWithState{sc: sc, state: state}) 956 } 957 } 958 defer func() { 959 if sc != nil { 960 sc.Connect() 961 } 962 }() 963 return mb1.cc.NewSubConn(addrs, opts) 964 } 965 966 func (mb1 *mockBalancer) updateAddresses(sc balancer.SubConn, addrs []resolver.Address) { 967 mb1.cc.UpdateAddresses(sc, addrs) 968 } 969 970 type mockBalancerBuilder2 struct{} 971 972 func (mockBalancerBuilder2) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { 973 return &mockBalancer{ 974 ccsCh: testutils.NewChannel(), 975 scStateCh: testutils.NewChannel(), 976 resolverErrCh: testutils.NewChannel(), 977 closeCh: testutils.NewChannel(), 978 cc: cc, 979 } 980 } 981 982 func (mockBalancerBuilder2) Name() string { 983 return balancerName2 984 } 985 986 type verifyBalancerBuilder struct{} 987 988 func (verifyBalancerBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { 989 return &verifyBalancer{ 990 closed: grpcsync.NewEvent(), 991 cc: cc, 992 } 993 } 994 995 func (verifyBalancerBuilder) Name() string { 996 return verifyBalName 997 } 998 999 // verifyBalancer is a balancer that verifies that after a Close() call, a 1000 // StateListener() call never happens. 1001 type verifyBalancer struct { 1002 closed *grpcsync.Event 1003 // Hold onto the ClientConn wrapper to communicate with it. 1004 cc balancer.ClientConn 1005 // To fail the test if StateListener gets called after Close(). 1006 t *testing.T 1007 } 1008 1009 func (vb *verifyBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error { 1010 return nil 1011 } 1012 1013 func (vb *verifyBalancer) ResolverError(err error) {} 1014 1015 func (vb *verifyBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { 1016 panic(fmt.Sprintf("UpdateSubConnState(%v, %+v) called unexpectedly", sc, state)) 1017 } 1018 1019 func (vb *verifyBalancer) Close() { 1020 vb.closed.Fire() 1021 } 1022 1023 func (vb *verifyBalancer) newSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (sc balancer.SubConn, err error) { 1024 if opts.StateListener == nil { 1025 opts.StateListener = func(state balancer.SubConnState) { 1026 if vb.closed.HasFired() { 1027 vb.t.Fatalf("StateListener(%+v) was called after Close(), which breaks the balancer API", state) 1028 } 1029 } 1030 } 1031 defer func() { sc.Connect() }() 1032 return vb.cc.NewSubConn(addrs, opts) 1033 } 1034 1035 type buildCallbackBalancerBuilder struct{} 1036 1037 func (buildCallbackBalancerBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { 1038 b := &buildCallbackBal{ 1039 cc: cc, 1040 closeCh: testutils.NewChannel(), 1041 } 1042 b.updateState(balancer.State{ 1043 ConnectivityState: connectivity.Connecting, 1044 }) 1045 sc, err := b.newSubConn([]resolver.Address{}, balancer.NewSubConnOptions{}) 1046 if err != nil { 1047 return nil 1048 } 1049 b.updateAddresses(sc, []resolver.Address{}) 1050 sc.Shutdown() 1051 return b 1052 } 1053 1054 func (buildCallbackBalancerBuilder) Name() string { 1055 return buildCallbackBalName 1056 } 1057 1058 type buildCallbackBal struct { 1059 // Hold onto the ClientConn wrapper to communicate with it. 1060 cc balancer.ClientConn 1061 // closeCh is a channel used to signal the closing of this balancer. 1062 closeCh *testutils.Channel 1063 } 1064 1065 func (bcb *buildCallbackBal) UpdateClientConnState(ccs balancer.ClientConnState) error { 1066 return nil 1067 } 1068 1069 func (bcb *buildCallbackBal) ResolverError(err error) {} 1070 1071 func (bcb *buildCallbackBal) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { 1072 panic(fmt.Sprintf("UpdateSubConnState(%v, %+v) called unexpectedly", sc, state)) 1073 } 1074 1075 func (bcb *buildCallbackBal) Close() { 1076 bcb.closeCh.Send(struct{}{}) 1077 } 1078 1079 func (bcb *buildCallbackBal) updateState(state balancer.State) { 1080 bcb.cc.UpdateState(state) 1081 } 1082 1083 func (bcb *buildCallbackBal) newSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (sc balancer.SubConn, err error) { 1084 defer func() { 1085 if sc != nil { 1086 sc.Connect() 1087 } 1088 }() 1089 return bcb.cc.NewSubConn(addrs, opts) 1090 } 1091 1092 func (bcb *buildCallbackBal) updateAddresses(sc balancer.SubConn, addrs []resolver.Address) { 1093 bcb.cc.UpdateAddresses(sc, addrs) 1094 } 1095 1096 // waitForClose verifies that the mockBalancer is closed before the context 1097 // expires. 1098 func (bcb *buildCallbackBal) waitForClose(ctx context.Context) error { 1099 if _, err := bcb.closeCh.Receive(ctx); err != nil { 1100 return err 1101 } 1102 return nil 1103 }