...

Source file src/google.golang.org/grpc/test/control_plane_status_test.go

Documentation: google.golang.org/grpc/test

     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 test
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"google.golang.org/grpc"
    28  	"google.golang.org/grpc/balancer"
    29  	"google.golang.org/grpc/balancer/base"
    30  	"google.golang.org/grpc/codes"
    31  	"google.golang.org/grpc/connectivity"
    32  	"google.golang.org/grpc/internal/balancer/stub"
    33  	iresolver "google.golang.org/grpc/internal/resolver"
    34  	"google.golang.org/grpc/internal/stubserver"
    35  	testpb "google.golang.org/grpc/interop/grpc_testing"
    36  	"google.golang.org/grpc/resolver"
    37  	"google.golang.org/grpc/resolver/manual"
    38  	"google.golang.org/grpc/status"
    39  )
    40  
    41  func (s) TestConfigSelectorStatusCodes(t *testing.T) {
    42  	testCases := []struct {
    43  		name  string
    44  		csErr error
    45  		want  error
    46  	}{{
    47  		name:  "legal status code",
    48  		csErr: status.Errorf(codes.Unavailable, "this error is fine"),
    49  		want:  status.Errorf(codes.Unavailable, "this error is fine"),
    50  	}, {
    51  		name:  "illegal status code",
    52  		csErr: status.Errorf(codes.NotFound, "this error is bad"),
    53  		want:  status.Errorf(codes.Internal, "this error is bad"),
    54  	}}
    55  
    56  	for _, tc := range testCases {
    57  		t.Run(tc.name, func(t *testing.T) {
    58  			ss := &stubserver.StubServer{
    59  				EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
    60  					return &testpb.Empty{}, nil
    61  				},
    62  			}
    63  			ss.R = manual.NewBuilderWithScheme("confSel")
    64  
    65  			if err := ss.Start(nil); err != nil {
    66  				t.Fatalf("Error starting endpoint server: %v", err)
    67  			}
    68  			defer ss.Stop()
    69  
    70  			state := iresolver.SetConfigSelector(resolver.State{
    71  				Addresses:     []resolver.Address{{Addr: ss.Address}},
    72  				ServiceConfig: parseServiceConfig(t, ss.R, "{}"),
    73  			}, funcConfigSelector{
    74  				f: func(i iresolver.RPCInfo) (*iresolver.RPCConfig, error) {
    75  					return nil, tc.csErr
    76  				},
    77  			})
    78  			ss.R.UpdateState(state) // Blocks until config selector is applied
    79  
    80  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    81  			defer cancel()
    82  			if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != status.Code(tc.want) || !strings.Contains(err.Error(), status.Convert(tc.want).Message()) {
    83  				t.Fatalf("client.EmptyCall(_, _) = _, %v; want _, %v", err, tc.want)
    84  			}
    85  		})
    86  	}
    87  }
    88  
    89  func (s) TestPickerStatusCodes(t *testing.T) {
    90  	testCases := []struct {
    91  		name      string
    92  		pickerErr error
    93  		want      error
    94  	}{{
    95  		name:      "legal status code",
    96  		pickerErr: status.Errorf(codes.Unavailable, "this error is fine"),
    97  		want:      status.Errorf(codes.Unavailable, "this error is fine"),
    98  	}, {
    99  		name:      "illegal status code",
   100  		pickerErr: status.Errorf(codes.NotFound, "this error is bad"),
   101  		want:      status.Errorf(codes.Internal, "this error is bad"),
   102  	}}
   103  
   104  	for _, tc := range testCases {
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			ss := &stubserver.StubServer{
   107  				EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
   108  					return &testpb.Empty{}, nil
   109  				},
   110  			}
   111  
   112  			if err := ss.Start(nil); err != nil {
   113  				t.Fatalf("Error starting endpoint server: %v", err)
   114  			}
   115  			defer ss.Stop()
   116  
   117  			// Create a stub balancer that creates a picker that always returns
   118  			// an error.
   119  			sbf := stub.BalancerFuncs{
   120  				UpdateClientConnState: func(d *stub.BalancerData, _ balancer.ClientConnState) error {
   121  					d.ClientConn.UpdateState(balancer.State{
   122  						ConnectivityState: connectivity.TransientFailure,
   123  						Picker:            base.NewErrPicker(tc.pickerErr),
   124  					})
   125  					return nil
   126  				},
   127  			}
   128  			stub.Register("testPickerStatusCodesBalancer", sbf)
   129  
   130  			ss.NewServiceConfig(`{"loadBalancingConfig": [{"testPickerStatusCodesBalancer":{}}] }`)
   131  
   132  			// Make calls until pickerErr is received.
   133  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   134  			defer cancel()
   135  
   136  			var lastErr error
   137  			for ctx.Err() == nil {
   138  				if _, lastErr = ss.Client.EmptyCall(ctx, &testpb.Empty{}); status.Code(lastErr) == status.Code(tc.want) && strings.Contains(lastErr.Error(), status.Convert(tc.want).Message()) {
   139  					// Success!
   140  					return
   141  				}
   142  				time.Sleep(time.Millisecond)
   143  			}
   144  
   145  			t.Fatalf("client.EmptyCall(_, _) = _, %v; want _, %v", lastErr, tc.want)
   146  		})
   147  	}
   148  }
   149  
   150  func (s) TestCallCredsFromDialOptionsStatusCodes(t *testing.T) {
   151  	testCases := []struct {
   152  		name     string
   153  		credsErr error
   154  		want     error
   155  	}{{
   156  		name:     "legal status code",
   157  		credsErr: status.Errorf(codes.Unavailable, "this error is fine"),
   158  		want:     status.Errorf(codes.Unavailable, "this error is fine"),
   159  	}, {
   160  		name:     "illegal status code",
   161  		credsErr: status.Errorf(codes.NotFound, "this error is bad"),
   162  		want:     status.Errorf(codes.Internal, "this error is bad"),
   163  	}}
   164  
   165  	for _, tc := range testCases {
   166  		t.Run(tc.name, func(t *testing.T) {
   167  			ss := &stubserver.StubServer{
   168  				EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
   169  					return &testpb.Empty{}, nil
   170  				},
   171  			}
   172  
   173  			errChan := make(chan error, 1)
   174  			creds := &testPerRPCCredentials{errChan: errChan}
   175  
   176  			if err := ss.Start(nil, grpc.WithPerRPCCredentials(creds)); err != nil {
   177  				t.Fatalf("Error starting endpoint server: %v", err)
   178  			}
   179  			defer ss.Stop()
   180  
   181  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   182  			defer cancel()
   183  
   184  			errChan <- tc.credsErr
   185  
   186  			if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != status.Code(tc.want) || !strings.Contains(err.Error(), status.Convert(tc.want).Message()) {
   187  				t.Fatalf("client.EmptyCall(_, _) = _, %v; want _, %v", err, tc.want)
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func (s) TestCallCredsFromCallOptionsStatusCodes(t *testing.T) {
   194  	testCases := []struct {
   195  		name     string
   196  		credsErr error
   197  		want     error
   198  	}{{
   199  		name:     "legal status code",
   200  		credsErr: status.Errorf(codes.Unavailable, "this error is fine"),
   201  		want:     status.Errorf(codes.Unavailable, "this error is fine"),
   202  	}, {
   203  		name:     "illegal status code",
   204  		credsErr: status.Errorf(codes.NotFound, "this error is bad"),
   205  		want:     status.Errorf(codes.Internal, "this error is bad"),
   206  	}}
   207  
   208  	for _, tc := range testCases {
   209  		t.Run(tc.name, func(t *testing.T) {
   210  			ss := &stubserver.StubServer{
   211  				EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
   212  					return &testpb.Empty{}, nil
   213  				},
   214  			}
   215  
   216  			errChan := make(chan error, 1)
   217  			creds := &testPerRPCCredentials{errChan: errChan}
   218  
   219  			if err := ss.Start(nil); err != nil {
   220  				t.Fatalf("Error starting endpoint server: %v", err)
   221  			}
   222  			defer ss.Stop()
   223  
   224  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   225  			defer cancel()
   226  
   227  			errChan <- tc.credsErr
   228  
   229  			if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}, grpc.PerRPCCredentials(creds)); status.Code(err) != status.Code(tc.want) || !strings.Contains(err.Error(), status.Convert(tc.want).Message()) {
   230  				t.Fatalf("client.EmptyCall(_, _) = _, %v; want _, %v", err, tc.want)
   231  			}
   232  		})
   233  	}
   234  }
   235  

View as plain text