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 19package grpc 20 21import ( 22 "fmt" 23 "net" 24 "testing" 25 26 "google.golang.org/grpc/balancer" 27 "google.golang.org/grpc/balancer/roundrobin" 28 "google.golang.org/grpc/connectivity" 29 "google.golang.org/grpc/resolver" 30 "google.golang.org/grpc/resolver/manual" 31) 32 33var _ balancer.V2Balancer = &funcBalancer{} 34 35type funcBalancer struct { 36 updateClientConnState func(s balancer.ClientConnState) error 37} 38 39func (*funcBalancer) HandleSubConnStateChange(balancer.SubConn, connectivity.State) { 40 panic("unimplemented") // v1 API 41} 42func (*funcBalancer) HandleResolvedAddrs([]resolver.Address, error) { 43 panic("unimplemented") // v1 API 44} 45func (b *funcBalancer) UpdateClientConnState(s balancer.ClientConnState) error { 46 return b.updateClientConnState(s) 47} 48func (*funcBalancer) ResolverError(error) {} 49func (*funcBalancer) UpdateSubConnState(balancer.SubConn, balancer.SubConnState) { 50 panic("unimplemented") // we never have sub-conns 51} 52func (*funcBalancer) Close() {} 53 54type funcBalancerBuilder struct { 55 name string 56 instance *funcBalancer 57} 58 59func (b *funcBalancerBuilder) Build(balancer.ClientConn, balancer.BuildOptions) balancer.Balancer { 60 return b.instance 61} 62func (b *funcBalancerBuilder) Name() string { return b.name } 63 64// TestBalancerErrorResolverPolling injects balancer errors and verifies 65// ResolveNow is called on the resolver with the appropriate backoff strategy 66// being consulted between ResolveNow calls. 67func (s) TestBalancerErrorResolverPolling(t *testing.T) { 68 // The test balancer will return ErrBadResolverState iff the 69 // ClientConnState contains no addresses. 70 fb := &funcBalancer{ 71 updateClientConnState: func(s balancer.ClientConnState) error { 72 if len(s.ResolverState.Addresses) == 0 { 73 return balancer.ErrBadResolverState 74 } 75 return nil 76 }, 77 } 78 const balName = "BalancerErrorResolverPolling" 79 balancer.Register(&funcBalancerBuilder{name: balName, instance: fb}) 80 81 testResolverErrorPolling(t, 82 func(r *manual.Resolver) { 83 // No addresses so the balancer will fail. 84 r.CC.UpdateState(resolver.State{}) 85 }, func(r *manual.Resolver) { 86 // UpdateState will block if ResolveNow is being called (which blocks on 87 // rn), so call it in a goroutine. Include some address so the balancer 88 // will be happy. 89 go r.CC.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "x"}}}) 90 }, 91 WithDefaultServiceConfig(fmt.Sprintf(`{ "loadBalancingConfig": [{"%v": {}}] }`, balName))) 92} 93 94// TestRoundRobinZeroAddressesResolverPolling reports no addresses to the round 95// robin balancer and verifies ResolveNow is called on the resolver with the 96// appropriate backoff strategy being consulted between ResolveNow calls. 97func (s) TestRoundRobinZeroAddressesResolverPolling(t *testing.T) { 98 // We need to start a real server or else the connecting loop will call 99 // ResolveNow after every iteration, even after a valid resolver result is 100 // returned. 101 lis, err := net.Listen("tcp", "localhost:0") 102 if err != nil { 103 t.Fatalf("Error while listening. Err: %v", err) 104 } 105 defer lis.Close() 106 s := NewServer() 107 defer s.Stop() 108 go s.Serve(lis) 109 110 testResolverErrorPolling(t, 111 func(r *manual.Resolver) { 112 // No addresses so the balancer will fail. 113 r.CC.UpdateState(resolver.State{}) 114 }, func(r *manual.Resolver) { 115 // UpdateState will block if ResolveNow is being called (which 116 // blocks on rn), so call it in a goroutine. Include a valid 117 // address so the balancer will be happy. 118 go r.CC.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: lis.Addr().String()}}}) 119 }, 120 WithDefaultServiceConfig(fmt.Sprintf(`{ "loadBalancingConfig": [{"%v": {}}] }`, roundrobin.Name))) 121} 122