1/* 2 * 3 * Copyright 2017 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 "context" 23 "errors" 24 "fmt" 25 "net" 26 "strings" 27 "testing" 28 "time" 29 30 "google.golang.org/grpc/balancer" 31 "google.golang.org/grpc/codes" 32 "google.golang.org/grpc/internal/balancer/stub" 33 "google.golang.org/grpc/resolver" 34 "google.golang.org/grpc/resolver/manual" 35 "google.golang.org/grpc/serviceconfig" 36 "google.golang.org/grpc/status" 37) 38 39// The target string with unknown scheme should be kept unchanged and passed to 40// the dialer. 41func (s) TestDialParseTargetUnknownScheme(t *testing.T) { 42 for _, test := range []struct { 43 targetStr string 44 want string 45 }{ 46 {"/unix/socket/address", "/unix/socket/address"}, 47 48 // For known scheme. 49 {"passthrough://a.server.com/google.com", "google.com"}, 50 } { 51 dialStrCh := make(chan string, 1) 52 cc, err := Dial(test.targetStr, WithInsecure(), WithDialer(func(addr string, _ time.Duration) (net.Conn, error) { 53 select { 54 case dialStrCh <- addr: 55 default: 56 } 57 return nil, fmt.Errorf("test dialer, always error") 58 })) 59 if err != nil { 60 t.Fatalf("Failed to create ClientConn: %v", err) 61 } 62 got := <-dialStrCh 63 cc.Close() 64 if got != test.want { 65 t.Errorf("Dial(%q), dialer got %q, want %q", test.targetStr, got, test.want) 66 } 67 } 68} 69 70const happyBalancerName = "happy balancer" 71 72func init() { 73 // Register a balancer that never returns an error from 74 // UpdateClientConnState, and doesn't do anything else either. 75 bf := stub.BalancerFuncs{ 76 UpdateClientConnState: func(*stub.BalancerData, balancer.ClientConnState) error { 77 return nil 78 }, 79 } 80 stub.Register(happyBalancerName, bf) 81} 82 83// TestResolverErrorInBuild makes the resolver.Builder call into the ClientConn 84// during the Build call. We use two separate mutexes in the code which make 85// sure there is no data race in this code path, and also that there is no 86// deadlock. 87func (s) TestResolverErrorInBuild(t *testing.T) { 88 r := manual.NewBuilderWithScheme("whatever") 89 r.InitialState(resolver.State{ServiceConfig: &serviceconfig.ParseResult{Err: errors.New("resolver build err")}}) 90 91 cc, err := Dial(r.Scheme()+":///test.server", WithInsecure(), WithResolvers(r)) 92 if err != nil { 93 t.Fatalf("Dial(_, _) = _, %v; want _, nil", err) 94 } 95 defer cc.Close() 96 97 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 98 defer cancel() 99 var dummy int 100 const wantMsg = "error parsing service config" 101 const wantCode = codes.Unavailable 102 if err := cc.Invoke(ctx, "/foo/bar", &dummy, &dummy); status.Code(err) != wantCode || !strings.Contains(status.Convert(err).Message(), wantMsg) { 103 t.Fatalf("cc.Invoke(_, _, _, _) = %v; want status.Code()==%v, status.Message() contains %q", err, wantCode, wantMsg) 104 } 105} 106 107func (s) TestServiceConfigErrorRPC(t *testing.T) { 108 r := manual.NewBuilderWithScheme("whatever") 109 110 cc, err := Dial(r.Scheme()+":///test.server", WithInsecure(), WithResolvers(r)) 111 if err != nil { 112 t.Fatalf("Dial(_, _) = _, %v; want _, nil", err) 113 } 114 defer cc.Close() 115 badsc := r.CC.ParseServiceConfig("bad config") 116 r.UpdateState(resolver.State{ServiceConfig: badsc}) 117 118 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 119 defer cancel() 120 var dummy int 121 const wantMsg = "error parsing service config" 122 const wantCode = codes.Unavailable 123 if err := cc.Invoke(ctx, "/foo/bar", &dummy, &dummy); status.Code(err) != wantCode || !strings.Contains(status.Convert(err).Message(), wantMsg) { 124 t.Fatalf("cc.Invoke(_, _, _, _) = %v; want status.Code()==%v, status.Message() contains %q", err, wantCode, wantMsg) 125 } 126} 127