github.com/cloudwego/kitex@v0.9.0/pkg/generic/proto/json_test.go (about)

     1  /*
     2   * Copyright 2023 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 proto
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"io/ioutil"
    23  	"testing"
    24  
    25  	"github.com/cloudwego/dynamicgo/conv"
    26  	"github.com/cloudwego/dynamicgo/proto"
    27  	"github.com/cloudwego/dynamicgo/testdata/kitex_gen/pb/example2"
    28  	"github.com/stretchr/testify/require"
    29  	goprotowire "google.golang.org/protobuf/encoding/protowire"
    30  
    31  	"github.com/cloudwego/kitex/internal/test"
    32  )
    33  
    34  var (
    35  	example2IDLPath   = "../jsonpb_test/idl/example2.proto"
    36  	example2ProtoPath = "../jsonpb_test/data/example2_pb.bin"
    37  )
    38  
    39  func TestRun(t *testing.T) {
    40  	t.Run("TestWrite", TestWrite)
    41  	t.Run("TestRead", TestRead)
    42  }
    43  
    44  // Check NewWriteJSON converting JSON to protobuf wire format
    45  func TestWrite(t *testing.T) {
    46  	method := "ExampleMethod"
    47  
    48  	opts := proto.Options{}
    49  	svc, err := opts.NewDescriptorFromPath(context.Background(), example2IDLPath)
    50  	test.Assert(t, err == nil)
    51  
    52  	wm, err := NewWriteJSON(svc, method, true, &conv.Options{})
    53  	test.Assert(t, err == nil)
    54  
    55  	msg := getExampleReq()
    56  
    57  	// get expected json struct
    58  	exp := &example2.ExampleReq{}
    59  	json.Unmarshal([]byte(msg), exp)
    60  
    61  	// marshal json string into protobuf wire format using Write
    62  	out, err := wm.Write(context.Background(), msg)
    63  	test.Assert(t, err == nil)
    64  	buf, ok := out.([]byte)
    65  	test.Assert(t, ok)
    66  
    67  	// read into struct using fastread
    68  	act := &example2.ExampleReq{}
    69  	l := 0
    70  	// fmt.Print(out)
    71  	dataLen := len(buf)
    72  	// fastRead to get target struct
    73  	for l < dataLen {
    74  		id, wtyp, tagLen := goprotowire.ConsumeTag(buf)
    75  		if tagLen < 0 {
    76  			t.Fatal("test failed")
    77  		}
    78  		l += tagLen
    79  		buf = buf[tagLen:]
    80  		offset, err := act.FastRead(buf, int8(wtyp), int32(id))
    81  		require.Nil(t, err)
    82  		buf = buf[offset:]
    83  		l += offset
    84  	}
    85  	test.Assert(t, err == nil)
    86  
    87  	// compare exp and act struct
    88  	require.Equal(t, exp, act)
    89  }
    90  
    91  // Check NewReadJSON converting protobuf wire format to JSON
    92  func TestRead(t *testing.T) {
    93  	// get protobuf wire format data
    94  	in := readExampleReqProtoBufData()
    95  	method := "ExampleMethod"
    96  
    97  	opts := proto.Options{}
    98  	svc, err := opts.NewDescriptorFromPath(context.Background(), example2IDLPath)
    99  	test.Assert(t, err == nil)
   100  
   101  	rm, err := NewReadJSON(svc, false, &conv.Options{})
   102  	test.Assert(t, err == nil)
   103  
   104  	// unmarshal protobuf wire format into json string using Read
   105  	out, err := rm.Read(context.Background(), method, in)
   106  	test.Assert(t, err == nil)
   107  
   108  	// get expected json struct
   109  	exp := &example2.ExampleReq{}
   110  
   111  	l := 0
   112  	dataLen := len(in)
   113  	for l < dataLen {
   114  		id, wtyp, tagLen := goprotowire.ConsumeTag(in)
   115  		if tagLen < 0 {
   116  			t.Fatal("proto data error format")
   117  		}
   118  		l += tagLen
   119  		in = in[tagLen:]
   120  		offset, err := exp.FastRead(in, int8(wtyp), int32(id))
   121  		require.Nil(t, err)
   122  		in = in[offset:]
   123  		l += offset
   124  	}
   125  	if len(in) != 0 {
   126  		t.Fatal("proto data error format")
   127  	}
   128  	test.Assert(t, err == nil)
   129  
   130  	act := &example2.ExampleReq{}
   131  	str, ok := out.(string)
   132  	test.Assert(t, ok)
   133  	json.Unmarshal([]byte(str), &act)
   134  
   135  	// compare exp and act struct
   136  	require.Equal(t, exp, act)
   137  }
   138  
   139  // helper methods
   140  func getExampleReq() string {
   141  	return `{
   142      "Msg":"hello",
   143      "A":25,
   144      "InnerBase2":{
   145          "Bool":true,
   146          "Uint32":123,
   147          "Uint64":123,
   148          "Double":22.3,
   149          "String":"hello_inner",
   150          "ListInt32":[12,13,14,15,16,17],
   151          "MapStringString":{"m1":"aaa","m2":"bbb"},
   152          "SetInt32":[200,201,202,203,204,205],
   153          "MapInt32String":{"1":"aaa","2":"bbb","3":"ccc","4":"ddd"},
   154          "Binary":"AQIDBA==",
   155          "MapUint32String":{"1":"u32aa","2":"u32bb","3":"u32cc","4":"u32dd"},
   156          "MapUint64String":{"1":"u64aa","2":"u64bb","3":"u64cc","4":"u64dd"},
   157          "MapInt64String":{"1":"64aaa","2":"64bbb","3":"64ccc","4":"64ddd"},
   158          "MapInt64Base":{
   159              "1":{
   160                  "LogID":"logId","Caller":"caller","Addr":"addr","Client":"client","TrafficEnv":{"Env":"env"},"Extra":{"1a":"aaa","2a":"bbb","3a":"ccc","4a":"ddd"}
   161              },
   162              "2":{
   163                  "LogID":"logId2","Caller":"caller2","Addr":"addr2","Client":"client2","TrafficEnv":{"Open":true,"Env":"env2"},"Extra":{"1a":"aaa2","2a":"bbb2","3a":"ccc2","4a":"ddd2"}
   164              }
   165          },
   166          "MapStringBase":{
   167              "1":{
   168                  "LogID":"logId","Caller":"caller","Addr":"addr","Client":"client","TrafficEnv":{"Env":"env"},"Extra":{"1a":"aaa","2a":"bbb","3a":"ccc","4a":"ddd"}
   169              },
   170              "2":{
   171                  "LogID":"logId2","Caller":"caller2","Addr":"addr2","Client":"client2","TrafficEnv":{"Open":true,"Env":"env2"},"Extra":{"1a":"aaa2","2a":"bbb2","3a":"ccc2","4a":"ddd2"}
   172              }
   173          },
   174          "ListBase":[
   175              {"LogID":"logId","Caller":"caller","Addr":"addr","Client":"client","TrafficEnv":{"Env":"env"},"Extra":{"1a":"aaa","2a":"bbb","3a":"ccc","4a":"ddd"}},
   176              {"LogID":"logId2","Caller":"caller2","Addr":"addr2","Client":"client2","TrafficEnv":{"Open":true,"Env":"env2"},"Extra":{"1a":"aaa2","2a":"bbb2","3a":"ccc2","4a":"ddd2"}}
   177          ],
   178          "ListString":["111","222","333","44","51","6"],
   179          "Base":{"LogID":"logId","Caller":"caller","Addr":"addr","Client":"client","TrafficEnv":{"Env":"env"},"Extra":{"1b":"aaa","2b":"bbb","3b":"ccc","4b":"ddd"}}
   180      }
   181  }`
   182  }
   183  
   184  // read ProtoBuf's data in binary format from exampleProtoPath
   185  func readExampleReqProtoBufData() []byte {
   186  	out, err := ioutil.ReadFile(example2ProtoPath)
   187  	if err != nil {
   188  		panic(err)
   189  	}
   190  	return out
   191  }