| /* |
| * |
| * Copyright 2019 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package grpc |
| |
| import ( |
| "fmt" |
| "net" |
| "testing" |
| |
| "google.golang.org/grpc/balancer" |
| "google.golang.org/grpc/balancer/roundrobin" |
| "google.golang.org/grpc/internal/balancer/stub" |
| "google.golang.org/grpc/resolver" |
| "google.golang.org/grpc/resolver/manual" |
| ) |
| |
| // TestBalancerErrorResolverPolling injects balancer errors and verifies |
| // ResolveNow is called on the resolver with the appropriate backoff strategy |
| // being consulted between ResolveNow calls. |
| func (s) TestBalancerErrorResolverPolling(t *testing.T) { |
| // The test balancer will return ErrBadResolverState iff the |
| // ClientConnState contains no addresses. |
| bf := stub.BalancerFuncs{ |
| UpdateClientConnState: func(_ *stub.BalancerData, s balancer.ClientConnState) error { |
| if len(s.ResolverState.Addresses) == 0 { |
| return balancer.ErrBadResolverState |
| } |
| return nil |
| }, |
| } |
| const balName = "BalancerErrorResolverPolling" |
| stub.Register(balName, bf) |
| |
| testResolverErrorPolling(t, |
| func(r *manual.Resolver) { |
| // No addresses so the balancer will fail. |
| r.CC.UpdateState(resolver.State{}) |
| }, func(r *manual.Resolver) { |
| // UpdateState will block if ResolveNow is being called (which blocks on |
| // rn), so call it in a goroutine. Include some address so the balancer |
| // will be happy. |
| go r.CC.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "x"}}}) |
| }, |
| WithDefaultServiceConfig(fmt.Sprintf(`{ "loadBalancingConfig": [{"%v": {}}] }`, balName))) |
| } |
| |
| // TestRoundRobinZeroAddressesResolverPolling reports no addresses to the round |
| // robin balancer and verifies ResolveNow is called on the resolver with the |
| // appropriate backoff strategy being consulted between ResolveNow calls. |
| func (s) TestRoundRobinZeroAddressesResolverPolling(t *testing.T) { |
| // We need to start a real server or else the connecting loop will call |
| // ResolveNow after every iteration, even after a valid resolver result is |
| // returned. |
| lis, err := net.Listen("tcp", "localhost:0") |
| if err != nil { |
| t.Fatalf("Error while listening. Err: %v", err) |
| } |
| defer lis.Close() |
| s := NewServer() |
| defer s.Stop() |
| go s.Serve(lis) |
| |
| testResolverErrorPolling(t, |
| func(r *manual.Resolver) { |
| // No addresses so the balancer will fail. |
| r.CC.UpdateState(resolver.State{}) |
| }, func(r *manual.Resolver) { |
| // UpdateState will block if ResolveNow is being called (which |
| // blocks on rn), so call it in a goroutine. Include a valid |
| // address so the balancer will be happy. |
| go r.CC.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: lis.Addr().String()}}}) |
| }, |
| WithDefaultServiceConfig(fmt.Sprintf(`{ "loadBalancingConfig": [{"%v": {}}] }`, roundrobin.Name))) |
| } |