github.com/gogf/gf/v2@v2.7.4/net/ghttp/ghttp_z_unit_issue_test.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package ghttp_test 8 9 import ( 10 "context" 11 "fmt" 12 "testing" 13 "time" 14 15 "github.com/gogf/gf/v2/encoding/gjson" 16 "github.com/gogf/gf/v2/encoding/gurl" 17 "github.com/gogf/gf/v2/frame/g" 18 "github.com/gogf/gf/v2/net/ghttp" 19 "github.com/gogf/gf/v2/test/gtest" 20 "github.com/gogf/gf/v2/text/gstr" 21 "github.com/gogf/gf/v2/util/gtag" 22 "github.com/gogf/gf/v2/util/guid" 23 ) 24 25 // https://github.com/gogf/gf/issues/1609 26 func Test_Issue1609(t *testing.T) { 27 s := g.Server(guid.S()) 28 group := s.Group("/api/get") 29 group.GET("/", func(r *ghttp.Request) { 30 r.Response.Write("get") 31 }) 32 s.SetDumpRouterMap(false) 33 gtest.Assert(s.Start(), nil) 34 defer s.Shutdown() 35 36 time.Sleep(100 * time.Millisecond) 37 gtest.C(t, func(t *gtest.T) { 38 c := g.Client() 39 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 40 41 t.Assert(c.GetContent(ctx, "/api/get"), "get") 42 t.Assert(c.PostContent(ctx, "/test"), "Not Found") 43 }) 44 } 45 46 func Test_Issue1611(t *testing.T) { 47 s := g.Server(guid.S()) 48 v := g.View(guid.S()) 49 content := "This is header" 50 gtest.AssertNil(v.SetPath(gtest.DataPath("issue1611"))) 51 s.SetView(v) 52 s.BindHandler("/", func(r *ghttp.Request) { 53 gtest.AssertNil(r.Response.WriteTpl("index/layout.html", g.Map{ 54 "header": content, 55 })) 56 }) 57 s.SetDumpRouterMap(false) 58 s.Start() 59 defer s.Shutdown() 60 61 time.Sleep(100 * time.Millisecond) 62 gtest.C(t, func(t *gtest.T) { 63 c := g.Client() 64 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 65 66 t.Assert(gstr.Contains(c.GetContent(ctx, "/"), content), true) 67 }) 68 } 69 70 // https://github.com/gogf/gf/issues/1626 71 func Test_Issue1626(t *testing.T) { 72 type TestReq struct { 73 Name string `v:"required"` 74 } 75 type TestRes struct { 76 Name string 77 } 78 s := g.Server(guid.S()) 79 s.Use( 80 ghttp.MiddlewareHandlerResponse, 81 func(r *ghttp.Request) { 82 r.Middleware.Next() 83 if err := r.GetError(); err != nil { 84 r.Response.ClearBuffer() 85 r.Response.Write(err.Error()) 86 } 87 }, 88 ) 89 s.BindHandler("/test", func(ctx context.Context, req *TestReq) (res *TestRes, err error) { 90 return &TestRes{Name: req.Name}, nil 91 }) 92 s.SetDumpRouterMap(false) 93 s.Start() 94 defer s.Shutdown() 95 96 time.Sleep(100 * time.Millisecond) 97 gtest.C(t, func(t *gtest.T) { 98 c := g.Client() 99 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 100 101 t.Assert(c.GetContent(ctx, "/test"), `The Name field is required`) 102 t.Assert( 103 gstr.Contains(c.GetContent(ctx, "/test?name=john"), `{"Name":"john"}`), 104 true, 105 ) 106 }) 107 } 108 109 type Issue1653TestReq struct { 110 g.Meta `path:"/test" method:"post" summary:"执行报表查询" tags:""` 111 UUID string `json:"uuid" v:"required#菜单唯一码不可为空" dc:""` 112 Limit int `json:"limit"` 113 Filter []g.Map `json:"filter"` 114 FilterMap g.Map `json:"filter_map"` 115 } 116 117 type Issue1653TestRes struct { 118 UUID string `json:"uuid"` 119 FeedBack interface{} `json:"feed_back"` 120 } 121 122 type cIssue1653Foo struct{} 123 124 var Issue1653Foo = new(cIssue1653Foo) 125 126 func (r cIssue1653Foo) PostTest(ctx context.Context, req *Issue1653TestReq) (*Issue1653TestRes, error) { 127 return &Issue1653TestRes{UUID: req.UUID, FeedBack: req.Filter[0]["code"]}, nil 128 } 129 130 func Test_Issue1653(t *testing.T) { 131 s := g.Server(guid.S()) 132 s.Use(ghttp.MiddlewareHandlerResponse) 133 s.Group("/boot", func(grp *ghttp.RouterGroup) { 134 grp.Bind(Issue1653Foo) 135 }) 136 s.SetDumpRouterMap(false) 137 s.Start() 138 defer s.Shutdown() 139 time.Sleep(1000 * time.Millisecond) 140 // g.Client()测试: 141 gtest.C(t, func(t *gtest.T) { 142 c := g.Client() 143 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 144 dataReq := ` 145 {"uuid":"28ee701c-7daf-4cdc-9a62-6d6704e6112b","limit":0,"filter": 146 [ 147 { 148 "code":"P00001","constraint":"", 149 "created_at":"2022-03-08 04:56:15","created_by":"3ed72aba-1622-4262-a61e-83581e020763","default_value":"MonthStart()", 150 "expression":"AND A.DLVDAT_0>='%v'","force":false,"frequent":true,"name":"发货日期起", 151 "parent":"13109602-0da3-49b9-827f-2f44183ab756","read_only":false,"reference":null,"type":"date", 152 "updated_at":"2022-03-08 04:56:15","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1, 153 "uuid":"e6cd3268-1d75-42e0-83f9-f1f7b29976e8" 154 }, 155 { 156 "code":"P00002","constraint":"","created_at":"2022-03-08 04:56:15","created_by": 157 "3ed72aba-1622-4262-a61e-83581e020763","default_value":"MonthEnd()","expression":"AND A.DLVDAT_0<='%v'","force":false,"frequent":true, 158 "name":"发货日期止","parent":"13109602-0da3-49b9-827f-2f44183ab756","read_only":false,"reference":null,"type":"date","updated_at": 159 "2022-03-08 04:56:15","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"dba005b5-655e-4ac4-8b22-898aa3ad2294" 160 } 161 ], 162 "filter_map":{"P00001":1646064000000,"P00002":1648742399999}, 163 "selector_template":"" 164 } 165 ` 166 resContent := c.PostContent(ctx, "/boot/test", dataReq) 167 t.Assert(resContent, `{"code":0,"message":"","data":{"uuid":"28ee701c-7daf-4cdc-9a62-6d6704e6112b","feed_back":"P00001"}}`) 168 }) 169 } 170 171 type LbseMasterHead struct { 172 Code string `json:"code" v:"code@required|min-length:1#The code is required"` 173 Active bool `json:"active"` 174 Preset bool `json:"preset"` 175 Superior string `json:"superior"` 176 Path []string `json:"path"` 177 Sort int `json:"sort"` 178 Folder bool `json:"folder"` 179 Test string `json:"test" v:"required"` 180 } 181 182 type Template struct { 183 LbseMasterHead 184 Datasource string `json:"datasource" v:"required|length:32,32#The datasource is required"` 185 SQLText string `json:"sql_text"` 186 } 187 188 type TemplateCreateReq struct { 189 g.Meta `path:"/test" method:"post" summary:"Create template" tags:"Template"` 190 Master Template `json:"master"` 191 } 192 193 type TemplateCreateRes struct{} 194 195 type cFoo1 struct{} 196 197 var Foo1 = new(cFoo1) 198 199 func (r cFoo1) PostTest1(ctx context.Context, req *TemplateCreateReq) (res *TemplateCreateRes, err error) { 200 g.Dump(req) 201 return 202 } 203 204 // https://github.com/gogf/gf/issues/1662 205 func Test_Issue662(t *testing.T) { 206 s := g.Server(guid.S()) 207 s.Use(ghttp.MiddlewareHandlerResponse) 208 s.Group("/boot", func(grp *ghttp.RouterGroup) { 209 grp.Bind(Foo1) 210 }) 211 s.SetDumpRouterMap(false) 212 s.Start() 213 defer s.Shutdown() 214 time.Sleep(1000 * time.Millisecond) 215 216 // g.Client()测试: 217 // code字段传入空字符串时,校验没有提示 218 gtest.C(t, func(t *gtest.T) { 219 c := g.Client() 220 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 221 dataReq := ` 222 {"master":{"active":true,"code":"","created_at":"","created_by":"","created_by_text":"","datasource":"38b6f170-a584-43fc-8912-cc1e9bf1b1a9","description":"币种","folder":false,"path":"[\"XCUR\"]","preset":false,"sort":1000,"sql_text":"SELECT!!!!","superior":null,"updated_at":"","updated_by":"","updated_by_text":"","updated_tick":0,"uuid":""},"translation":[{"code":"zh_CN","text":"币种"},{"code":"en_US","text":"币种"}],"filters":null,"fields":[{"code":"F001","created_at":"2022-01-18 23:37:38","created_by":"3ed72aba-1622-4262-a61e-83581e020763","field":"value","hide":false,"min_width":120,"name":"value","parent":"296154bf-b718-4e8f-8b70-efb969b831ec","updated_at":"2022-01-18 23:37:38","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"f2140b7a-044c-41c3-b70e-852e6160b21b"},{"code":"F002","created_at":"2022-01-18 23:37:38","created_by":"3ed72aba-1622-4262-a61e-83581e020763","field":"label","hide":false,"min_width":120,"name":"label","parent":"296154bf-b718-4e8f-8b70-efb969b831ec","updated_at":"2022-01-18 23:37:38","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"2d3bba5d-308b-4dba-bcac-f093e6556eca"}],"limit":0} 223 ` 224 t.Assert(c.PostContent(ctx, "/boot/test", dataReq), `{"code":51,"message":"The code is required","data":null}`) 225 }) 226 } 227 228 type DemoReq struct { 229 g.Meta `path:"/demo" method:"post"` 230 Data *gjson.Json 231 } 232 233 type DemoRes struct { 234 Content string 235 } 236 237 type Api struct{} 238 239 func (a *Api) Demo(ctx context.Context, req *DemoReq) (res *DemoRes, err error) { 240 return &DemoRes{ 241 Content: req.Data.MustToJsonString(), 242 }, err 243 } 244 245 var api = Api{} 246 247 // https://github.com/gogf/gf/issues/2172 248 func Test_Issue2172(t *testing.T) { 249 s := g.Server(guid.S()) 250 s.Use(ghttp.MiddlewareHandlerResponse) 251 s.Group("/", func(group *ghttp.RouterGroup) { 252 group.Bind(api) 253 }) 254 s.SetDumpRouterMap(false) 255 s.Start() 256 defer s.Shutdown() 257 time.Sleep(1000 * time.Millisecond) 258 259 gtest.C(t, func(t *gtest.T) { 260 c := g.Client() 261 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 262 dataReq := `{"data":{"asd":1}}` 263 t.Assert(c.PostContent(ctx, "/demo", dataReq), `{"code":0,"message":"","data":{"Content":"{\"asd\":1}"}}`) 264 }) 265 } 266 267 // https://github.com/gogf/gf/issues/2334 268 func Test_Issue2334(t *testing.T) { 269 s := g.Server(guid.S()) 270 s.SetServerRoot(gtest.DataPath("static1")) 271 s.SetDumpRouterMap(false) 272 s.Start() 273 defer s.Shutdown() 274 time.Sleep(1000 * time.Millisecond) 275 gtest.C(t, func(t *gtest.T) { 276 c := g.Client() 277 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 278 t.Assert(c.GetContent(ctx, "/index.html"), "index") 279 280 c.SetHeader("If-Modified-Since", "Mon, 12 Dec 2040 05:53:35 GMT") 281 res, _ := c.Get(ctx, "/index.html") 282 t.Assert(res.StatusCode, 304) 283 }) 284 } 285 286 type CreateOrderReq struct { 287 g.Meta `path:"/order" tags:"订单" method:"put" summary:"创建订单"` 288 Details []*OrderDetail `p:"detail" v:"required#请输入订单详情" dc:"订单详情"` 289 } 290 291 type OrderDetail struct { 292 Name string `p:"name" v:"required#请输入物料名称" dc:"物料名称"` 293 Sn string `p:"sn" v:"required#请输入客户编号" dc:"客户编号"` 294 Images string `p:"images" dc:"图片"` 295 Desc string `p:"desc" dc:"备注"` 296 Number int `p:"number" v:"required#请输入数量" dc:"数量"` 297 Price float64 `p:"price" v:"required" dc:"单价"` 298 } 299 300 type CreateOrderRes struct{} 301 type OrderController struct{} 302 303 func (c *OrderController) CreateOrder(ctx context.Context, req *CreateOrderReq) (res *CreateOrderRes, err error) { 304 return 305 } 306 307 // https://github.com/gogf/gf/issues/2482 308 func Test_Issue2482(t *testing.T) { 309 s := g.Server(guid.S()) 310 s.Group("/api/v2", func(group *ghttp.RouterGroup) { 311 group.Middleware(ghttp.MiddlewareHandlerResponse) 312 group.Bind(OrderController{}) 313 }) 314 s.SetDumpRouterMap(false) 315 s.Start() 316 defer s.Shutdown() 317 time.Sleep(1000 * time.Millisecond) 318 319 c := g.Client() 320 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 321 gtest.C(t, func(t *gtest.T) { 322 content := ` 323 { 324 "detail": [ 325 { 326 "images": "string", 327 "desc": "string", 328 "number": 0, 329 "price": 0 330 } 331 ] 332 } 333 ` 334 t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入物料名称","data":null}`) 335 }) 336 gtest.C(t, func(t *gtest.T) { 337 content := ` 338 { 339 "detail": [ 340 { 341 "images": "string", 342 "desc": "string", 343 "number": 0, 344 "name": "string", 345 "price": 0 346 } 347 ] 348 } 349 ` 350 t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入客户编号","data":null}`) 351 }) 352 gtest.C(t, func(t *gtest.T) { 353 content := ` 354 { 355 "detail": [ 356 { 357 "images": "string", 358 "desc": "string", 359 "number": 0, 360 "name": "string", 361 "sn": "string", 362 "price": 0 363 } 364 ] 365 } 366 ` 367 t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":0,"message":"","data":null}`) 368 }) 369 } 370 371 type Issue2890Enum string 372 373 const ( 374 Issue2890EnumA Issue2890Enum = "a" 375 Issue2890EnumB Issue2890Enum = "b" 376 ) 377 378 type Issue2890Req struct { 379 g.Meta `path:"/issue2890" method:"post"` 380 Id int 381 Enums Issue2890Enum `v:"required|enums"` 382 } 383 384 type Issue2890Res struct{} 385 type Issue2890Controller struct{} 386 387 func (c *Issue2890Controller) Post(ctx context.Context, req *Issue2890Req) (res *Issue2890Res, err error) { 388 g.RequestFromCtx(ctx).Response.Write(req.Enums) 389 return 390 } 391 392 // https://github.com/gogf/gf/issues/2890 393 func Test_Issue2890(t *testing.T) { 394 gtest.C(t, func(t *gtest.T) { 395 oldEnumsJson, err := gtag.GetGlobalEnums() 396 t.AssertNil(err) 397 defer t.AssertNil(gtag.SetGlobalEnums(oldEnumsJson)) 398 399 err = gtag.SetGlobalEnums(`{"github.com/gogf/gf/v2/net/ghttp_test.Issue2890Enum": ["a","b"]}`) 400 t.AssertNil(err) 401 402 s := g.Server(guid.S()) 403 s.Group("/api/v2", func(group *ghttp.RouterGroup) { 404 group.Middleware(ghttp.MiddlewareHandlerResponse) 405 group.Bind(Issue2890Controller{}) 406 }) 407 s.SetDumpRouterMap(false) 408 s.Start() 409 defer s.Shutdown() 410 time.Sleep(1000 * time.Millisecond) 411 412 c := g.Client() 413 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 414 t.Assert( 415 c.PostContent(ctx, "/api/v2/issue2890", ``), 416 `{"code":51,"message":"The Enums field is required","data":null}`, 417 ) 418 t.Assert( 419 c.PostContent(ctx, "/api/v2/issue2890", `{"Enums":"c"}`), 420 "{\"code\":51,\"message\":\"The Enums value `c` should be in enums of: [\\\"a\\\",\\\"b\\\"]\",\"data\":null}", 421 ) 422 }) 423 } 424 425 // https://github.com/gogf/gf/issues/2963 426 func Test_Issue2963(t *testing.T) { 427 gtest.C(t, func(t *gtest.T) { 428 s := g.Server(guid.S()) 429 s.SetServerRoot(gtest.DataPath("issue2963")) 430 s.SetDumpRouterMap(false) 431 s.Start() 432 defer s.Shutdown() 433 time.Sleep(100 * time.Millisecond) 434 435 c := g.Client() 436 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 437 t.Assert(c.GetContent(ctx, "/1.txt"), `1`) 438 t.Assert(c.GetContent(ctx, "/中文G146(1)-icon.txt"), `中文G146(1)-icon`) 439 t.Assert(c.GetContent(ctx, "/"+gurl.Encode("中文G146(1)-icon.txt")), `中文G146(1)-icon`) 440 }) 441 } 442 443 type Issue3077Req struct { 444 g.Meta `path:"/echo" method:"get"` 445 A string `default:"a"` 446 B string `default:""` 447 } 448 type Issue3077Res struct { 449 g.Meta `mime:"text/html"` 450 } 451 452 type Issue3077V1 struct{} 453 454 func (c *Issue3077V1) Hello(ctx context.Context, req *Issue3077Req) (res *Issue3077Res, err error) { 455 g.RequestFromCtx(ctx).Response.Write(fmt.Sprintf("%v", req)) 456 return 457 } 458 459 // https://github.com/gogf/gf/issues/3077 460 func Test_Issue3077(t *testing.T) { 461 gtest.C(t, func(t *gtest.T) { 462 s := g.Server(guid.S()) 463 s.Group("/", func(group *ghttp.RouterGroup) { 464 group.Bind(Issue3077V1{}) 465 }) 466 s.SetDumpRouterMap(false) 467 s.Start() 468 defer s.Shutdown() 469 time.Sleep(100 * time.Millisecond) 470 471 c := g.Client() 472 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 473 t.Assert(c.GetContent(ctx, "/echo?a=1&b=2"), `&{{} 1 2}`) 474 t.Assert(c.GetContent(ctx, "/echo?"), `&{{} a }`) 475 }) 476 } 477 478 type ListMessageReq struct { 479 g.Meta `path:"/list" method:"get"` 480 StartTime int64 481 EndTime int64 482 } 483 type ListMessageRes struct { 484 g.Meta 485 Title string 486 Content string 487 } 488 type BaseRes[T any] struct { 489 g.Meta 490 Code int 491 Data T 492 Msg string 493 } 494 type cMessage struct{} 495 496 func (c *cMessage) List(ctx context.Context, req *ListMessageReq) (res *BaseRes[*ListMessageRes], err error) { 497 res = &BaseRes[*ListMessageRes]{ 498 Code: 100, 499 Data: &ListMessageRes{ 500 Title: "title", 501 Content: "hello", 502 }, 503 } 504 return res, err 505 } 506 507 // https://github.com/gogf/gf/issues/2457 508 func Test_Issue2457(t *testing.T) { 509 gtest.C(t, func(t *gtest.T) { 510 s := g.Server(guid.S()) 511 s.Use(ghttp.MiddlewareHandlerResponse) 512 s.Group("/", func(group *ghttp.RouterGroup) { 513 group.Bind( 514 new(cMessage), 515 ) 516 }) 517 s.SetDumpRouterMap(false) 518 s.Start() 519 defer s.Shutdown() 520 time.Sleep(100 * time.Millisecond) 521 522 c := g.Client() 523 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 524 t.Assert(c.GetContent(ctx, "/list"), `{"code":0,"message":"","data":{"Code":100,"Data":{"Title":"title","Content":"hello"},"Msg":""}}`) 525 }) 526 } 527 528 // https://github.com/gogf/gf/issues/3245 529 type Issue3245Req struct { 530 g.Meta `path:"/hello" method:"get"` 531 Name string `p:"nickname" json:"name"` 532 XHeaderName string `p:"Header-Name" in:"header" json:"X-Header-Name"` 533 XHeaderAge uint8 `p:"Header-Age" in:"cookie" json:"X-Header-Age"` 534 } 535 type Issue3245Res struct { 536 Reply any 537 } 538 539 type Issue3245V1 struct{} 540 541 func (Issue3245V1) Hello(ctx context.Context, req *Issue3245Req) (res *Issue3245Res, err error) { 542 res = &Issue3245Res{ 543 Reply: req, 544 } 545 return 546 } 547 548 func Test_Issue3245(t *testing.T) { 549 gtest.C(t, func(t *gtest.T) { 550 s := g.Server(guid.S()) 551 s.Use(ghttp.MiddlewareHandlerResponse) 552 s.Group("/", func(group *ghttp.RouterGroup) { 553 group.Bind( 554 new(Issue3245V1), 555 ) 556 }) 557 s.SetDumpRouterMap(false) 558 s.Start() 559 defer s.Shutdown() 560 time.Sleep(100 * time.Millisecond) 561 562 c := g.Client() 563 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 564 c.SetHeader("Header-Name", "oldme") 565 c.SetCookie("Header-Age", "25") 566 567 expect := `{"code":0,"message":"","data":{"Reply":{"name":"oldme","X-Header-Name":"oldme","X-Header-Age":25}}}` 568 t.Assert(c.GetContent(ctx, "/hello?nickname=oldme"), expect) 569 }) 570 } 571 572 type ItemSecondThird struct { 573 SecondID uint64 `json:"secondId,string"` 574 ThirdID uint64 `json:"thirdId,string"` 575 } 576 type ItemFirst struct { 577 ID uint64 `json:"id,string"` 578 ItemSecondThird 579 } 580 type ItemInput struct { 581 ItemFirst 582 } 583 type Issue3789Req struct { 584 g.Meta `path:"/hello" method:"GET"` 585 ItemInput 586 } 587 type Issue3789Res struct { 588 ItemInput 589 } 590 591 type Issue3789 struct{} 592 593 func (Issue3789) Say(ctx context.Context, req *Issue3789Req) (res *Issue3789Res, err error) { 594 res = &Issue3789Res{ 595 ItemInput: req.ItemInput, 596 } 597 return 598 } 599 600 // https://github.com/gogf/gf/issues/3789 601 func Test_Issue3789(t *testing.T) { 602 gtest.C(t, func(t *gtest.T) { 603 s := g.Server() 604 s.Use(ghttp.MiddlewareHandlerResponse) 605 s.Group("/", func(group *ghttp.RouterGroup) { 606 group.Bind( 607 new(Issue3789), 608 ) 609 }) 610 s.SetDumpRouterMap(false) 611 s.Start() 612 defer s.Shutdown() 613 time.Sleep(100 * time.Millisecond) 614 615 c := g.Client() 616 c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 617 expect := `{"code":0,"message":"","data":{"id":"0","secondId":"2","thirdId":"3"}}` 618 t.Assert(c.GetContent(ctx, "/hello?id=&secondId=2&thirdId=3"), expect) 619 }) 620 }