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 "testing" 24 25 "google.golang.org/grpc/balancer" 26 "google.golang.org/grpc/connectivity" 27 "google.golang.org/grpc/resolver" 28 "google.golang.org/grpc/resolver/manual" 29) 30 31var _ balancer.V2Balancer = &funcBalancer{} 32 33type funcBalancer struct { 34 updateClientConnState func(s balancer.ClientConnState) error 35} 36 37func (*funcBalancer) HandleSubConnStateChange(balancer.SubConn, connectivity.State) { 38 panic("unimplemented") // v1 API 39} 40func (*funcBalancer) HandleResolvedAddrs([]resolver.Address, error) { 41 panic("unimplemented") // v1 API 42} 43func (b *funcBalancer) UpdateClientConnState(s balancer.ClientConnState) error { 44 return b.updateClientConnState(s) 45} 46func (*funcBalancer) ResolverError(error) { 47 panic("unimplemented") // resolver never reports error 48} 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