github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/testdata/baseline_j2p_test.go (about) 1 package testdata 2 3 import ( 4 "bytes" 5 "context" 6 ejson "encoding/json" 7 "math" 8 "strconv" 9 "sync" 10 "testing" 11 12 "github.com/bytedance/sonic" 13 "github.com/cloudwego/dynamicgo/conv" 14 "github.com/cloudwego/dynamicgo/conv/j2p" 15 "github.com/cloudwego/dynamicgo/testdata/kitex_gen/pb/baseline" 16 "github.com/stretchr/testify/require" 17 "google.golang.org/protobuf/encoding/protowire" 18 ) 19 20 //go:generate kitex -module=github.com/cloudwego/dynamicgo idl/baseline.proto 21 const ( 22 protoPath = "testdata/idl/baseline.proto" 23 ) 24 25 var ( 26 simplePbJSON = "" 27 nestingPbJSON = "" 28 ) 29 30 func init() { 31 // build simpleJSON data 32 sobj := getPbSimpleValue() 33 sout, err := ejson.Marshal(sobj) 34 if err != nil { 35 panic(err) 36 } 37 simplePbJSON = string(sout) 38 var out bytes.Buffer 39 ejson.Indent(&out, sout, "", "") 40 41 // build nestingJSON data 42 nobj := getPbNestingValue() 43 nout, err := ejson.Marshal(nobj) 44 if err != nil { 45 panic(err) 46 } 47 nestingPbJSON = string(nout) 48 out.Reset() 49 50 psobj := getPartialSimpleValue() 51 _, err = ejson.Marshal(psobj) 52 if err != nil { 53 panic(err) 54 } 55 56 pnobj := getPartialNestingValue() 57 _, err = ejson.Marshal(pnobj) 58 if err != nil { 59 panic(err) 60 } 61 } 62 63 func getPbSimpleValue() *baseline.Simple { 64 return &baseline.Simple{ 65 ByteField: []byte{math.MaxInt8}, 66 I64Field: math.MaxInt64, 67 DoubleField: math.MaxFloat64, 68 I32Field: math.MaxInt32, 69 StringField: getString(), 70 BinaryField: getBytes(), 71 } 72 } 73 74 func getPbPartialSimpleValue() *baseline.PartialSimple { 75 return &baseline.PartialSimple{ 76 ByteField: []byte{math.MaxInt8}, 77 DoubleField: math.MaxFloat64, 78 BinaryField: getBytes(), 79 } 80 } 81 82 func getPbNestingValue() *baseline.Nesting { 83 var ret = &baseline.Nesting{ 84 String_: getString(), 85 ListSimple: []*baseline.Simple{}, 86 Double: math.MaxFloat64, 87 I32: math.MaxInt32, 88 ListI32: []int32{}, 89 I64: math.MaxInt64, 90 MapStringString: map[string]string{}, 91 SimpleStruct: getPbSimpleValue(), 92 MapI32I64: map[int32]int64{}, 93 ListString: []string{}, 94 Binary: getBytes(), 95 MapI64String: map[int64]string{}, 96 ListI64: []int64{}, 97 Byte: []byte{math.MaxInt8}, 98 MapStringSimple: map[string]*baseline.Simple{}, 99 } 100 for i := 0; i < listCount; i++ { 101 ret.ListSimple = append(ret.ListSimple, getPbSimpleValue()) 102 ret.ListI32 = append(ret.ListI32, math.MinInt32) 103 ret.ListI64 = append(ret.ListI64, math.MinInt64) 104 ret.ListString = append(ret.ListString, getString()) 105 } 106 107 for i := 0; i < mapCount; i++ { 108 ret.MapStringString[strconv.Itoa(i)] = getString() 109 ret.MapI32I64[int32(i)] = math.MinInt64 110 ret.MapI64String[int64(i)] = getString() 111 ret.MapStringSimple[strconv.Itoa(i)] = getPbSimpleValue() 112 } 113 114 return ret 115 } 116 117 func getPbPartialNestingValue() *baseline.PartialNesting { 118 var ret = &baseline.PartialNesting{ 119 ListSimple: []*baseline.PartialSimple{}, 120 SimpleStruct: getPbPartialSimpleValue(), 121 MapStringSimple: map[string]*baseline.PartialSimple{}, 122 } 123 for i := 0; i < listCount; i++ { 124 ret.ListSimple = append(ret.ListSimple, getPbPartialSimpleValue()) 125 } 126 127 for i := 0; i < mapCount; i++ { 128 ret.MapStringSimple[strconv.Itoa(i)] = getPbPartialSimpleValue() 129 } 130 131 return ret 132 } 133 134 func TestJSON2Protobuf_Simple(t *testing.T) { 135 _, err := ejson.Marshal(baseline.Simple{}) 136 if err != nil { 137 t.Fatal(err) 138 } 139 simple := getPbSimpleDesc() 140 // unmarshal json to get pb obj 141 stru2 := baseline.Simple{} 142 if err := sonic.UnmarshalString(simplePbJSON, &stru2); err != nil { 143 t.Fatal(err) 144 } 145 // convert json to pb bytes 146 // nj := convertI642StringSimple(simplePbJSON) // may have error here 147 cv := j2p.NewBinaryConv(conv.Options{ 148 WriteDefaultField: true, 149 EnableHttpMapping: false, 150 }) 151 ctx := context.Background() 152 153 out, err := cv.Do(ctx, simple, []byte(simplePbJSON)) 154 require.Nil(t, err) 155 156 // kitex read pb bytes to pb obj 157 stru := baseline.Simple{} 158 l := 0 159 dataLen := len(out) 160 for l < dataLen { 161 id, wtyp, tagLen := protowire.ConsumeTag(out) 162 if tagLen < 0 { 163 t.Fatal("proto data error format") 164 } 165 l += tagLen 166 out = out[tagLen:] 167 offset, err := stru.FastRead(out, int8(wtyp), int32(id)) 168 require.Nil(t, err) 169 out = out[offset:] 170 l += offset 171 } 172 if len(out) != 0 { 173 t.Fatal("proto data error format") 174 } 175 require.Equal(t, stru2, stru) 176 } 177 178 func TestJSON2Protobuf_Simple_Parallel(t *testing.T) { 179 _, err := ejson.Marshal(baseline.Simple{}) 180 if err != nil { 181 t.Fatal(err) 182 } 183 simple := getPbSimpleDesc() 184 // unmarshal json to get pb obj 185 stru2 := baseline.Simple{} 186 if err := sonic.UnmarshalString(simplePbJSON, &stru2); err != nil { 187 t.Fatal(err) 188 } 189 // convert json to pb bytes 190 // nj := convertI642StringSimple(simplePbJSON) // may have error here 191 cv := j2p.NewBinaryConv(conv.Options{ 192 WriteDefaultField: true, 193 EnableHttpMapping: false, 194 }) 195 wg := sync.WaitGroup{} 196 for i := 0; i < Concurrency; i++ { 197 wg.Add(1) 198 go func(i int) { 199 defer func() { 200 if r := recover(); r != nil { 201 t.Fatalf("panic: %d\n%s", i, simplePbJSON) 202 } 203 }() 204 defer wg.Done() 205 ctx := context.Background() 206 207 out, err := cv.Do(ctx, simple, []byte(simplePbJSON)) 208 require.Nil(t, err) 209 210 stru := baseline.Simple{} 211 l := 0 212 dataLen := len(out) 213 for l < dataLen { 214 id, wtyp, tagLen := protowire.ConsumeTag(out) 215 if tagLen < 0 { 216 t.Fatal("proto data error format") 217 } 218 l += tagLen 219 out = out[tagLen:] 220 offset, err := stru.FastRead(out, int8(wtyp), int32(id)) 221 require.Nil(t, err) 222 out = out[offset:] 223 l += offset 224 } 225 if len(out) != 0 { 226 t.Fatal("proto data error format") 227 } 228 require.Equal(t, stru2, stru) 229 }(i) 230 } 231 wg.Wait() 232 } 233 234 func TestJSON2Protobuf_Nesting(t *testing.T) { 235 _, err := ejson.Marshal(baseline.Nesting{}) 236 if err != nil { 237 t.Fatal(err) 238 } 239 nesting := getPbNestingDesc() 240 // unmarshal json to get pb obj 241 stru2 := baseline.Nesting{} 242 if err := sonic.UnmarshalString(nestingPbJSON, &stru2); err != nil { 243 t.Fatal(err) 244 } 245 // convert json to pb bytes 246 // nj := convertI642StringSimple(simplePbJSON) // may have error here 247 cv := j2p.NewBinaryConv(conv.Options{ 248 WriteDefaultField: true, 249 EnableHttpMapping: false, 250 }) 251 ctx := context.Background() 252 out, err := cv.Do(ctx, nesting, []byte(nestingPbJSON)) 253 require.Nil(t, err) 254 255 // kitex read pb bytes to pb obj 256 stru := baseline.Nesting{} 257 l := 0 258 dataLen := len(out) 259 for l < dataLen { 260 id, wtyp, tagLen := protowire.ConsumeTag(out) 261 if tagLen < 0 { 262 t.Fatal("proto data error format") 263 } 264 l += tagLen 265 out = out[tagLen:] 266 offset, err := stru.FastRead(out, int8(wtyp), int32(id)) 267 require.Nil(t, err) 268 out = out[offset:] 269 l += offset 270 } 271 if len(out) != 0 { 272 t.Fatal("proto data error format") 273 } 274 require.Equal(t, stru2, stru) 275 } 276 277 func TestJSON2Protobuf_Nesting_Parallel(t *testing.T) { 278 _, err := ejson.Marshal(baseline.Nesting{}) 279 if err != nil { 280 t.Fatal(err) 281 } 282 nesting := getPbNestingDesc() 283 // unmarshal json to get pb obj 284 stru2 := baseline.Nesting{} 285 if err := sonic.UnmarshalString(nestingPbJSON, &stru2); err != nil { 286 t.Fatal(err) 287 } 288 // convert json to pb bytes 289 // nj := convertI642StringSimple(simplePbJSON) // may have error here 290 cv := j2p.NewBinaryConv(conv.Options{ 291 WriteDefaultField: true, 292 EnableHttpMapping: false, 293 }) 294 295 wg := sync.WaitGroup{} 296 for i := 0; i < Concurrency; i++ { 297 wg.Add(1) 298 go func(i int) { 299 defer func() { 300 if r := recover(); r != nil { 301 t.Fatalf("panic: %d\n%s", i, nestingPbJSON) 302 } 303 }() 304 defer wg.Done() 305 ctx := context.Background() 306 307 out, err := cv.Do(ctx, nesting, []byte(nestingPbJSON)) 308 require.Nil(t, err) 309 310 stru := baseline.Nesting{} 311 l := 0 312 dataLen := len(out) 313 for l < dataLen { 314 id, wtyp, tagLen := protowire.ConsumeTag(out) 315 if tagLen < 0 { 316 t.Fatal("proto data error format") 317 } 318 l += tagLen 319 out = out[tagLen:] 320 offset, err := stru.FastRead(out, int8(wtyp), int32(id)) 321 require.Nil(t, err) 322 out = out[offset:] 323 l += offset 324 } 325 if len(out) != 0 { 326 t.Fatal("proto data error format") 327 } 328 require.Equal(t, stru2, stru) 329 }(i) 330 } 331 wg.Wait() 332 } 333 334 func BenchmarkJSON2Protobuf_DynamicGo_Raw(b *testing.B) { 335 b.Run("small", func(b *testing.B) { 336 simple := getPbSimpleDesc() 337 cv := j2p.NewBinaryConv(conv.Options{ 338 WriteDefaultField: false, 339 EnableValueMapping: true, 340 }) 341 // nj := []byte(convertI642StringSimple(simpleJSON)) 342 ctx := context.Background() 343 out, err := cv.Do(ctx, simple, []byte(simplePbJSON)) 344 require.Nil(b, err) 345 346 b.SetBytes(int64(len(out))) 347 b.ResetTimer() 348 for i := 0; i < b.N; i++ { 349 _, _ = cv.Do(ctx, simple, []byte(simplePbJSON)) 350 } 351 }) 352 353 b.Run("medium", func(b *testing.B) { 354 nesting := getPbNestingDesc() 355 cv := j2p.NewBinaryConv(conv.Options{ 356 WriteDefaultField: false, 357 EnableValueMapping: true, 358 }) 359 // println(string(nestingPbJSON)) 360 // nj := []byte(convertI642StringSimple(simpleJSON)) 361 ctx := context.Background() 362 363 out, err := cv.Do(ctx, nesting, []byte(nestingPbJSON)) 364 require.Nil(b, err) 365 366 b.SetBytes(int64(len(out))) 367 b.ResetTimer() 368 for i := 0; i < b.N; i++ { 369 _, _ = cv.Do(ctx, nesting, []byte(nestingPbJSON)) 370 } 371 }) 372 } 373 374 func BenchmarkJSON2Protobuf_SonicAndKitex(b *testing.B) { 375 b.Run("small", func(b *testing.B) { 376 v := baseline.Simple{} 377 if err := sonic.UnmarshalString(simplePbJSON, &v); err != nil { 378 b.Fatal(err) 379 } 380 var buf = make([]byte, v.Size()) 381 v.FastWrite(buf) 382 383 b.SetBytes(int64(len(buf))) 384 b.ResetTimer() 385 for i := 0; i < b.N; i++ { 386 v := baseline.Simple{} 387 _ = v.Size() 388 _ = sonic.UnmarshalString(simplePbJSON, &v) 389 v.FastWrite(buf) 390 } 391 }) 392 393 b.Run("medium", func(b *testing.B) { 394 v := baseline.Nesting{} 395 if err := sonic.UnmarshalString(nestingPbJSON, &v); err != nil { 396 b.Fatal(err) 397 } 398 var buf = make([]byte, v.Size()) 399 v.FastWrite(buf) 400 401 b.SetBytes(int64(len(buf))) 402 b.ResetTimer() 403 for i := 0; i < b.N; i++ { 404 v := baseline.Nesting{} 405 _ = v.Size() 406 _ = sonic.UnmarshalString(nestingPbJSON, &v) 407 v.FastWrite(buf) 408 } 409 }) 410 } 411 412 // func BenchmarkJSON2Protobuf_ProtoBufGo(b *testing.B) { 413 // b.Run("small", func(b *testing.B) { 414 // v := baseline.Simple{} 415 // if err := protojson.Unmarshal([]byte(simplePbJSON), v.ProtoReflect().Interface()); err != nil { 416 // b.Fatal(err) 417 // } 418 // b.ResetTimer() 419 // for i := 0; i < b.N; i++ { 420 // _ = protojson.Unmarshal([]byte(simplePbJSON), v.ProtoReflect().Interface()) 421 // } 422 // }) 423 424 // b.Run("medium", func(b *testing.B) { 425 // v := baseline.Nesting{} 426 // if err := protojson.Unmarshal([]byte(nestingPbJSON), v.ProtoReflect().Interface()); err != nil { 427 // b.Fatal(err) 428 // } 429 // b.ResetTimer() 430 // for i := 0; i < b.N; i++ { 431 // _ = protojson.Unmarshal([]byte(nestingPbJSON), v.ProtoReflect().Interface()) 432 // } 433 // }) 434 // }