github.com/cloudwego/kitex@v0.9.0/pkg/generic/httpthrift_codec_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 generic
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"io/ioutil"
    23  	"net/http"
    24  	"testing"
    25  
    26  	"github.com/bytedance/sonic"
    27  	"github.com/cloudwego/dynamicgo/conv"
    28  
    29  	"github.com/cloudwego/kitex/internal/mocks"
    30  	"github.com/cloudwego/kitex/internal/test"
    31  	"github.com/cloudwego/kitex/pkg/generic/descriptor"
    32  	"github.com/cloudwego/kitex/pkg/remote"
    33  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    34  	"github.com/cloudwego/kitex/transport"
    35  )
    36  
    37  var customJson = sonic.Config{
    38  	EscapeHTML: true,
    39  	UseNumber:  true,
    40  }.Froze()
    41  
    42  func TestFromHTTPRequest(t *testing.T) {
    43  	jsonBody := `{"a": 1111111111111, "b": "hello"}`
    44  	req, err := http.NewRequest(http.MethodPost, "http://example.com", bytes.NewBufferString(jsonBody))
    45  	test.Assert(t, err == nil)
    46  	customReq, err := FromHTTPRequest(req)
    47  	test.Assert(t, err == nil)
    48  	test.DeepEqual(t, string(customReq.RawBody), jsonBody)
    49  }
    50  
    51  func TestHttpThriftCodec(t *testing.T) {
    52  	// without dynamicgo
    53  	p, err := NewThriftFileProvider("./http_test/idl/binary_echo.thrift")
    54  	test.Assert(t, err == nil)
    55  	gOpts := &Options{dynamicgoConvOpts: DefaultHTTPDynamicGoConvOpts}
    56  	htc, err := newHTTPThriftCodec(p, thriftCodec, gOpts)
    57  	test.Assert(t, err == nil)
    58  	test.Assert(t, !htc.dynamicgoEnabled)
    59  	test.Assert(t, !htc.useRawBodyForHTTPResp)
    60  	test.DeepEqual(t, htc.convOpts, conv.Options{})
    61  	test.DeepEqual(t, htc.convOptsWithThriftBase, conv.Options{})
    62  	defer htc.Close()
    63  	test.Assert(t, htc.Name() == "HttpThrift")
    64  
    65  	req := &HTTPRequest{Request: getStdHttpRequest()}
    66  	// wrong
    67  	method, err := htc.getMethod("test")
    68  	test.Assert(t, err.Error() == "req is invalid, need descriptor.HTTPRequest" && method == nil)
    69  	// right
    70  	method, err = htc.getMethod(req)
    71  	test.Assert(t, err == nil && method.Name == "BinaryEcho")
    72  
    73  	ctx := context.Background()
    74  	sendMsg := initHttpSendMsg()
    75  
    76  	// Marshal side
    77  	out := remote.NewWriterBuffer(256)
    78  	err = htc.Marshal(ctx, sendMsg, out)
    79  	test.Assert(t, err == nil)
    80  
    81  	// Unmarshal side
    82  	recvMsg := initHttpRecvMsg()
    83  	buf, err := out.Bytes()
    84  	test.Assert(t, err == nil)
    85  	recvMsg.SetPayloadLen(len(buf))
    86  	in := remote.NewReaderBuffer(buf)
    87  	err = htc.Unmarshal(ctx, recvMsg, in)
    88  	test.Assert(t, err == nil)
    89  }
    90  
    91  func TestHttpThriftCodecWithDynamicGo(t *testing.T) {
    92  	// with dynamicgo
    93  	p, err := NewThriftFileProviderWithDynamicGo("./http_test/idl/binary_echo.thrift")
    94  	test.Assert(t, err == nil)
    95  	gOpts := &Options{dynamicgoConvOpts: DefaultHTTPDynamicGoConvOpts, useRawBodyForHTTPResp: true}
    96  	htc, err := newHTTPThriftCodec(p, thriftCodec, gOpts)
    97  	test.Assert(t, err == nil)
    98  	test.Assert(t, htc.dynamicgoEnabled)
    99  	test.Assert(t, htc.useRawBodyForHTTPResp)
   100  	test.DeepEqual(t, htc.convOpts, DefaultHTTPDynamicGoConvOpts)
   101  	convOptsWithThriftBase := DefaultHTTPDynamicGoConvOpts
   102  	convOptsWithThriftBase.EnableThriftBase = true
   103  	test.DeepEqual(t, htc.convOptsWithThriftBase, convOptsWithThriftBase)
   104  	defer htc.Close()
   105  	test.Assert(t, htc.Name() == "HttpThrift")
   106  
   107  	req := &HTTPRequest{Request: getStdHttpRequest()}
   108  	// wrong
   109  	method, err := htc.getMethod("test")
   110  	test.Assert(t, err.Error() == "req is invalid, need descriptor.HTTPRequest" && method == nil)
   111  	// right
   112  	method, err = htc.getMethod(req)
   113  	test.Assert(t, err == nil && method.Name == "BinaryEcho")
   114  
   115  	ctx := context.Background()
   116  	sendMsg := initHttpSendMsg()
   117  
   118  	// Marshal side
   119  	out := remote.NewWriterBuffer(256)
   120  	err = htc.Marshal(ctx, sendMsg, out)
   121  	test.Assert(t, err == nil)
   122  
   123  	// Unmarshal side
   124  	recvMsg := initHttpRecvMsg()
   125  	buf, err := out.Bytes()
   126  	test.Assert(t, err == nil)
   127  	recvMsg.SetPayloadLen(len(buf))
   128  	in := remote.NewReaderBuffer(buf)
   129  	err = htc.Unmarshal(ctx, recvMsg, in)
   130  	test.Assert(t, err == nil)
   131  }
   132  
   133  func initHttpSendMsg() remote.Message {
   134  	stdReq := getStdHttpRequest()
   135  	b, err := stdReq.GetBody()
   136  	if err != nil {
   137  		panic(err)
   138  	}
   139  	rawBody, err := ioutil.ReadAll(b)
   140  	if err != nil {
   141  		panic(err)
   142  	}
   143  	req := &Args{
   144  		Request: &descriptor.HTTPRequest{
   145  			Request: stdReq,
   146  			RawBody: rawBody,
   147  		},
   148  		Method: "BinaryEcho",
   149  	}
   150  	svcInfo := mocks.ServiceInfo()
   151  	ink := rpcinfo.NewInvocation("", "BinaryEcho")
   152  	ri := rpcinfo.NewRPCInfo(nil, nil, ink, nil, rpcinfo.NewRPCStats())
   153  	msg := remote.NewMessage(req, svcInfo, ri, remote.Call, remote.Client)
   154  	msg.SetProtocolInfo(remote.NewProtocolInfo(transport.TTHeader, svcInfo.PayloadCodec))
   155  	return msg
   156  }
   157  
   158  func initHttpRecvMsg() remote.Message {
   159  	req := &Args{
   160  		Request: "Test",
   161  		Method:  "BinaryEcho",
   162  	}
   163  	ink := rpcinfo.NewInvocation("", "BinaryEcho")
   164  	ri := rpcinfo.NewRPCInfo(nil, nil, ink, nil, rpcinfo.NewRPCStats())
   165  	msg := remote.NewMessage(req, mocks.ServiceInfo(), ri, remote.Call, remote.Server)
   166  	return msg
   167  }
   168  
   169  func getStdHttpRequest() *http.Request {
   170  	body := map[string]interface{}{
   171  		"msg":        []byte("hello"),
   172  		"got_base64": true,
   173  		"num":        "",
   174  	}
   175  	data, err := customJson.Marshal(body)
   176  	if err != nil {
   177  		panic(err)
   178  	}
   179  	stdReq, err := http.NewRequest(http.MethodGet, "/BinaryEcho", bytes.NewBuffer(data))
   180  	if err != nil {
   181  		panic(err)
   182  	}
   183  	return stdReq
   184  }