github.com/cloudwego/kitex@v0.9.0/client/option_test.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package client 18 19 import ( 20 "context" 21 "crypto/tls" 22 "fmt" 23 "reflect" 24 "testing" 25 "time" 26 27 "github.com/golang/mock/gomock" 28 29 "github.com/cloudwego/kitex/internal/client" 30 "github.com/cloudwego/kitex/internal/mocks" 31 mocksloadbalance "github.com/cloudwego/kitex/internal/mocks/loadbalance" 32 mocksnetpoll "github.com/cloudwego/kitex/internal/mocks/netpoll" 33 mocksproxy "github.com/cloudwego/kitex/internal/mocks/proxy" 34 mock_remote "github.com/cloudwego/kitex/internal/mocks/remote" 35 "github.com/cloudwego/kitex/internal/mocks/rpc_info" 36 "github.com/cloudwego/kitex/internal/test" 37 "github.com/cloudwego/kitex/pkg/circuitbreak" 38 "github.com/cloudwego/kitex/pkg/connpool" 39 "github.com/cloudwego/kitex/pkg/diagnosis" 40 "github.com/cloudwego/kitex/pkg/discovery" 41 "github.com/cloudwego/kitex/pkg/endpoint" 42 "github.com/cloudwego/kitex/pkg/generic" 43 "github.com/cloudwego/kitex/pkg/http" 44 "github.com/cloudwego/kitex/pkg/loadbalance" 45 "github.com/cloudwego/kitex/pkg/proxy" 46 "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/grpc" 47 "github.com/cloudwego/kitex/pkg/retry" 48 "github.com/cloudwego/kitex/pkg/rpcinfo" 49 "github.com/cloudwego/kitex/pkg/rpcinfo/remoteinfo" 50 "github.com/cloudwego/kitex/pkg/stats" 51 "github.com/cloudwego/kitex/pkg/xds" 52 "github.com/cloudwego/kitex/transport" 53 ) 54 55 func TestRetryOptionDebugInfo(t *testing.T) { 56 fp := retry.NewFailurePolicy() 57 fp.WithDDLStop() 58 expectPolicyStr := "WithFailureRetry({StopPolicy:{MaxRetryTimes:2 MaxDurationMS:0 DisableChainStop:false DDLStop:true " + 59 "CBPolicy:{ErrorRate:0.1}} BackOffPolicy:&{BackOffType:none CfgItems:map[]} RetrySameNode:false ShouldResultRetry:{ErrorRetry:false, RespRetry:false}})" 60 policyStr := fmt.Sprintf("WithFailureRetry(%+v)", *fp) 61 test.Assert(t, policyStr == expectPolicyStr, policyStr) 62 63 fp.WithFixedBackOff(10) 64 expectPolicyStr = "WithFailureRetry({StopPolicy:{MaxRetryTimes:2 MaxDurationMS:0 DisableChainStop:false DDLStop:true " + 65 "CBPolicy:{ErrorRate:0.1}} BackOffPolicy:&{BackOffType:fixed CfgItems:map[fix_ms:10]} RetrySameNode:false ShouldResultRetry:{ErrorRetry:false, RespRetry:false}})" 66 policyStr = fmt.Sprintf("WithFailureRetry(%+v)", *fp) 67 test.Assert(t, policyStr == expectPolicyStr, policyStr) 68 69 fp.WithRandomBackOff(10, 20) 70 fp.DisableChainRetryStop() 71 expectPolicyStr = "WithFailureRetry({StopPolicy:{MaxRetryTimes:2 MaxDurationMS:0 DisableChainStop:true DDLStop:true " + 72 "CBPolicy:{ErrorRate:0.1}} BackOffPolicy:&{BackOffType:random CfgItems:map[max_ms:20 min_ms:10]} RetrySameNode:false ShouldResultRetry:{ErrorRetry:false, RespRetry:false}})" 73 policyStr = fmt.Sprintf("WithFailureRetry(%+v)", *fp) 74 test.Assert(t, policyStr == expectPolicyStr, policyStr) 75 76 fp.WithRetrySameNode() 77 expectPolicyStr = "WithFailureRetry({StopPolicy:{MaxRetryTimes:2 MaxDurationMS:0 DisableChainStop:true DDLStop:true " + 78 "CBPolicy:{ErrorRate:0.1}} BackOffPolicy:&{BackOffType:random CfgItems:map[max_ms:20 min_ms:10]} RetrySameNode:true ShouldResultRetry:{ErrorRetry:false, RespRetry:false}})" 79 policyStr = fmt.Sprintf("WithFailureRetry(%+v)", *fp) 80 test.Assert(t, policyStr == expectPolicyStr, policyStr) 81 82 fp.WithSpecifiedResultRetry(&retry.ShouldResultRetry{ErrorRetry: func(err error, ri rpcinfo.RPCInfo) bool { 83 return false 84 }}) 85 expectPolicyStr = "WithFailureRetry({StopPolicy:{MaxRetryTimes:2 MaxDurationMS:0 DisableChainStop:true DDLStop:true " + 86 "CBPolicy:{ErrorRate:0.1}} BackOffPolicy:&{BackOffType:random CfgItems:map[max_ms:20 min_ms:10]} RetrySameNode:true ShouldResultRetry:{ErrorRetry:true, RespRetry:false}})" 87 policyStr = fmt.Sprintf("WithFailureRetry(%+v)", *fp) 88 test.Assert(t, policyStr == expectPolicyStr, policyStr) 89 90 bp := retry.NewBackupPolicy(20) 91 expectPolicyStr = "WithBackupRequest({RetryDelayMS:20 StopPolicy:{MaxRetryTimes:1 MaxDurationMS:0 DisableChainStop:false " + 92 "DDLStop:false CBPolicy:{ErrorRate:0.1}} RetrySameNode:false})" 93 policyStr = fmt.Sprintf("WithBackupRequest(%+v)", *bp) 94 test.Assert(t, policyStr == expectPolicyStr, policyStr) 95 WithBackupRequest(bp) 96 } 97 98 func TestRetryOption(t *testing.T) { 99 defer func() { 100 err := recover() 101 test.Assert(t, err != nil) 102 }() 103 fp := retry.NewFailurePolicy() 104 var options []client.Option 105 options = append(options, WithFailureRetry(fp)) 106 bp := retry.NewBackupPolicy(20) 107 options = append(options, WithBackupRequest(bp)) 108 109 client.NewOptions(options) 110 // both setup failure and backup retry, panic should happen 111 test.Assert(t, false) 112 } 113 114 func TestTransportProtocolOption(t *testing.T) { 115 var options []client.Option 116 options = append(options, WithTransportProtocol(transport.GRPC)) 117 client.NewOptions(options) 118 } 119 120 func TestWithHostPorts(t *testing.T) { 121 var options []client.Option 122 options = append(options, WithHostPorts("127.0.0.1:8080")) 123 opts := client.NewOptions(options) 124 test.Assert(t, opts.Resolver.Name() == "127.0.0.1:8080") 125 res, err := opts.Resolver.Resolve(context.Background(), "") 126 test.Assert(t, err == nil) 127 test.Assert(t, res.Instances[0].Address().String() == "127.0.0.1:8080") 128 } 129 130 func TestForwardProxy(t *testing.T) { 131 ctrl := gomock.NewController(t) 132 defer ctrl.Finish() 133 134 fp := mocksproxy.NewMockForwardProxy(ctrl) 135 fp.EXPECT().Configure(gomock.Any()).DoAndReturn(func(cfg *proxy.Config) error { 136 test.Assert(t, cfg.Resolver == nil, cfg.Resolver) 137 test.Assert(t, cfg.Balancer == nil, cfg.Balancer) 138 return nil 139 }).AnyTimes() 140 fp.EXPECT().ResolveProxyInstance(gomock.Any()).DoAndReturn(func(ctx context.Context) error { 141 ri := rpcinfo.GetRPCInfo(ctx) 142 re := remoteinfo.AsRemoteInfo(ri.To()) 143 in := re.GetInstance() 144 test.Assert(t, in == nil, in) 145 re.SetInstance(instance505) 146 return nil 147 }).AnyTimes() 148 149 var opts []Option 150 opts = append(opts, WithTransHandlerFactory(newMockCliTransHandlerFactory(ctrl))) 151 opts = append(opts, WithDialer(newDialer(ctrl))) 152 opts = append(opts, WithDestService("destService")) 153 opts = append(opts, WithProxy(fp)) 154 155 svcInfo := mocks.ServiceInfo() 156 // Configure long pool and check if the pool is closed when initProxy 157 // If the proxy does not configure pool, use the predefined pool 158 mockLongPool := mock_remote.NewMockLongConnPool(ctrl) 159 var closed bool 160 mockLongPool.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mocksnetpoll.NewMockConnection(ctrl), nil).Times(1) 161 mockLongPool.EXPECT().Close().Do(func() { 162 closed = true 163 }).AnyTimes() 164 mockLongPool.EXPECT().Put(gomock.Any()).Return(nil).AnyTimes() 165 mockLongPool.EXPECT().Discard(gomock.Any()).Return(nil).AnyTimes() 166 opts = append(opts, WithConnPool(mockLongPool)) 167 cli, err := NewClient(svcInfo, opts...) 168 test.Assert(t, err == nil) 169 test.Assert(t, !closed) 170 mtd := mocks.MockMethod 171 ctx := context.Background() 172 req := new(MockTStruct) 173 res := new(MockTStruct) 174 175 err = cli.Call(ctx, mtd, req, res) 176 test.Assert(t, err == nil, err) 177 } 178 179 func TestProxyWithResolver(t *testing.T) { 180 ctrl := gomock.NewController(t) 181 defer ctrl.Finish() 182 183 resolver := resolver404(ctrl) 184 fp := mocksproxy.NewMockForwardProxy(ctrl) 185 fp.EXPECT().Configure(gomock.Any()).DoAndReturn(func(cfg *proxy.Config) error { 186 test.Assert(t, cfg.Resolver == resolver) 187 test.Assert(t, cfg.Balancer == nil, cfg.Balancer) 188 return nil 189 }).AnyTimes() 190 fp.EXPECT().ResolveProxyInstance(gomock.Any()).DoAndReturn(func(ctx context.Context) error { 191 ri := rpcinfo.GetRPCInfo(ctx) 192 re := remoteinfo.AsRemoteInfo(ri.To()) 193 in := re.GetInstance() 194 test.Assert(t, in == instance404[0]) 195 re.SetInstance(instance505) 196 return nil 197 }).AnyTimes() 198 199 var opts []Option 200 opts = append(opts, WithTransHandlerFactory(newMockCliTransHandlerFactory(ctrl))) 201 opts = append(opts, WithDialer(newDialer(ctrl))) 202 opts = append(opts, WithDestService("destService")) 203 opts = append(opts, WithProxy(fp)) 204 opts = append(opts, WithResolver(resolver)) 205 206 svcInfo := mocks.ServiceInfo() 207 cli, err := NewClient(svcInfo, opts...) 208 test.Assert(t, err == nil) 209 210 mtd := mocks.MockMethod 211 ctx := context.Background() 212 req := new(MockTStruct) 213 res := new(MockTStruct) 214 215 err = cli.Call(ctx, mtd, req, res) 216 test.Assert(t, err == nil, err) 217 } 218 219 func TestProxyWithBalancer(t *testing.T) { 220 ctrl := gomock.NewController(t) 221 defer ctrl.Finish() 222 223 lb := mocksloadbalance.NewMockLoadbalancer(ctrl) 224 lb.EXPECT().GetPicker(gomock.Any()).DoAndReturn(func(entry discovery.Result) loadbalance.Picker { 225 picker := mocksloadbalance.NewMockPicker(ctrl) 226 picker.EXPECT().Next(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, request interface{}) discovery.Instance { 227 if len(entry.Instances) > 0 { 228 return entry.Instances[0] 229 } 230 return nil 231 }).AnyTimes() 232 return picker 233 }).AnyTimes() 234 fp := mocksproxy.NewMockForwardProxy(ctrl) 235 fp.EXPECT().Configure(gomock.Any()).DoAndReturn(func(cfg *proxy.Config) error { 236 test.Assert(t, cfg.Resolver == nil, cfg.Resolver) 237 test.Assert(t, cfg.Balancer == lb) 238 return nil 239 }).AnyTimes() 240 fp.EXPECT().ResolveProxyInstance(gomock.Any()).DoAndReturn(func(ctx context.Context) error { 241 ri := rpcinfo.GetRPCInfo(ctx) 242 re := remoteinfo.AsRemoteInfo(ri.To()) 243 in := re.GetInstance() 244 test.Assert(t, in == nil) 245 re.SetInstance(instance505) 246 return nil 247 }).AnyTimes() 248 249 var opts []Option 250 opts = append(opts, WithTransHandlerFactory(newMockCliTransHandlerFactory(ctrl))) 251 opts = append(opts, WithDialer(newDialer(ctrl))) 252 opts = append(opts, WithDestService("destService")) 253 opts = append(opts, WithProxy(fp)) 254 opts = append(opts, WithLoadBalancer(lb)) 255 256 svcInfo := mocks.ServiceInfo() 257 cli, err := NewClient(svcInfo, opts...) 258 test.Assert(t, err == nil) 259 260 mtd := mocks.MockMethod 261 ctx := context.Background() 262 req := new(MockTStruct) 263 res := new(MockTStruct) 264 265 err = cli.Call(ctx, mtd, req, res) 266 test.Assert(t, err == nil) 267 } 268 269 func TestProxyWithResolverAndBalancer(t *testing.T) { 270 ctrl := gomock.NewController(t) 271 defer ctrl.Finish() 272 273 lb := mocksloadbalance.NewMockLoadbalancer(ctrl) 274 lb.EXPECT().GetPicker(gomock.Any()).DoAndReturn(func(entry discovery.Result) loadbalance.Picker { 275 picker := mocksloadbalance.NewMockPicker(ctrl) 276 picker.EXPECT().Next(gomock.Any(), gomock.Any()).Return(instance505).AnyTimes() 277 return picker 278 }).AnyTimes() 279 lb.EXPECT().Name().Return("mock_load_balancer").AnyTimes() 280 resolver := resolver404(ctrl) 281 fp := mocksproxy.NewMockForwardProxy(ctrl) 282 fp.EXPECT().Configure(gomock.Any()).DoAndReturn(func(cfg *proxy.Config) error { 283 test.Assert(t, cfg.Resolver == resolver) 284 test.Assert(t, cfg.Balancer == lb) 285 return nil 286 }).AnyTimes() 287 fp.EXPECT().ResolveProxyInstance(gomock.Any()).DoAndReturn(func(ctx context.Context) error { 288 ri := rpcinfo.GetRPCInfo(ctx) 289 re := remoteinfo.AsRemoteInfo(ri.To()) 290 in := re.GetInstance() 291 test.Assert(t, in == instance505) 292 return nil 293 }).AnyTimes() 294 295 var opts []Option 296 opts = append(opts, WithTransHandlerFactory(newMockCliTransHandlerFactory(ctrl))) 297 opts = append(opts, WithDialer(newDialer(ctrl))) 298 opts = append(opts, WithDestService("destService")) 299 opts = append(opts, WithProxy(fp)) 300 opts = append(opts, WithResolver(resolver)) 301 opts = append(opts, WithLoadBalancer(lb)) 302 303 svcInfo := mocks.ServiceInfo() 304 cli, err := NewClient(svcInfo, opts...) 305 test.Assert(t, err == nil) 306 307 mtd := mocks.MockMethod 308 ctx := context.Background() 309 req := new(MockTStruct) 310 res := new(MockTStruct) 311 312 err = cli.Call(ctx, mtd, req, res) 313 test.Assert(t, err == nil) 314 } 315 316 func TestProxyWithConnPool(t *testing.T) { 317 ctrl := gomock.NewController(t) 318 defer ctrl.Finish() 319 320 type mockLongConnPool struct { 321 *mock_remote.MockLongConnPool 322 *mock_remote.MockConnPoolReporter 323 } 324 325 fp := mocksproxy.NewMockForwardProxy(ctrl) 326 fp.EXPECT().Configure(gomock.Any()).DoAndReturn(func(cfg *proxy.Config) error { 327 cp := mock_remote.NewMockLongConnPool(ctrl) 328 cp.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mocksnetpoll.NewMockConnection(ctrl), nil).Times(1) 329 cp.EXPECT().Put(gomock.Any()).Return(nil).AnyTimes() 330 cp.EXPECT().Discard(gomock.Any()).Return(nil).AnyTimes() 331 cp.EXPECT().Close().Return(nil).Times(1) 332 rp := mock_remote.NewMockConnPoolReporter(ctrl) 333 rp.EXPECT().EnableReporter().Times(1) 334 cfg.Pool = &mockLongConnPool{cp, rp} 335 return nil 336 }).AnyTimes() 337 fp.EXPECT().ResolveProxyInstance(gomock.Any()).Return(nil).AnyTimes() 338 339 var opts []Option 340 opts = append(opts, WithTransHandlerFactory(newMockCliTransHandlerFactory(ctrl))) 341 opts = append(opts, WithDestService("destService")) 342 opts = append(opts, WithProxy(fp)) 343 opts = append(opts, WithConnReporterEnabled()) 344 opts = append(opts, WithResolver(resolver404(ctrl))) 345 // Preconfigured longConnPool should be closed because the proxy configured the pool 346 mockLongPool := mock_remote.NewMockLongConnPool(ctrl) 347 var closed bool 348 mockLongPool.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mocksnetpoll.NewMockConnection(ctrl), nil).Times(0) 349 mockLongPool.EXPECT().Close().Do(func() { 350 closed = true 351 }).AnyTimes() 352 mockLongPool.EXPECT().Put(gomock.Any()).Return(nil).AnyTimes() 353 mockLongPool.EXPECT().Discard(gomock.Any()).Return(nil).AnyTimes() 354 opts = append(opts, WithConnPool(mockLongPool)) 355 356 svcInfo := mocks.ServiceInfo() 357 cli, err := NewClient(svcInfo, opts...) 358 test.Assert(t, err == nil) 359 test.Assert(t, closed) // should be true 360 361 mtd := mocks.MockMethod 362 ctx := context.Background() 363 req := new(MockTStruct) 364 res := new(MockTStruct) 365 366 err = cli.Call(ctx, mtd, req, res) 367 test.Assert(t, err == nil) 368 369 err = cli.(interface{ Close() error }).Close() 370 test.Assert(t, err == nil) 371 } 372 373 var ( 374 // mock middleware, do nothing 375 md = func(next endpoint.Endpoint) endpoint.Endpoint { 376 return func(ctx context.Context, req, resp interface{}) (err error) { 377 return nil 378 } 379 } 380 httpResolver = http.NewDefaultResolver() 381 ) 382 383 type mockDiagnosis struct { 384 probes map[diagnosis.ProbeName]diagnosis.ProbeFunc 385 } 386 387 func (m *mockDiagnosis) RegisterProbeFunc(name diagnosis.ProbeName, probeFunc diagnosis.ProbeFunc) { 388 m.probes[name] = probeFunc 389 } 390 391 func (m *mockDiagnosis) ProbePairs() map[diagnosis.ProbeName]diagnosis.ProbeFunc { 392 return m.probes 393 } 394 395 func TestWithInstanceMW(t *testing.T) { 396 opts := client.NewOptions([]client.Option{WithInstanceMW(md)}) 397 test.Assert(t, len(opts.IMWBs) == 1, len(opts.IMWBs)) 398 } 399 400 func TestWithHTTPResolver(t *testing.T) { 401 opts := client.NewOptions([]client.Option{WithHTTPResolver(httpResolver)}) 402 test.DeepEqual(t, opts.HTTPResolver, httpResolver) 403 } 404 405 func TestShortConnection(t *testing.T) { 406 opts := client.NewOptions([]client.Option{WithShortConnection()}) 407 test.Assert(t, opts.PoolCfg != nil, opts.PoolCfg) 408 } 409 410 func TestWithMuxConnection(t *testing.T) { 411 connNum := 100 412 opts := client.NewOptions([]client.Option{WithMuxConnection(connNum)}) 413 test.Assert(t, opts.RemoteOpt.ConnPool != nil) 414 test.Assert(t, opts.RemoteOpt.CliHandlerFactory != nil) 415 test.Assert(t, opts.Configs.TransportProtocol() == transport.TTHeader, opts.Configs.TransportProtocol()) 416 } 417 418 func TestWithTimeoutProvider(t *testing.T) { 419 ctrl := gomock.NewController(t) 420 defer ctrl.Finish() 421 422 mockTimeoutProvider := rpc_info.NewMockTimeoutProvider(ctrl) 423 opts := client.NewOptions([]client.Option{WithTimeoutProvider(mockTimeoutProvider)}) 424 test.DeepEqual(t, opts.Timeouts, mockTimeoutProvider) 425 } 426 427 func TestWithStatsLevel(t *testing.T) { 428 opts := client.NewOptions([]client.Option{WithStatsLevel(stats.LevelDisabled)}) 429 test.Assert(t, opts.StatsLevel != nil && *opts.StatsLevel == stats.LevelDisabled, opts.StatsLevel) 430 } 431 432 func TestWithCodec(t *testing.T) { 433 ctrl := gomock.NewController(t) 434 defer ctrl.Finish() 435 436 mockCodec := mock_remote.NewMockCodec(ctrl) 437 opts := client.NewOptions([]client.Option{WithCodec(mockCodec)}) 438 test.DeepEqual(t, opts.RemoteOpt.Codec, mockCodec) 439 } 440 441 func TestWithPayloadCodec(t *testing.T) { 442 ctrl := gomock.NewController(t) 443 defer ctrl.Finish() 444 445 mockPayloadCodec := mock_remote.NewMockPayloadCodec(ctrl) 446 opts := client.NewOptions([]client.Option{WithPayloadCodec(mockPayloadCodec)}) 447 test.DeepEqual(t, opts.RemoteOpt.PayloadCodec, mockPayloadCodec) 448 } 449 450 func TestWithConnReporterEnabled(t *testing.T) { 451 opts := client.NewOptions([]client.Option{WithConnReporterEnabled()}) 452 test.Assert(t, opts.RemoteOpt.EnableConnPoolReporter) 453 } 454 455 func TestWithCircuitBreaker(t *testing.T) { 456 opts := client.NewOptions([]client.Option{ 457 WithCircuitBreaker(circuitbreak.NewCBSuite(func(ri rpcinfo.RPCInfo) string { return "" })), 458 }) 459 test.Assert(t, opts.CBSuite != nil) 460 } 461 462 const mockUint32Size uint32 = 0 463 464 func TestWithGRPCConnPoolSize(t *testing.T) { 465 opts := client.NewOptions([]client.Option{WithGRPCConnPoolSize(mockUint32Size)}) 466 test.Assert(t, opts.GRPCConnPoolSize == mockUint32Size, opts.GRPCConnPoolSize) 467 } 468 469 func TestWithGRPCInitialWindowSize(t *testing.T) { 470 opts := client.NewOptions([]client.Option{WithGRPCInitialWindowSize(mockUint32Size)}) 471 test.Assert(t, opts.GRPCConnectOpts.InitialWindowSize == mockUint32Size, opts.GRPCConnectOpts.InitialWindowSize) 472 } 473 474 func TestWithGRPCInitialConnWindowSize(t *testing.T) { 475 opts := client.NewOptions([]client.Option{WithGRPCInitialConnWindowSize(mockUint32Size)}) 476 test.Assert(t, opts.GRPCConnectOpts.InitialConnWindowSize == mockUint32Size, 477 opts.GRPCConnectOpts.InitialConnWindowSize) 478 } 479 480 func TestWithGRPCMaxHeaderListSize(t *testing.T) { 481 opts := client.NewOptions([]client.Option{WithGRPCMaxHeaderListSize(mockUint32Size)}) 482 test.Assert(t, 483 opts.GRPCConnectOpts.MaxHeaderListSize != nil && 484 *opts.GRPCConnectOpts.MaxHeaderListSize == mockUint32Size, 485 opts.GRPCConnectOpts.MaxHeaderListSize) 486 } 487 488 func TestWithGRPCKeepaliveParams(t *testing.T) { 489 opts := client.NewOptions( 490 []client.Option{ 491 WithGRPCKeepaliveParams(grpc.ClientKeepalive{ 492 Time: 5 * time.Second, // less than grpc.KeepaliveMinPingTime(5s) 493 Timeout: 20 * time.Second, 494 PermitWithoutStream: true, 495 }), 496 }) 497 test.Assert(t, opts.GRPCConnectOpts.KeepaliveParams.Time == grpc.KeepaliveMinPingTime, 498 opts.GRPCConnectOpts.KeepaliveParams.Time) 499 test.Assert(t, opts.GRPCConnectOpts.KeepaliveParams.Timeout == 20*time.Second, 500 opts.GRPCConnectOpts.KeepaliveParams.Timeout) 501 test.Assert(t, opts.GRPCConnectOpts.KeepaliveParams.PermitWithoutStream) 502 } 503 504 func TestWithHTTPConnection(t *testing.T) { 505 opts := client.NewOptions([]client.Option{WithHTTPConnection()}) 506 test.Assert(t, opts.RemoteOpt.CliHandlerFactory != nil) 507 } 508 509 func TestWithClientBasicInfo(t *testing.T) { 510 mockEBI := &rpcinfo.EndpointBasicInfo{} 511 opts := client.NewOptions([]client.Option{WithClientBasicInfo(mockEBI)}) 512 test.Assert(t, opts.Cli == mockEBI) 513 } 514 515 func TestWithDiagnosisService(t *testing.T) { 516 mockDS := &mockDiagnosis{ 517 make(map[diagnosis.ProbeName]diagnosis.ProbeFunc), 518 } 519 opts := client.NewOptions([]client.Option{ 520 WithDiagnosisService(mockDS), 521 }) 522 test.Assert(t, opts.DebugService == mockDS, opts.DebugService) 523 } 524 525 func mockACLRule(ctx context.Context, request interface{}) (reason error) { 526 return nil 527 } 528 529 func TestWithACLRules(t *testing.T) { 530 opts := client.NewOptions([]client.Option{WithACLRules(mockACLRule)}) 531 test.Assert(t, reflect.ValueOf(mockACLRule).Pointer() == reflect.ValueOf(opts.ACLRules[0]).Pointer()) 532 } 533 534 func TestWithFirstMetaHandler(t *testing.T) { 535 mockMetaHandler := &mock_remote.MockMetaHandler{} 536 opts := client.NewOptions([]client.Option{WithFirstMetaHandler(mockMetaHandler)}) 537 test.DeepEqual(t, opts.MetaHandlers[0], mockMetaHandler) 538 } 539 540 func TestWithMetaHandler(t *testing.T) { 541 mockMetaHandler := &mock_remote.MockMetaHandler{} 542 opts := client.NewOptions([]client.Option{WithMetaHandler(mockMetaHandler)}) 543 test.DeepEqual(t, opts.MetaHandlers[1], mockMetaHandler) 544 } 545 546 func TestWithConnPool(t *testing.T) { 547 ctrl := gomock.NewController(t) 548 defer ctrl.Finish() 549 550 mockPool := mock_remote.NewMockConnPool(ctrl) 551 opts := client.NewOptions([]client.Option{WithConnPool(mockPool)}) 552 test.Assert(t, opts.RemoteOpt.ConnPool == mockPool) 553 } 554 555 func TestWithRetryContainer(t *testing.T) { 556 mockRetryContainer := &retry.Container{} 557 opts := client.NewOptions([]client.Option{WithRetryContainer(mockRetryContainer)}) 558 test.Assert(t, opts.RetryContainer == mockRetryContainer) 559 } 560 561 func TestWithGeneric(t *testing.T) { 562 opts := client.NewOptions([]client.Option{WithGeneric(generic.BinaryThriftGeneric())}) 563 test.DeepEqual(t, opts.RemoteOpt.PayloadCodec, generic.BinaryThriftGeneric().PayloadCodec()) 564 } 565 566 func TestWithCloseCallbacks(t *testing.T) { 567 opts := client.NewOptions([]client.Option{WithCloseCallbacks(func() error { return nil })}) 568 test.Assert(t, len(opts.CloseCallbacks) > 0) 569 } 570 571 func TestWithErrorHandler(t *testing.T) { 572 errHandler := func(context.Context, error) error { return nil } 573 opts := client.NewOptions([]client.Option{WithErrorHandler(errHandler)}) 574 test.Assert(t, reflect.ValueOf(opts.ErrHandle).Pointer() == reflect.ValueOf(errHandler).Pointer()) 575 } 576 577 func TestWithBoundHandler(t *testing.T) { 578 ctrl := gomock.NewController(t) 579 defer ctrl.Finish() 580 581 mockInboundHandler := mock_remote.NewMockInboundHandler(ctrl) 582 opts := client.NewOptions([]client.Option{WithBoundHandler(mockInboundHandler)}) 583 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 0) 584 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 1) 585 586 opts = client.NewOptions([]client.Option{WithBoundHandler(mockInboundHandler), WithBoundHandler(mockInboundHandler)}) 587 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 0) 588 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 1) 589 590 mockInboundHandler2 := mock_remote.NewMockInboundHandler(ctrl) 591 opts = client.NewOptions([]client.Option{WithBoundHandler(mockInboundHandler), WithBoundHandler(mockInboundHandler2)}) 592 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 0) 593 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 1) 594 595 mockOutboundHandler := mock_remote.NewMockOutboundHandler(ctrl) 596 opts = client.NewOptions([]client.Option{WithBoundHandler(mockOutboundHandler)}) 597 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 1) 598 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 0) 599 600 opts = client.NewOptions( 601 []client.Option{WithBoundHandler(mockOutboundHandler), WithBoundHandler(mockOutboundHandler)}) 602 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 1) 603 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 0) 604 605 mockOutboundHandler2 := mock_remote.NewMockOutboundHandler(ctrl) 606 opts = client.NewOptions([]client.Option{ 607 WithBoundHandler(mockOutboundHandler), WithBoundHandler(mockOutboundHandler2), 608 }) 609 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 1) 610 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 0) 611 612 mockDuplexBoundHandler := mock_remote.NewMockDuplexBoundHandler(ctrl) 613 opts = client.NewOptions([]client.Option{WithBoundHandler(mockDuplexBoundHandler), WithBoundHandler(mockDuplexBoundHandler)}) 614 test.Assert(t, len(opts.RemoteOpt.Outbounds) == 1) 615 test.Assert(t, len(opts.RemoteOpt.Inbounds) == 1) 616 } 617 618 // collection of options 619 type mockSuite struct{} 620 621 var ( 622 mockEndpointBasicInfo = &rpcinfo.EndpointBasicInfo{} 623 mockDiagnosisService = &mockDiagnosis{make(map[diagnosis.ProbeName]diagnosis.ProbeFunc)} 624 mockRetryContainer = &retry.Container{} 625 ) 626 627 func (m *mockSuite) Options() []Option { 628 return []Option{ 629 WithClientBasicInfo(mockEndpointBasicInfo), 630 WithDiagnosisService(mockDiagnosisService), 631 WithRetryContainer(mockRetryContainer), 632 } 633 } 634 635 func TestWithSuite(t *testing.T) { 636 var suite *mockSuite 637 options := []client.Option{ 638 WithSuite(suite), 639 } 640 opts := client.NewOptions(options) 641 test.Assert(t, opts.Cli == mockEndpointBasicInfo) 642 test.Assert(t, reflect.DeepEqual(opts.DebugService, mockDiagnosisService)) 643 test.Assert(t, opts.RetryContainer == mockRetryContainer) 644 } 645 646 func TestWithLongConnectionOption(t *testing.T) { 647 idleCfg := connpool.IdleConfig{} 648 options := []client.Option{ 649 WithLongConnection(idleCfg), 650 } 651 opts := client.NewOptions(options) 652 test.Assert(t, opts.PoolCfg.MaxIdleTimeout == 30*time.Second) // defaultMaxIdleTimeout 653 test.Assert(t, opts.PoolCfg.MaxIdlePerAddress == 1) // default 654 test.Assert(t, opts.PoolCfg.MaxIdleGlobal == 1<<20) // default 655 } 656 657 func TestWithWarmingUpOption(t *testing.T) { 658 options := []client.Option{ 659 WithWarmingUp(mockWarmupOption), 660 } 661 opt := client.NewOptions(options) 662 test.Assert(t, opt.WarmUpOption == mockWarmupOption) 663 } 664 665 func TestWithFramedTransport(t *testing.T) { 666 options := []client.Option{ 667 WithFramedTransport(), 668 } 669 opt := client.NewOptions(options) 670 test.Assert(t, opt.Configs.TransportProtocol() == transport.Framed) 671 } 672 673 func TestWithConnMetric(t *testing.T) { 674 options := []client.Option{ 675 WithConnMetric(), 676 } 677 opt := client.NewOptions(options) 678 test.Assert(t, opt.RemoteOpt.EnableConnPoolReporter == true) 679 } 680 681 func TestWithXDSSuite(t *testing.T) { 682 // failed 683 s := xds.ClientSuite{} 684 options := []client.Option{ 685 WithXDSSuite(s), 686 } 687 opt := client.NewOptions(options) 688 test.Assert(t, opt.XDSEnabled == false) 689 test.Assert(t, opt.XDSRouterMiddleware == nil) 690 test.Assert(t, opt.Resolver == nil) 691 692 // succeed 693 s = xds.ClientSuite{ 694 RouterMiddleware: endpoint.DummyMiddleware, 695 Resolver: discovery.SynthesizedResolver{}, 696 } 697 options = []client.Option{ 698 WithXDSSuite(s), 699 } 700 opt = client.NewOptions(options) 701 test.Assert(t, opt.XDSEnabled == true) 702 test.Assert(t, opt.XDSRouterMiddleware != nil) 703 test.Assert(t, opt.Resolver != nil) 704 } 705 706 func TestWithGRPCTLSConfig(t *testing.T) { 707 cfg := &tls.Config{} 708 opts := client.NewOptions([]client.Option{WithGRPCTLSConfig(cfg)}) 709 test.Assert(t, opts.GRPCConnectOpts != nil) 710 }