github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/t2j/conv_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 t2j 18 19 import ( 20 "context" 21 "encoding/base64" 22 "encoding/json" 23 "io/ioutil" 24 "math" 25 "os" 26 "reflect" 27 "runtime" 28 "runtime/debug" 29 "strconv" 30 "testing" 31 "time" 32 "unsafe" 33 34 sjson "github.com/bytedance/sonic/ast" 35 "github.com/cloudwego/dynamicgo/conv" 36 "github.com/cloudwego/dynamicgo/http" 37 "github.com/cloudwego/dynamicgo/internal/util_test" 38 "github.com/cloudwego/dynamicgo/meta" 39 kbase "github.com/cloudwego/dynamicgo/testdata/kitex_gen/base" 40 "github.com/cloudwego/dynamicgo/testdata/kitex_gen/example3" 41 "github.com/cloudwego/dynamicgo/thrift" 42 "github.com/cloudwego/dynamicgo/thrift/annotation" 43 "github.com/cloudwego/dynamicgo/thrift/base" 44 "github.com/davecgh/go-spew/spew" 45 "github.com/stretchr/testify/assert" 46 "github.com/stretchr/testify/require" 47 ) 48 49 var ( 50 debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == "" 51 ) 52 53 func TestMain(m *testing.M) { 54 go func() { 55 if !debugAsyncGC { 56 return 57 } 58 println("Begin GC looping...") 59 for { 60 runtime.GC() 61 debug.FreeOSMemory() 62 } 63 }() 64 time.Sleep(time.Millisecond) 65 annotation.InitAGWAnnos() 66 m.Run() 67 } 68 69 func GetDescByName(method string, isReq bool) *thrift.TypeDescriptor { 70 opts := thrift.Options{} 71 svc, err := opts.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 72 if err != nil { 73 panic(err) 74 } 75 if isReq { 76 return svc.Functions()[method].Request().Struct().Fields()[0].Type() 77 } else { 78 return svc.Functions()[method].Response().Struct().Fields()[0].Type() 79 } 80 } 81 82 func getExamplePartialDesc() *thrift.TypeDescriptor { 83 svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 84 if err != nil { 85 panic(err) 86 } 87 return svc.Functions()["PartialMethod"].Response().Struct().Fields()[0].Type() 88 } 89 90 func getExampleInt2Float() *thrift.TypeDescriptor { 91 svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 92 if err != nil { 93 panic(err) 94 } 95 return svc.Functions()["Int2FloatMethod"].Response().Struct().Fields()[0].Type() 96 } 97 98 func getExamplePartialDesc2() *thrift.TypeDescriptor { 99 svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 100 if err != nil { 101 panic(err) 102 } 103 return svc.Functions()["PartialMethod"].Request().Struct().Fields()[0].Type() 104 } 105 106 func getExampleErrorDesc() *thrift.TypeDescriptor { 107 svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 108 if err != nil { 109 panic(err) 110 } 111 return svc.Functions()["ErrorMethod"].Response().Struct().Fields()[0].Type() 112 } 113 114 func getExampleFallbackDesc() *thrift.TypeDescriptor { 115 svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift")) 116 if err != nil { 117 panic(err) 118 } 119 return svc.Functions()["FallbackMethod"].Response().Struct().Fields()[0].Type() 120 } 121 122 func getExample3Data() []byte { 123 out, err := ioutil.ReadFile(util_test.MustGitPath("testdata/data/example3resp.bin")) 124 if err != nil { 125 panic(err) 126 } 127 return out 128 } 129 130 func getExmaple3JSON() string { 131 out, err := ioutil.ReadFile(util_test.MustGitPath("testdata/data/example3resp.json")) 132 if err != nil { 133 panic(err) 134 } 135 return string(out) 136 } 137 138 func TestConvThrift2JSON(t *testing.T) { 139 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{})) 140 // js := getExmaple3JSON() 141 cv := NewBinaryConv(conv.Options{}) 142 in := getExample3Data() 143 out, err := cv.Do(context.Background(), desc, in) 144 if err != nil { 145 t.Fatal(err) 146 } 147 var exp, act example3.ExampleResp 148 // require.Nil(t, json.Unmarshal([]byte(js), &exp)) 149 _, err = exp.FastRead(in) 150 require.Nil(t, err) 151 require.Nil(t, json.Unmarshal([]byte(out), &act)) 152 println(string(out)) 153 assert.Equal(t, exp, act) 154 // assert.Equal(t, len(js), len(out)) 155 } 156 157 // func getHTTPResponse() *http.HTTPResponse { 158 // return &http.HTTPResponse{ 159 // StatusCode: 200, 160 // Header: map[string][]string{}, 161 // Cookies: map[string]*stdh.Cookie{}, 162 // RawBody: []byte{}, 163 // } 164 // } 165 166 func chechHelper(t *testing.T, exp string, act string, opts testOptions) { 167 var expMap, actMap map[string]interface{} 168 require.Nil(t, json.Unmarshal([]byte(exp), &expMap)) 169 require.Nil(t, json.Unmarshal([]byte(act), &actMap)) 170 assert.True(t, checkAInB(t, reflect.ValueOf(actMap), reflect.ValueOf(expMap), opts)) 171 } 172 173 type testOptions struct { 174 JSConv bool 175 } 176 177 func checkAInB(t *testing.T, a reflect.Value, b reflect.Value, opts testOptions) bool { 178 if a.IsZero() { 179 return true 180 } 181 if a.Kind() == reflect.Ptr || a.Kind() == reflect.Interface { 182 a = a.Elem() 183 } 184 if b.Kind() == reflect.Ptr || b.Kind() == reflect.Interface { 185 b = b.Elem() 186 } 187 // if a.Type() != b.Type() { 188 // t.Logf("type mismatch: %v != %v", a.Type(), b.Type()) 189 // return false 190 // } 191 if a.Kind() != reflect.Map && a.Kind() != reflect.Slice { 192 if !reflect.DeepEqual(a.Interface(), b.Interface()) { 193 // a := a.Elem() 194 // b := b.Elem() 195 if opts.JSConv { 196 switch a.Kind() { 197 case reflect.String: 198 x, _ := strconv.ParseFloat(a.String(), 64) 199 if x != (b.Float()) { 200 return false 201 } 202 return true 203 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 204 x, _ := strconv.Atoi(b.String()) 205 if x != int(a.Int()) { 206 return false 207 } 208 return true 209 } 210 } 211 t.Logf("value mismatch: %#v != %#v", a.Interface(), b.Interface()) 212 return false 213 } 214 } 215 if a.Kind() == reflect.Map { 216 for _, k := range a.MapKeys() { 217 if !checkAInB(t, a.MapIndex(k), b.MapIndex(k), opts) { 218 return false 219 } 220 } 221 } 222 if a.Kind() == reflect.Slice { 223 for i := 0; i < a.Len(); i++ { 224 if !checkAInB(t, a.Index(i), b.Index(i), opts) { 225 return false 226 } 227 } 228 } 229 return true 230 } 231 232 func TestThriftResponseBase(t *testing.T) { 233 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{ 234 EnableThriftBase: true, 235 })) 236 js := getExmaple3JSON() 237 cv := NewBinaryConv(conv.Options{ 238 EnableThriftBase: true, 239 }) 240 in := getExample3Data() 241 242 ctx := context.Background() 243 out, err := cv.Do(ctx, desc, in) 244 require.NoError(t, err) 245 var exp, act = new(example3.ExampleResp), new(example3.ExampleResp) 246 require.Nil(t, json.Unmarshal([]byte(js), &exp)) 247 require.Nil(t, json.Unmarshal([]byte(out), &act)) 248 require.Equal(t, exp, act) 249 250 b := base.NewBaseResp() 251 require.NoError(t, err) 252 ctx = context.WithValue(ctx, conv.CtxKeyThriftRespBase, b) 253 out, err = cv.Do(ctx, desc, in) 254 require.NoError(t, err) 255 exp, act = new(example3.ExampleResp), new(example3.ExampleResp) 256 require.Nil(t, json.Unmarshal([]byte(js), &exp)) 257 require.Nil(t, json.Unmarshal([]byte(out), &act)) 258 require.NotEqual(t, exp, act) 259 n, err := sjson.NewSearcher(js).GetByPath("BaseResp") 260 bj, err := n.Raw() 261 require.NoError(t, err) 262 require.Nil(t, json.Unmarshal([]byte(bj), &act.BaseResp)) 263 require.Equal(t, (*base.BaseResp)(unsafe.Pointer(act.BaseResp)), b) 264 } 265 266 func TestAGWBodyDynamic(t *testing.T) { 267 cv := NewBinaryConv(conv.Options{ 268 EnableValueMapping: true, 269 }) 270 desc := getExampleErrorDesc() 271 exp := example3.NewExampleErrorResp() 272 exp.Int64 = 1 273 exp.Xjson = `{"b":1}` 274 ctx := context.Background() 275 in := make([]byte, exp.BLength()) 276 _ = exp.FastWriteNocopy(in, nil) 277 out, err := cv.Do(ctx, desc, in) 278 require.NoError(t, err) 279 expj := (`{"Int64":1,"Xjson":{"b":1}}`) 280 require.Equal(t, expj, string(out)) 281 282 cv.opts.EnableValueMapping = false 283 out, err = cv.Do(ctx, desc, in) 284 require.NoError(t, err) 285 require.Equal(t, (`{"Int64":1,"Xjson":"{\"b\":1}"}`), string(out)) 286 } 287 288 func TestException(t *testing.T) { 289 cv := NewBinaryConv(conv.Options{ 290 ConvertException: true, 291 }) 292 desc := thrift.FnWholeResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{})) 293 294 exp := example3.NewExampleServiceExampleMethodResult() 295 success := example3.NewExampleResp() 296 success.Status = 202 297 exception := example3.NewException() 298 exception.Code = 400 299 exception.Msg = "this is an exception" 300 exp.Success = success 301 exp.Err = exception 302 ctx := context.Background() 303 in := make([]byte, exp.BLength()) 304 _ = exp.FastWriteNocopy(in, nil) 305 _, err := cv.Do(ctx, desc, in) 306 require.Error(t, err) 307 require.Equal(t, err.Error(), `{"code":400,"msg":"this is an exception"}`) 308 } 309 310 func TestInt2String(t *testing.T) { 311 cv := NewBinaryConv(conv.Options{ 312 EnableValueMapping: true, 313 }) 314 desc := getExampleInt2Float() 315 exp := example3.NewExampleInt2Float() 316 exp.Int32 = 1 317 exp.Int64 = 2 318 exp.Float64 = 3.14 319 exp.String_ = "hello" 320 exp.Subfix = 0.92653 321 ctx := context.Background() 322 in := make([]byte, exp.BLength()) 323 _ = exp.FastWriteNocopy(in, nil) 324 325 out, err := cv.Do(ctx, desc, in) 326 require.NoError(t, err) 327 require.Equal(t, `{"Int32":"1","Float64":"3.14","Int64":2,"Subfix":0.92653,"中文":"hello"}`, string(out)) 328 329 cv.opts.EnableValueMapping = false 330 out, err = cv.Do(ctx, desc, in) 331 require.NoError(t, err) 332 require.Equal(t, (`{"Int32":1,"Float64":3.14,"Int64":2,"Subfix":0.92653,"中文":"hello"}`), string(out)) 333 334 cv.opts.Int642String = true 335 out, err = cv.Do(ctx, desc, in) 336 require.NoError(t, err) 337 require.Equal(t, (`{"Int32":1,"Float64":3.14,"Int64":"2","Subfix":0.92653,"中文":"hello"}`), string(out)) 338 } 339 340 func TestHttpMappingFallback(t *testing.T) { 341 cv := NewBinaryConv(conv.Options{}) 342 t.Run("not as extra", func(t *testing.T) { 343 desc := getExampleFallbackDesc() 344 exp := example3.NewExampleFallback() 345 exp.Msg = "hello" 346 exp.Heeader = "world" 347 in := make([]byte, exp.BLength()) 348 _ = exp.FastWriteNocopy(in, nil) 349 expJSON := `{}` 350 cv.SetOptions(conv.Options{ 351 EnableHttpMapping: true, 352 WriteHttpValueFallback: false, 353 OmitHttpMappingErrors: true, 354 }) 355 ctx := context.Background() 356 resp := http.NewHTTPResponse() 357 ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp) 358 out, err := cv.Do(ctx, desc, in) 359 if err != nil { 360 t.Fatal(err) 361 } 362 require.Equal(t, expJSON, string(out)) 363 assert.Equal(t, "world", resp.Header["Heeader"][0]) 364 }) 365 t.Run("as extra", func(t *testing.T) { 366 desc := getExampleFallbackDesc() 367 exp := example3.NewExampleFallback() 368 exp.Msg = "hello" 369 exp.Heeader = "world" 370 in := make([]byte, exp.BLength()) 371 _ = exp.FastWriteNocopy(in, nil) 372 expJSON := `{"Msg":"hello"}` 373 cv.SetOptions(conv.Options{ 374 EnableHttpMapping: true, 375 WriteHttpValueFallback: true, 376 OmitHttpMappingErrors: true, 377 }) 378 ctx := context.Background() 379 resp := http.NewHTTPResponse() 380 ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp) 381 out, err := cv.Do(ctx, desc, in) 382 if err != nil { 383 t.Fatal(err) 384 } 385 require.Equal(t, expJSON, string(out)) 386 assert.Equal(t, "world", resp.Header["Heeader"][0]) 387 }) 388 } 389 390 func TestWriteEmpty(t *testing.T) { 391 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{})) 392 p := thrift.NewBinaryProtocolBuffer() 393 p.WriteStructBegin("ExampleResp") 394 p.WriteFieldBegin("Status", thrift.I32, 3) 395 expStatus := int32(23) 396 p.WriteI32(expStatus) 397 p.WriteFieldEnd() 398 p.WriteStructEnd() 399 data := p.Buf 400 cv := NewBinaryConv(conv.Options{ 401 WriteDefaultField: true, 402 EnableHttpMapping: true, 403 }) 404 ctx := context.Background() 405 resp := http.NewHTTPResponse() 406 ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp) 407 out, err := cv.Do(ctx, desc, data) 408 if err != nil { 409 t.Fatal(err) 410 } 411 var exp, act example3.ExampleResp 412 _, err = exp.FastRead(data) 413 require.NoError(t, err) 414 require.Nil(t, json.Unmarshal([]byte(out), &act)) 415 assert.NotEqual(t, exp, act) 416 assert.Equal(t, int32(0), act.Status) 417 assert.Equal(t, expStatus, int32(resp.StatusCode)) 418 assert.Equal(t, &kbase.BaseResp{ 419 StatusMessage: "", 420 StatusCode: 0, 421 Extra: map[string]string{}, 422 }, act.BaseResp) 423 } 424 425 func TestUnknowFields(t *testing.T) { 426 t.Run("top", func(t *testing.T) { 427 desc := getExamplePartialDesc() 428 // js := getExmaple3JSON() 429 cv := NewBinaryConv(conv.Options{ 430 DisallowUnknownField: true, 431 }) 432 in := getExample3Data() 433 _, err := cv.Do(context.Background(), desc, in) 434 require.Error(t, err) 435 require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior()) 436 }) 437 438 t.Run("nested", func(t *testing.T) { 439 desc := getExamplePartialDesc2() 440 // js := getExmaple3JSON() 441 cv := NewBinaryConv(conv.Options{ 442 DisallowUnknownField: true, 443 }) 444 in := getExample3Data() 445 _, err := cv.Do(context.Background(), desc, in) 446 require.Error(t, err) 447 require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior()) 448 }) 449 450 t.Run("skip top", func(t *testing.T) { 451 desc := getExamplePartialDesc() 452 // js := getExmaple3JSON() 453 cv := NewBinaryConv(conv.Options{ 454 DisallowUnknownField: false, 455 }) 456 in := getExample3Data() 457 _, err := cv.Do(context.Background(), desc, in) 458 require.NoError(t, err) 459 }) 460 461 t.Run("skip nested", func(t *testing.T) { 462 desc := getExamplePartialDesc2() 463 // js := getExmaple3JSON() 464 cv := NewBinaryConv(conv.Options{ 465 DisallowUnknownField: false, 466 }) 467 in := getExample3Data() 468 _, err := cv.Do(context.Background(), desc, in) 469 require.NoError(t, err) 470 }) 471 } 472 473 func TestNobodyRequiredFields(t *testing.T) { 474 desc := GetDescByName("Base64BinaryMethod", true) 475 476 t.Run("base64 encode", func(t *testing.T) { 477 cv := NewBinaryConv(conv.Options{ 478 EnableHttpMapping: true, 479 NoBase64Binary: false, 480 }) 481 exp := example3.NewExampleBase64Binary() 482 exp.Binary = []byte("hello") 483 exp.Binary2 = []byte("world") 484 in := make([]byte, exp.BLength()) 485 _ = exp.FastWriteNocopy(in, nil) 486 resp := http.NewHTTPResponse() 487 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 488 out, err := cv.Do(ctx, desc, in) 489 require.NoError(t, err) 490 491 act := example3.NewExampleBase64Binary() 492 err = json.Unmarshal(out, act) 493 require.NoError(t, err) 494 assert.Equal(t, exp.Binary, act.Binary) 495 assert.Equal(t, base64.StdEncoding.EncodeToString(exp.Binary2), resp.Response.Header["Binary2"][0]) 496 }) 497 498 t.Run("no base64 encode", func(t *testing.T) { 499 cv := NewBinaryConv(conv.Options{ 500 EnableHttpMapping: true, 501 NoBase64Binary: true, 502 }) 503 exp := example3.NewExampleBase64Binary() 504 exp.Binary = []byte("hello") 505 exp.Binary2 = []byte("world") 506 in := make([]byte, exp.BLength()) 507 _ = exp.FastWriteNocopy(in, nil) 508 resp := http.NewHTTPResponse() 509 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 510 out, err := cv.Do(ctx, desc, in) 511 require.NoError(t, err) 512 513 act := struct { 514 Binary string `json:"Binary"` 515 }{} 516 err = json.Unmarshal(out, &act) 517 require.NoError(t, err) 518 assert.Equal(t, string(exp.Binary), act.Binary) 519 assert.Equal(t, string(exp.Binary2), resp.Response.Header["Binary2"][0]) 520 }) 521 } 522 523 func TestJSONString(t *testing.T) { 524 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "JSONStringMethod", thrift.Options{})) 525 exp := example3.NewExampleJSONString() 526 eobj := &example3.JSONObject{ 527 A: "1", 528 B: -1, 529 } 530 exp.Header = eobj 531 exp.Header2 = map[int32]string{1: "1"} 532 exp.Cookie = &example3.JSONObject{} 533 exp.Cookie2 = []int32{1, 2} 534 in := make([]byte, exp.BLength()) 535 _ = exp.FastWriteNocopy(in, nil) 536 537 cv := NewBinaryConv(conv.Options{ 538 EnableHttpMapping: true, 539 WriteHttpValueFallback: true, 540 OmitHttpMappingErrors: true, 541 }) 542 ctx := context.Background() 543 resp := http.NewHTTPResponse() 544 ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp) 545 out, err := cv.Do(ctx, desc, in) 546 require.NoError(t, err) 547 548 act := example3.NewExampleJSONString() 549 require.Equal(t, "{\"Query\":{},\"Query2\":[]}", string(out)) 550 require.NoError(t, json.Unmarshal([]byte(resp.Response.Header.Get("header")), &act.Header)) 551 require.Equal(t, exp.Header, act.Header) 552 require.NoError(t, json.Unmarshal([]byte(resp.Response.Header.Get("header2")), &act.Header2)) 553 require.Equal(t, exp.Header2, act.Header2) 554 // require.NoError(t, json.Unmarshal([]byte(resp.Cookies()[0].Value), &act.Cookie)) 555 // require.Equal(t, exp.Cookie, act.Cookie) 556 require.NoError(t, json.Unmarshal([]byte(resp.Cookies()[1].Value), &act.Cookie2)) 557 require.Equal(t, exp.Cookie2, act.Cookie2) 558 } 559 560 func TestDefaultValue(t *testing.T) { 561 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "DefaultValueMethod", thrift.Options{ 562 UseDefaultValue: true, 563 })) 564 in := []byte{byte(thrift.STOP)} 565 t.Run("default value", func(t *testing.T) { 566 cv := NewBinaryConv(conv.Options{ 567 EnableHttpMapping: true, 568 WriteDefaultField: true, 569 }) 570 resp := http.NewHTTPResponse() 571 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 572 out, err := cv.Do(ctx, desc, in) 573 require.NoError(t, err) 574 act := &example3.ExampleDefaultValue{} 575 err = json.Unmarshal(out, act) 576 require.NoError(t, err) 577 578 exp := example3.NewExampleDefaultValue() 579 exp.C = 0 580 exp.D = "" 581 assert.Equal(t, exp, act) 582 require.Equal(t, "1.2", resp.Response.Header.Get("c")) 583 require.Equal(t, "const string", resp.Response.Cookies()[0].Value) 584 }) 585 t.Run("zero value", func(t *testing.T) { 586 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "DefaultValueMethod", thrift.Options{ 587 UseDefaultValue: false, 588 })) 589 cv := NewBinaryConv(conv.Options{ 590 EnableHttpMapping: true, 591 WriteDefaultField: true, 592 }) 593 resp := http.NewHTTPResponse() 594 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 595 out, err := cv.Do(ctx, desc, in) 596 require.NoError(t, err) 597 act := &example3.ExampleDefaultValue{} 598 err = json.Unmarshal(out, act) 599 require.NoError(t, err) 600 601 exp := &example3.ExampleDefaultValue{} 602 assert.Equal(t, exp, act) 603 require.Equal(t, "0", resp.Response.Header.Get("c")) 604 require.Equal(t, "", resp.Response.Cookies()[0].Value) 605 }) 606 } 607 608 func TestOptionalDefaultValue(t *testing.T) { 609 in := []byte{byte(thrift.STOP)} 610 t.Run("write required", func(t *testing.T) { 611 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "OptionalDefaultValueMethod", thrift.Options{ 612 UseDefaultValue: true, 613 })) 614 cv := NewBinaryConv(conv.Options{ 615 EnableHttpMapping: true, 616 WriteRequireField: true, 617 }) 618 resp := http.NewHTTPResponse() 619 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 620 out, err := cv.Do(ctx, desc, in) 621 require.NoError(t, err) 622 act := &example3.ExampleOptionalDefaultValue{} 623 err = json.Unmarshal(out, act) 624 require.NoError(t, err) 625 626 exp := example3.NewExampleOptionalDefaultValue() 627 exp.A = "" 628 exp.C = 0 629 exp.D = "" 630 assert.Equal(t, exp, act) 631 require.Equal(t, "const string", resp.Response.Cookies()[0].Value) 632 }) 633 t.Run("write required + write default + write optional", func(t *testing.T) { 634 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "OptionalDefaultValueMethod", thrift.Options{ 635 SetOptionalBitmap: true, 636 UseDefaultValue: true, 637 })) 638 cv := NewBinaryConv(conv.Options{ 639 EnableHttpMapping: true, 640 WriteRequireField: true, 641 WriteDefaultField: true, 642 WriteOptionalField: true, 643 }) 644 resp := http.NewHTTPResponse() 645 ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp) 646 out, err := cv.Do(ctx, desc, in) 647 require.NoError(t, err) 648 spew.Dump(string(out)) 649 act := &example3.ExampleOptionalDefaultValue{} 650 err = json.Unmarshal(out, act) 651 require.NoError(t, err) 652 653 exp := example3.NewExampleOptionalDefaultValue() 654 exp.C = 0 655 exp.D = "" 656 exp.E = new(string) 657 assert.Equal(t, exp, act) 658 require.Equal(t, "1.2", resp.Response.Header.Get("c")) 659 require.Equal(t, "const string", resp.Response.Cookies()[0].Value) 660 require.Equal(t, ``, resp.Response.Header.Get("f")) 661 }) 662 } 663 664 func TestSimpleArgs(t *testing.T) { 665 cv := NewBinaryConv(conv.Options{}) 666 667 t.Run("string", func(t *testing.T) { 668 desc := GetDescByName("String", false) 669 p := thrift.NewBinaryProtocolBuffer() 670 p.WriteString("hello") 671 in := p.Buf 672 out, err := cv.Do(context.Background(), desc, in) 673 require.NoError(t, err) 674 require.Equal(t, `"hello"`, string(out)) 675 }) 676 677 t.Run("int", func(t *testing.T) { 678 desc := GetDescByName("I64", false) 679 p := thrift.NewBinaryProtocolBuffer() 680 p.WriteI64(math.MaxInt64) 681 in := p.Buf 682 out, err := cv.Do(context.Background(), desc, in) 683 require.NoError(t, err) 684 require.Equal(t, strconv.Itoa(math.MaxInt64), string(out)) 685 }) 686 } 687 688 func TestConvThrift2HTTP_KitexApiHeader(t *testing.T) { 689 // annotation.RegisterHttpMaping(annotation.APIHeader, annotation.HttpMapingHandler{Req:annotation.ApiHeaderRequest, Resp:annotation.ApiheaderKitexResponse, Enc:annotation.ApiHeaderKitexEncoding}) 690 691 desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "JSONStringMethod", thrift.Options{})) 692 exp := example3.NewExampleJSONString() 693 eobj := &example3.JSONObject{ 694 A: "1", 695 B: -1, 696 } 697 exp.Header = eobj 698 exp.Header2 = map[int32]string{1: "1"} 699 exp.Cookie = &example3.JSONObject{} 700 exp.Cookie2 = []int32{1, 2} 701 in := make([]byte, exp.BLength()) 702 _ = exp.FastWriteNocopy(in, nil) 703 704 cv := NewBinaryConv(conv.Options{ 705 EnableHttpMapping: true, 706 WriteHttpValueFallback: true, 707 OmitHttpMappingErrors: true, 708 UseKitexHttpEncoding: true, 709 }) 710 ctx := context.Background() 711 resp := http.NewHTTPResponse() 712 ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp) 713 out, err := cv.Do(ctx, desc, in) 714 require.NoError(t, err) 715 716 // act := example3.NewExampleJSONString() 717 require.Equal(t, "{\"Query\":{},\"Query2\":[]}", string(out)) 718 require.Equal(t, "map[a:1 b:-1]", resp.Response.Header.Get("header")) 719 require.Equal(t, "map[1:1]", resp.Response.Header.Get("header2")) 720 require.Equal(t, "map[a: b:0]", resp.Cookies()[0].Value) 721 require.Equal(t, "1,2", resp.Cookies()[1].Value) 722 723 // annotation.RegisterHttpMaping(annotation.APIHeader, annotation.HttpMapingHandler{Req:annotation.ApiHeaderRequest, Resp: annotation.ApiHeaderResponse, Enc:annotation.ApiHeaderEncoding}) 724 }