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  }