github.com/cloudwego/kitex@v0.9.0/pkg/generic/json_test/generic_init.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 test ... 18 package test 19 20 import ( 21 "bytes" 22 "context" 23 "encoding/base64" 24 "encoding/json" 25 "errors" 26 "fmt" 27 "math" 28 "net" 29 "strconv" 30 "strings" 31 "time" 32 33 "github.com/tidwall/gjson" 34 35 "github.com/cloudwego/kitex/client" 36 "github.com/cloudwego/kitex/client/genericclient" 37 "github.com/cloudwego/kitex/internal/mocks" 38 kt "github.com/cloudwego/kitex/internal/mocks/thrift" 39 "github.com/cloudwego/kitex/internal/test" 40 "github.com/cloudwego/kitex/pkg/generic" 41 "github.com/cloudwego/kitex/pkg/generic/descriptor" 42 "github.com/cloudwego/kitex/pkg/rpcinfo" 43 "github.com/cloudwego/kitex/pkg/serviceinfo" 44 "github.com/cloudwego/kitex/server" 45 "github.com/cloudwego/kitex/server/genericserver" 46 "github.com/cloudwego/kitex/transport" 47 ) 48 49 var reqMsg = `{"Msg":"hello","InnerBase":{"Base":{"LogID":"log_id_inner"}},"Base":{"LogID":"log_id"}}` 50 51 var reqRegression = `{"Msg":"hello","InnerBase":{"Base":{"LogID":"log_id_inner"}},"Base":{"LogID":"log_id"},"I8":"8","I16":"16","I32":"32","I64":"64","Double":"12.3"}` 52 53 var respMsgWithExtra = `{"Msg":"world","required_field":"required_field","extra_field":"extra_field"}` 54 55 var reqExtendMsg = `{"Msg":123}` 56 57 var errResp = "Test Error" 58 59 type Simple struct { 60 ByteField int8 `thrift:"ByteField,1" json:"ByteField"` 61 I64Field int64 `thrift:"I64Field,2" json:"I64Field"` 62 DoubleField float64 `thrift:"DoubleField,3" json:"DoubleField"` 63 I32Field int32 `thrift:"I32Field,4" json:"I32Field"` 64 StringField string `thrift:"StringField,5" json:"StringField"` 65 BinaryField []byte `thrift:"BinaryField,6" json:"BinaryField"` 66 } 67 68 type Nesting struct { 69 String_ string `thrift:"String,1" json:"String"` 70 ListSimple []*Simple `thrift:"ListSimple,2" json:"ListSimple"` 71 Double float64 `thrift:"Double,3" json:"Double"` 72 I32 int32 `thrift:"I32,4" json:"I32"` 73 ListI32 []int32 `thrift:"ListI32,5" json:"ListI32"` 74 I64 int64 `thrift:"I64,6" json:"I64"` 75 MapStringString map[string]string `thrift:"MapStringString,7" json:"MapStringString"` 76 SimpleStruct *Simple `thrift:"SimpleStruct,8" json:"SimpleStruct"` 77 MapI32I64 map[int32]int64 `thrift:"MapI32I64,9" json:"MapI32I64"` 78 ListString []string `thrift:"ListString,10" json:"ListString"` 79 Binary []byte `thrift:"Binary,11" json:"Binary"` 80 MapI64String map[int64]string `thrift:"MapI64String,12" json:"MapI64String"` 81 ListI64 []int64 `thrift:"ListI64,13" json:"ListI64"` 82 Byte int8 `thrift:"Byte,14" json:"Byte"` 83 MapStringSimple map[string]*Simple `thrift:"MapStringSimple,15" json:"MapStringSimple"` 84 } 85 86 func getString() string { 87 return strings.Repeat("你好,\b\n\r\t世界", 2) 88 } 89 90 func getBytes() []byte { 91 return bytes.Repeat([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 2) 92 } 93 94 func getSimpleValue() *Simple { 95 return &Simple{ 96 ByteField: math.MaxInt8, 97 I64Field: math.MaxInt64, 98 DoubleField: math.MaxFloat64, 99 I32Field: math.MaxInt32, 100 StringField: getString(), 101 BinaryField: getBytes(), 102 } 103 } 104 105 func getNestingValue() *Nesting { 106 ret := &Nesting{ 107 String_: getString(), 108 ListSimple: []*Simple{}, 109 Double: math.MaxFloat64, 110 I32: math.MaxInt32, 111 ListI32: []int32{}, 112 I64: math.MaxInt64, 113 MapStringString: map[string]string{}, 114 SimpleStruct: getSimpleValue(), 115 MapI32I64: map[int32]int64{}, 116 ListString: []string{}, 117 Binary: getBytes(), 118 MapI64String: map[int64]string{}, 119 ListI64: []int64{}, 120 Byte: math.MaxInt8, 121 MapStringSimple: map[string]*Simple{}, 122 } 123 124 for i := 0; i < 16; i++ { 125 ret.ListSimple = append(ret.ListSimple, getSimpleValue()) 126 ret.ListI32 = append(ret.ListI32, math.MinInt32) 127 ret.ListI64 = append(ret.ListI64, math.MinInt64) 128 ret.ListString = append(ret.ListString, getString()) 129 } 130 131 for i := 0; i < 16; i++ { 132 ret.MapStringString[strconv.Itoa(i)] = getString() 133 ret.MapI32I64[int32(i)] = math.MinInt64 134 ret.MapI64String[int64(i)] = getString() 135 ret.MapStringSimple[strconv.Itoa(i)] = getSimpleValue() 136 } 137 138 return ret 139 } 140 141 func newGenericClient(tp transport.Protocol, destService string, g generic.Generic, targetIPPort string) genericclient.Client { 142 var opts []client.Option 143 opts = append(opts, client.WithHostPorts(targetIPPort), client.WithTransportProtocol(tp)) 144 genericCli, _ := genericclient.NewClient(destService, g, opts...) 145 return genericCli 146 } 147 148 func newGenericServer(g generic.Generic, addr net.Addr, handler generic.Service) server.Server { 149 var opts []server.Option 150 opts = append(opts, server.WithServiceAddr(addr), server.WithExitWaitTime(time.Microsecond*10)) 151 svr := genericserver.NewServer(handler, g, opts...) 152 go func() { 153 err := svr.Run() 154 if err != nil { 155 panic(err) 156 } 157 }() 158 test.WaitServerStart(addr.String()) 159 return svr 160 } 161 162 // GenericServiceImpl ... 163 type GenericServiceImpl struct{} 164 165 // GenericCall ... 166 func (g *GenericServiceImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 167 if method == "ExtendMethod" { 168 return request, nil 169 } 170 buf := request.(string) 171 rpcinfo := rpcinfo.GetRPCInfo(ctx) 172 fmt.Printf("Method from Ctx: %s\n", rpcinfo.Invocation().MethodName()) 173 fmt.Printf("Recv: %v\n", buf) 174 fmt.Printf("Method: %s\n", method) 175 return respMsgWithExtra, nil 176 } 177 178 // GenericServiceErrorImpl ... 179 type GenericServiceErrorImpl struct{} 180 181 // GenericCall ... 182 func (g *GenericServiceErrorImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 183 return response, errors.New(errResp) 184 } 185 186 // GenericServicePingImpl ... 187 type GenericServicePingImpl struct{} 188 189 // GenericCall ... 190 func (g *GenericServicePingImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 191 msg := request.(string) 192 fmt.Printf("Recv: %v\n", msg) 193 return request, nil 194 } 195 196 // GenericServiceOnewayImpl ... 197 type GenericServiceOnewayImpl struct{} 198 199 // GenericCall ... 200 func (g *GenericServiceOnewayImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 201 msg := request.(string) 202 fmt.Printf("Recv: %v\n", msg) 203 return descriptor.Void{}, nil 204 } 205 206 // GenericServiceVoidImpl ... 207 type GenericServiceVoidImpl struct{} 208 209 // GenericCall ... 210 func (g *GenericServiceVoidImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 211 msg := request.(string) 212 fmt.Printf("Recv: %v\n", msg) 213 return descriptor.Void{}, nil 214 } 215 216 // GenericServiceVoidWithStringImpl ... 217 type GenericServiceVoidWithStringImpl struct{} 218 219 // GenericCall ... 220 func (g *GenericServiceVoidWithStringImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 221 msg := request.(string) 222 fmt.Printf("Recv: %v\n", msg) 223 return "Void", nil 224 } 225 226 // GenericServiceBinaryEchoImpl ... 227 type GenericServiceBinaryEchoImpl struct{} 228 229 const mockMyMsg = "my msg" 230 231 type BinaryEcho struct { 232 Msg string `json:"msg"` 233 GotBase64 bool `json:"got_base64"` 234 } 235 236 // GenericCall ... 237 func (g *GenericServiceBinaryEchoImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 238 req := &BinaryEcho{} 239 json.Unmarshal([]byte(request.(string)), req) 240 fmt.Printf("Recv: %s\n", req.Msg) 241 if !req.GotBase64 && req.Msg != mockMyMsg { 242 return nil, errors.New("call failed, msg type mismatch") 243 } 244 if req.GotBase64 && req.Msg != base64.StdEncoding.EncodeToString([]byte(mockMyMsg)) { 245 return nil, errors.New("call failed, incorrect base64 data") 246 } 247 return request, nil 248 } 249 250 // GenericServiceImpl ... 251 type GenericServiceBenchmarkImpl struct{} 252 253 // GenericCall ... 254 func (g *GenericServiceBenchmarkImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 255 return request, nil 256 } 257 258 var ( 259 mockReq = `{"Msg":"hello","strMap":{"mk1":"mv1","mk2":"mv2"},"strList":["lv1","lv2"]} ` 260 mockResp = "this is response" 261 ) 262 263 // normal server 264 func newMockServer(handler kt.Mock, addr net.Addr, opts ...server.Option) server.Server { 265 var options []server.Option 266 opts = append(opts, server.WithServiceAddr(addr), server.WithExitWaitTime(time.Microsecond*10)) 267 options = append(options, opts...) 268 269 svr := server.NewServer(options...) 270 if err := svr.RegisterService(serviceInfo(), handler); err != nil { 271 panic(err) 272 } 273 if err := svr.RegisterService(mocks.ServiceInfo(), mocks.MyServiceHandler()); err != nil { 274 panic(err) 275 } 276 go func() { 277 err := svr.Run() 278 if err != nil { 279 panic(err) 280 } 281 }() 282 return svr 283 } 284 285 func serviceInfo() *serviceinfo.ServiceInfo { 286 destService := "Mock" 287 handlerType := (*kt.Mock)(nil) 288 methods := map[string]serviceinfo.MethodInfo{ 289 "Test": serviceinfo.NewMethodInfo(testHandler, newMockTestArgs, newMockTestResult, false), 290 "ExceptionTest": serviceinfo.NewMethodInfo(exceptionHandler, newMockExceptionTestArgs, newMockExceptionTestResult, false), 291 } 292 svcInfo := &serviceinfo.ServiceInfo{ 293 ServiceName: destService, 294 HandlerType: handlerType, 295 Methods: methods, 296 Extra: make(map[string]interface{}), 297 } 298 return svcInfo 299 } 300 301 func newMockTestArgs() interface{} { 302 return kt.NewMockTestArgs() 303 } 304 305 func newMockTestResult() interface{} { 306 return kt.NewMockTestResult() 307 } 308 309 func testHandler(ctx context.Context, handler, arg, result interface{}) error { 310 realArg := arg.(*kt.MockTestArgs) 311 realResult := result.(*kt.MockTestResult) 312 success, err := handler.(kt.Mock).Test(ctx, realArg.Req) 313 if err != nil { 314 return err 315 } 316 realResult.Success = &success 317 return nil 318 } 319 320 func newMockExceptionTestArgs() interface{} { 321 return kt.NewMockExceptionTestArgs() 322 } 323 324 func newMockExceptionTestResult() interface{} { 325 return &kt.MockExceptionTestResult{} 326 } 327 328 func exceptionHandler(ctx context.Context, handler, args, result interface{}) error { 329 a := args.(*kt.MockExceptionTestArgs) 330 r := result.(*kt.MockExceptionTestResult) 331 reply, err := handler.(kt.Mock).ExceptionTest(ctx, a.Req) 332 if err != nil { 333 switch v := err.(type) { 334 case *kt.Exception: 335 r.Err = v 336 default: 337 return err 338 } 339 } else { 340 r.Success = &reply 341 } 342 return nil 343 } 344 345 type mockImpl struct{} 346 347 // Test ... 348 func (m *mockImpl) Test(ctx context.Context, req *kt.MockReq) (r string, err error) { 349 msg := gjson.Get(mockReq, "Msg") 350 if req.Msg != msg.String() { 351 return "", fmt.Errorf("msg is not %s", mockReq) 352 } 353 strMap := gjson.Get(mockReq, "strMap") 354 if len(strMap.Map()) == 0 { 355 return "", fmt.Errorf("strmsg is not map[interface{}]interface{}") 356 } 357 for k, v := range strMap.Map() { 358 if req.StrMap[k] != v.String() { 359 return "", fmt.Errorf("strMsg is not %s", req.StrMap) 360 } 361 } 362 363 strList := gjson.Get(mockReq, "strList") 364 array := strList.Array() 365 if len(array) == 0 { 366 return "", fmt.Errorf("strlist is not %v", strList) 367 } 368 for idx := range array { 369 if array[idx].Value() != req.StrList[idx] { 370 return "", fmt.Errorf("strlist is not %s", mockReq) 371 } 372 } 373 return mockResp, nil 374 } 375 376 // ExceptionTest ... 377 func (m *mockImpl) ExceptionTest(ctx context.Context, req *kt.MockReq) (r string, err error) { 378 msg := gjson.Get(mockReq, "Msg") 379 if req.Msg != msg.String() { 380 return "", fmt.Errorf("msg is not %s", mockReq) 381 } 382 strMap := gjson.Get(mockReq, "strMap") 383 if len(strMap.Map()) == 0 { 384 return "", fmt.Errorf("strmsg is not map[interface{}]interface{}") 385 } 386 for k, v := range strMap.Map() { 387 if req.StrMap[k] != v.String() { 388 return "", fmt.Errorf("strMsg is not %s", req.StrMap) 389 } 390 } 391 392 strList := gjson.Get(mockReq, "strList") 393 array := strList.Array() 394 if len(array) == 0 { 395 return "", fmt.Errorf("strlist is not %v", strList) 396 } 397 for idx := range array { 398 if array[idx].Value() != req.StrList[idx] { 399 return "", fmt.Errorf("strlist is not %s", mockReq) 400 } 401 } 402 return "", &kt.Exception{Code: 400, Msg: "this is an exception"} 403 } 404 405 // GenericRegressionImpl ... 406 type GenericRegressionImpl struct{} 407 408 // GenericCall ... 409 func (g *GenericRegressionImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 410 buf := request.(string) 411 rpcinfo := rpcinfo.GetRPCInfo(ctx) 412 fmt.Printf("Method from Ctx: %s\n", rpcinfo.Invocation().MethodName()) 413 fmt.Printf("Recv: %v\n", buf) 414 fmt.Printf("Method: %s\n", method) 415 respMsg := `{"Msg":"world","required_field":"required_field","num":64,"I8":"8","I16":"16","I32":"32","I64":"64","Double":"12.3"}` 416 return respMsg, nil 417 }