From 9c9cfba09f1dad02a407c4affa86d14ba050a267 Mon Sep 17 00:00:00 2001 From: Guangming Luo Date: Mon, 29 Jul 2024 17:34:15 +0800 Subject: [PATCH 01/11] chore: update go mod and CI to support go1.22 (#1158) Co-authored-by: yinxuran.lucky --- .github/workflows/pr-check.yml | 4 ++-- .github/workflows/tests.yml | 10 ++++----- _typos.toml | 2 +- go.mod | 31 ++++++++++++++++++++++------ go.sum | 37 +++++++++++++++++++++------------- pkg/app/client/option_test.go | 2 -- pkg/app/server/hertz_test.go | 10 ++++----- 7 files changed, 61 insertions(+), 35 deletions(-) diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index dba5baaf3..16f214ef0 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v3 - name: Check License Header - uses: apache/skywalking-eyes/header@501a28d2fb4a9b962661987e50cf0219631b32ff + uses: apache/skywalking-eyes/header@v0.4.0 - name: typos-action uses: crate-ci/typos@master @@ -22,7 +22,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.21 - uses: reviewdog/action-staticcheck@v1 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e16ee73af..1098aa013 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,7 +6,7 @@ jobs: compat-test: strategy: matrix: - version: ["1.16", "1.17"] + version: ["1.17", "1.18"] runs-on: [self-hosted, X64] steps: - uses: actions/checkout@v3 @@ -23,7 +23,7 @@ jobs: lint-and-ut: strategy: matrix: - version: ["1.18", "1.19", "1.20"] + version: ["1.19", "1.20", "1.21", "1.22"] runs-on: [self-hosted, X64] steps: - uses: actions/checkout@v3 @@ -48,7 +48,7 @@ jobs: ut-windows: strategy: matrix: - version: ["1.18", "1.19", "1.20"] + version: ["1.19", "1.20", "1.21", "1.22"] runs-on: windows-latest steps: - uses: actions/checkout@v3 @@ -64,7 +64,7 @@ jobs: hz-test-unix: strategy: matrix: - version: [ '1.20' ] + version: [ '1.21' ] runs-on: [ self-hosted, X64 ] steps: - uses: actions/checkout@v3 @@ -93,7 +93,7 @@ jobs: hz-test-windows: strategy: matrix: - version: [ '1.20'] + version: [ '1.21'] runs-on: windows-latest steps: - uses: actions/checkout@v3 diff --git a/_typos.toml b/_typos.toml index bb673bac6..50baf653c 100644 --- a/_typos.toml +++ b/_typos.toml @@ -1,7 +1,7 @@ # Typo check: https://github.com/crate-ci/typos [files] -extend-exclude = ["go.sum"] +extend-exclude = ["go.mod", "go.sum"] [default.extend-identifiers] # *sigh* this just isn't worth the cost of fixing diff --git a/go.mod b/go.mod index 36f7e5132..6bf4bf9a2 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,35 @@ module github.com/cloudwego/hertz -go 1.16 +go 1.17 require ( github.com/bytedance/go-tagexpr/v2 v2.9.2 - github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 - github.com/bytedance/mockey v1.2.1 - github.com/bytedance/sonic v1.8.1 - github.com/cloudwego/netpoll v0.6.0 + github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3 + github.com/bytedance/mockey v1.2.10 + github.com/bytedance/sonic v1.11.9 + github.com/cloudwego/netpoll v0.6.2 github.com/fsnotify/fsnotify v1.5.4 github.com/tidwall/gjson v1.14.4 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 google.golang.org/protobuf v1.27.1 ) + +require ( + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect +) diff --git a/go.sum b/go.sum index 4b60e994d..40eecc656 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,19 @@ github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= -github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= -github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4= -github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/cloudwego/netpoll v0.6.0 h1:JRMkrA1o8k/4quxzg6Q1XM+zIhwZsyoWlq6ef+ht31U= -github.com/cloudwego/netpoll v0.6.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3 h1:ZKUHguI38SRQJkq7hhmwn8lAv3xM6B5qkj1IneS15YY= +github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= +github.com/bytedance/mockey v1.2.10 h1:4JlMpkm7HMXmTUtItid+iCu2tm61wvq+ca1X2u7ymzE= +github.com/bytedance/mockey v1.2.10/go.mod h1:bNrUnI1u7+pAc0TYDgPATM+wF2yzHxmNH+iDXg4AOCU= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cloudwego/netpoll v0.6.2 h1:+KdILv5ATJU+222wNNXpHapYaBeRvvL8qhJyhcxRxrQ= +github.com/cloudwego/netpoll v0.6.2/go.mod h1:kaqvfZ70qd4T2WtIIpCOi5Cxyob8viEpzLhCrTrz3HM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -33,6 +35,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -65,13 +68,18 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VA golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -83,4 +91,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pkg/app/client/option_test.go b/pkg/app/client/option_test.go index f744210c9..3b5af7183 100644 --- a/pkg/app/client/option_test.go +++ b/pkg/app/client/option_test.go @@ -17,7 +17,6 @@ package client import ( - "fmt" "testing" "time" @@ -60,5 +59,4 @@ func TestClientOptions(t *testing.T) { assert.DeepEqual(t, 5*time.Second, opt.RetryConfig.MaxDelay) assert.DeepEqual(t, 1*time.Second, opt.RetryConfig.MaxJitter) assert.DeepEqual(t, 1*time.Second, opt.ObservationInterval) - assert.DeepEqual(t, fmt.Sprint(retry.CombineDelay(retry.FixedDelayPolicy, retry.BackOffDelayPolicy, retry.RandomDelayPolicy)), fmt.Sprint(opt.RetryConfig.DelayPolicy)) } diff --git a/pkg/app/server/hertz_test.go b/pkg/app/server/hertz_test.go index 3352d34c8..d20db2f96 100644 --- a/pkg/app/server/hertz_test.go +++ b/pkg/app/server/hertz_test.go @@ -218,28 +218,28 @@ func Test_getServerName(t *testing.T) { } func TestServer_Run(t *testing.T) { - hertz := New(WithHostPorts("127.0.0.1:8888")) + hertz := New(WithHostPorts("127.0.0.1:8899")) hertz.GET("/test", func(c context.Context, ctx *app.RequestContext) { path := ctx.Request.URI().PathOriginal() ctx.SetBodyString(string(path)) }) hertz.POST("/redirect", func(c context.Context, ctx *app.RequestContext) { - ctx.Redirect(consts.StatusMovedPermanently, []byte("http://127.0.0.1:8888/test")) + ctx.Redirect(consts.StatusMovedPermanently, []byte("http://127.0.0.1:8899/test")) }) go hertz.Run() time.Sleep(100 * time.Microsecond) - resp, err := http.Get("http://127.0.0.1:8888/test") + resp, err := http.Get("http://127.0.0.1:8899/test") assert.Nil(t, err) assert.DeepEqual(t, consts.StatusOK, resp.StatusCode) b := make([]byte, 5) resp.Body.Read(b) assert.DeepEqual(t, "/test", string(b)) - resp, err = http.Get("http://127.0.0.1:8888/foo") + resp, err = http.Get("http://127.0.0.1:8899/foo") assert.Nil(t, err) assert.DeepEqual(t, consts.StatusNotFound, resp.StatusCode) - resp, err = http.Post("http://127.0.0.1:8888/redirect", "", nil) + resp, err = http.Post("http://127.0.0.1:8899/redirect", "", nil) assert.Nil(t, err) assert.DeepEqual(t, consts.StatusOK, resp.StatusCode) b = make([]byte, 5) From 9536ec490466492b90562ab5edcd66b9f490b457 Mon Sep 17 00:00:00 2001 From: haopeng <63844184+lhpqaq@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:07:42 +0800 Subject: [PATCH 02/11] fix(test): modify the comparison to function signatures in TestClientOptions (#1163) --- pkg/app/client/option_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/app/client/option_test.go b/pkg/app/client/option_test.go index 3b5af7183..08e6c851d 100644 --- a/pkg/app/client/option_test.go +++ b/pkg/app/client/option_test.go @@ -40,7 +40,7 @@ func TestClientOptions(t *testing.T) { retry.WithInitDelay(100*time.Millisecond), retry.WithMaxDelay(5*time.Second), retry.WithMaxJitter(1*time.Second), - retry.WithDelayPolicy(retry.CombineDelay(retry.FixedDelayPolicy, retry.BackOffDelayPolicy, retry.RandomDelayPolicy)), + retry.WithDelayPolicy(retry.CombineDelay(retry.DefaultDelayPolicy, retry.FixedDelayPolicy, retry.BackOffDelayPolicy)), ), WithWriteTimeout(time.Second), WithConnStateObserve(nil, time.Second), @@ -59,4 +59,7 @@ func TestClientOptions(t *testing.T) { assert.DeepEqual(t, 5*time.Second, opt.RetryConfig.MaxDelay) assert.DeepEqual(t, 1*time.Second, opt.RetryConfig.MaxJitter) assert.DeepEqual(t, 1*time.Second, opt.ObservationInterval) + for i := 0; i < 100; i++ { + assert.DeepEqual(t, opt.RetryConfig.DelayPolicy(uint(i), nil, opt.RetryConfig), retry.CombineDelay(retry.DefaultDelayPolicy, retry.FixedDelayPolicy, retry.BackOffDelayPolicy)(uint(i), nil, opt.RetryConfig)) + } } From dbd3166c0697e3a7720d278618ecda5a461587c2 Mon Sep 17 00:00:00 2001 From: GuangyuFan <97507466+FGYFFFF@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:20:54 +0800 Subject: [PATCH 03/11] feat: add flag to force update hertz_client.go (#1165) --- cmd/hz/app/app.go | 2 ++ cmd/hz/config/argument.go | 1 + cmd/hz/generator/client.go | 2 +- cmd/hz/generator/package.go | 1 + cmd/hz/protobuf/plugin.go | 1 + cmd/hz/thrift/plugin.go | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/hz/app/app.go b/cmd/hz/app/app.go index 739db8823..2885a7e56 100644 --- a/cmd/hz/app/app.go +++ b/cmd/hz/app/app.go @@ -178,6 +178,7 @@ func Init() *cli.App { protoPluginsFlag := cli.StringSliceFlag{Name: "protoc-plugins", Usage: "Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir})"} noRecurseFlag := cli.BoolFlag{Name: "no_recurse", Usage: "Generate master model only.", Destination: &globalArgs.NoRecurse} forceNewFlag := cli.BoolFlag{Name: "force", Aliases: []string{"f"}, Usage: "Force new a project, which will overwrite the generated files", Destination: &globalArgs.ForceNew} + forceUpdateClientFlag := cli.BoolFlag{Name: "force_client", Usage: "Force update 'hertz_client.go'", Destination: &globalArgs.ForceUpdateClient} enableExtendsFlag := cli.BoolFlag{Name: "enable_extends", Usage: "Parse 'extends' for thrift IDL", Destination: &globalArgs.EnableExtends} sortRouterFlag := cli.BoolFlag{Name: "sort_router", Usage: "Sort router register code, to avoid code difference", Destination: &globalArgs.SortRouter} @@ -316,6 +317,7 @@ func Init() *cli.App { &clientDirFlag, &useFlag, &forceClientDirFlag, + &forceUpdateClientFlag, &includesFlag, &thriftOptionsFlag, diff --git a/cmd/hz/config/argument.go b/cmd/hz/config/argument.go index 48e381297..d9dcca441 100644 --- a/cmd/hz/config/argument.go +++ b/cmd/hz/config/argument.go @@ -71,6 +71,7 @@ type Argument struct { NoRecurse bool HandlerByMethod bool ForceNew bool + ForceUpdateClient bool SnakeStyleMiddleware bool EnableExtends bool SortRouter bool diff --git a/cmd/hz/generator/client.go b/cmd/hz/generator/client.go index 7545a5023..b1b887eaf 100644 --- a/cmd/hz/generator/client.go +++ b/cmd/hz/generator/client.go @@ -71,7 +71,7 @@ func (pkgGen *HttpPackageGenerator) genClient(pkg *HttpPackage, clientDir string BaseDomain: baseDomain, Config: ClientConfig{QueryEnumAsInt: pkgGen.QueryEnumAsInt}, } - if !isExist { + if !isExist || pkgGen.ForceUpdateClient { err := pkgGen.TemplateGenerator.Generate(client, hertzClientTplName, hertzClientPath, false) if err != nil { return err diff --git a/cmd/hz/generator/package.go b/cmd/hz/generator/package.go index db4d9762b..6896229b0 100644 --- a/cmd/hz/generator/package.go +++ b/cmd/hz/generator/package.go @@ -70,6 +70,7 @@ type HttpPackageGenerator struct { HandlerByMethod bool // generate handler files with method dimension SnakeStyleMiddleware bool // use snake name style for middleware SortRouter bool + ForceUpdateClient bool // force update 'hertz_client.go' loadedBackend Backend curModel *model.Model diff --git a/cmd/hz/protobuf/plugin.go b/cmd/hz/protobuf/plugin.go index fbae89929..abb7616c4 100644 --- a/cmd/hz/protobuf/plugin.go +++ b/cmd/hz/protobuf/plugin.go @@ -628,6 +628,7 @@ func (plugin *Plugin) genHttpPackage(ast *descriptorpb.FileDescriptorProto, deps QueryEnumAsInt: args.QueryEnumAsInt, SnakeStyleMiddleware: args.SnakeStyleMiddleware, SortRouter: args.SortRouter, + ForceUpdateClient: args.ForceUpdateClient, } if args.ModelBackend != "" { diff --git a/cmd/hz/thrift/plugin.go b/cmd/hz/thrift/plugin.go index 91fab02fc..0e773df30 100644 --- a/cmd/hz/thrift/plugin.go +++ b/cmd/hz/thrift/plugin.go @@ -153,6 +153,7 @@ func (plugin *Plugin) Run() int { QueryEnumAsInt: args.QueryEnumAsInt, SnakeStyleMiddleware: args.SnakeStyleMiddleware, SortRouter: args.SortRouter, + ForceUpdateClient: args.ForceUpdateClient, } if args.ModelBackend != "" { sg.Backend = meta.Backend(args.ModelBackend) From fc3c77ee82d0e51ccc3733184a7b3380f88e65b7 Mon Sep 17 00:00:00 2001 From: Joway Date: Mon, 5 Aug 2024 17:10:31 +0800 Subject: [PATCH 04/11] build: upgrade gopkg to v0.1.0 (#1166) --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6bf4bf9a2..971818ea8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/bytedance/go-tagexpr/v2 v2.9.2 - github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3 + github.com/bytedance/gopkg v0.1.0 github.com/bytedance/mockey v1.2.10 github.com/bytedance/sonic v1.11.9 github.com/cloudwego/netpoll v0.6.2 diff --git a/go.sum b/go.sum index 40eecc656..ce80f8a37 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,8 @@ github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= -github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3 h1:ZKUHguI38SRQJkq7hhmwn8lAv3xM6B5qkj1IneS15YY= github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= +github.com/bytedance/gopkg v0.1.0 h1:aAxB7mm1qms4Wz4sp8e1AtKDOeFLtdqvGiUe7aonRJs= +github.com/bytedance/gopkg v0.1.0/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= github.com/bytedance/mockey v1.2.10 h1:4JlMpkm7HMXmTUtItid+iCu2tm61wvq+ca1X2u7ymzE= github.com/bytedance/mockey v1.2.10/go.mod h1:bNrUnI1u7+pAc0TYDgPATM+wF2yzHxmNH+iDXg4AOCU= github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= From 226f0e824d257c6e1c018363063705b92f0033c3 Mon Sep 17 00:00:00 2001 From: Xin Hao Date: Thu, 8 Aug 2024 17:49:57 +0800 Subject: [PATCH 05/11] build: Upgrade sonic to v0.12.0 to be compatible with Go 1.23 (#1167) --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 971818ea8..0fd7648ad 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bytedance/go-tagexpr/v2 v2.9.2 github.com/bytedance/gopkg v0.1.0 github.com/bytedance/mockey v1.2.10 - github.com/bytedance/sonic v1.11.9 + github.com/bytedance/sonic v1.12.0 github.com/cloudwego/netpoll v0.6.2 github.com/fsnotify/fsnotify v1.5.4 github.com/tidwall/gjson v1.14.4 @@ -16,7 +16,7 @@ require ( ) require ( - github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/golang/protobuf v1.5.0 // indirect diff --git a/go.sum b/go.sum index ce80f8a37..f20c60c76 100644 --- a/go.sum +++ b/go.sum @@ -5,10 +5,11 @@ github.com/bytedance/gopkg v0.1.0 h1:aAxB7mm1qms4Wz4sp8e1AtKDOeFLtdqvGiUe7aonRJs github.com/bytedance/gopkg v0.1.0/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= github.com/bytedance/mockey v1.2.10 h1:4JlMpkm7HMXmTUtItid+iCu2tm61wvq+ca1X2u7ymzE= github.com/bytedance/mockey v1.2.10/go.mod h1:bNrUnI1u7+pAc0TYDgPATM+wF2yzHxmNH+iDXg4AOCU= -github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= -github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= -github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic v1.12.0 h1:YGPgxF9xzaCNvd/ZKdQ28yRovhfMFZQjuk6fKBzZ3ls= +github.com/bytedance/sonic v1.12.0/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= From a64f3901f81d790f33547e884fd95109d15d20e7 Mon Sep 17 00:00:00 2001 From: Guangming Luo Date: Fri, 9 Aug 2024 10:06:08 +0800 Subject: [PATCH 06/11] chore: update CI and optimze efficiency (#1168) --- .github/workflows/pr-check.yml | 29 ++++++++++++++---- .github/workflows/tests.yml | 53 +++++++++++++-------------------- .github/workflows/vulncheck.yml | 4 +-- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index 16f214ef0..a9c318f53 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -11,18 +11,21 @@ jobs: - name: Check License Header uses: apache/skywalking-eyes/header@v0.4.0 - - name: typos-action + - name: Check Spell uses: crate-ci/typos@master staticcheck: runs-on: [ self-hosted, X64 ] steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: 1.21 + go-version: stable + # For self-hosted, the cache path is shared across projects + # and it works well without the cache of github actions + # Enable it if we're going to use Github only + cache: false - uses: reviewdog/action-staticcheck@v1 with: @@ -35,3 +38,19 @@ jobs: fail_on_error: true # Set staticcheck flags staticcheck_flags: -checks=inherit,-SA1029,-SA5008 + + lint: + runs-on: [ self-hosted, X64 ] + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: stable + cache: false # don't use cache for self-hosted runners + + - name: Golangci Lint + # https://golangci-lint.run/ + uses: golangci/golangci-lint-action@v6 + with: + version: latest \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1098aa013..7c97b982e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,39 +6,33 @@ jobs: compat-test: strategy: matrix: - version: ["1.17", "1.18"] + version: ["1.17", "1.18", "1.19"] runs-on: [self-hosted, X64] steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.version }} + cache: false # don't use cache for self-hosted runners # Just build tests without running them - name: Build Test run: go test -run=nope ./... - lint-and-ut: + unit-test: strategy: matrix: - version: ["1.19", "1.20", "1.21", "1.22"] + version: ["1.20", "1.21", "1.22"] runs-on: [self-hosted, X64] steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.version }} + cache: false # don't use cache for self-hosted runners - - name: Golangci Lint - # https://golangci-lint.run/ - uses: golangci/golangci-lint-action@v3 - with: - version: latest - skip-cache: true - name: Unit Test run: go test -race -covermode=atomic -coverprofile=coverage.txt ./... @@ -48,31 +42,28 @@ jobs: ut-windows: strategy: matrix: - version: ["1.19", "1.20", "1.21", "1.22"] + version: ["1.20", "1.21", "1.22"] runs-on: windows-latest steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.version }} + cache: false # don't use cache for self-hosted runners - name: Unit Test run: go test -race -covermode=atomic ./... hz-test-unix: - strategy: - matrix: - version: [ '1.21' ] runs-on: [ self-hosted, X64 ] steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: ${{ matrix.version }} + go-version: stable + cache: false # don't use cache for self-hosted runners - name: Setup Environment run: | @@ -91,17 +82,13 @@ jobs: hz-test-windows: - strategy: - matrix: - version: [ '1.21'] runs-on: windows-latest steps: - - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: ${{ matrix.version }} + go-version: stable - name: Get changed files id: changed-files diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index 9b88498b9..6cbeff848 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -22,9 +22,9 @@ jobs: uses: actions/checkout@v4 - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: "stable" + go-version: stable check-latest: true cache: false From c29f150532af6c57bce9aa5497acc3cfa2678535 Mon Sep 17 00:00:00 2001 From: Wenju Gao Date: Thu, 22 Aug 2024 11:47:52 +0800 Subject: [PATCH 07/11] feat(http1): add env to disable request context pool (#1173) --- pkg/app/client/client_test.go | 234 ++++++++++++++---- .../binding/internal/decoder/text_decoder.go | 2 +- pkg/app/server/hertz_test.go | 37 ++- pkg/common/utils/env.go | 36 +++ pkg/protocol/http1/server.go | 31 ++- pkg/protocol/http1/server_test.go | 40 +++ pkg/route/engine.go | 10 +- pkg/route/engine_test.go | 12 +- 8 files changed, 330 insertions(+), 72 deletions(-) create mode 100644 pkg/common/utils/env.go diff --git a/pkg/app/client/client_test.go b/pkg/app/client/client_test.go index 5f3e8c62f..ed5959bea 100644 --- a/pkg/app/client/client_test.go +++ b/pkg/app/client/client_test.go @@ -92,7 +92,12 @@ func TestCloseIdleConnections(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) @@ -136,7 +141,12 @@ func TestClientInvalidURI(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) req, res := protocol.AcquireRequest(), protocol.AcquireResponse() @@ -170,7 +180,12 @@ func TestClientGetWithBody(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) req, res := protocol.AcquireRequest(), protocol.AcquireResponse() @@ -205,7 +220,12 @@ func TestClientPostBodyStream(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } cStream, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil)), WithResponseBodyStream(true)) args := &protocol.Args{} @@ -246,7 +266,12 @@ func TestClientURLAuth(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) for up, expected := range cases { @@ -278,7 +303,12 @@ func TestClientNilResp(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) @@ -301,7 +331,15 @@ func TestClientParseConn(t *testing.T) { engine.GET("/", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(time.Millisecond * 500) + defer func() { + engine.Close() + }() + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) req, res := protocol.AcquireRequest(), protocol.AcquireResponse() @@ -343,7 +381,12 @@ func TestClientPostArgs(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) req, res := protocol.AcquireRequest(), protocol.AcquireResponse() defer func() { @@ -403,20 +446,22 @@ func TestClientReadTimeout(t *testing.T) { t.Skip("skipping test in short mode") } - timeout := false opt := config.NewOptions([]config.Option{}) - opt.Addr = "localhost:10008" + opt.Addr = "localhost:10024" engine := route.NewEngine(opt) - engine.GET("/", func(c context.Context, ctx *app.RequestContext) { - if timeout { - time.Sleep(time.Minute) - } else { - timeout = true - } + engine.GET("/normal", func(c context.Context, ctx *app.RequestContext) { + ctx.String(201, "ok") + }) + engine.GET("/timeout", func(c context.Context, ctx *app.RequestContext) { + time.Sleep(time.Second * 60) + ctx.String(202, "timeout ok") }) go engine.Run() - time.Sleep(time.Millisecond * 500) + defer func() { + engine.Close() + }() + time.Sleep(time.Second * 1) c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -430,7 +475,7 @@ func TestClientReadTimeout(t *testing.T) { req := protocol.AcquireRequest() res := protocol.AcquireResponse() - req.SetRequestURI("http://" + opt.Addr) + req.SetRequestURI("http://" + opt.Addr + "/normal") req.Header.SetMethod(consts.MethodGet) // Setting Connection: Close will make the connection be returned to the pool. @@ -448,13 +493,17 @@ func TestClientReadTimeout(t *testing.T) { req := protocol.AcquireRequest() res := protocol.AcquireResponse() - req.SetRequestURI("http://" + opt.Addr) + req.SetRequestURI("http://" + opt.Addr + "/timeout") req.Header.SetMethod(consts.MethodGet) req.SetConnectionClose() if err := c.Do(context.Background(), req, res); !errors.Is(err, errs.ErrTimeout) { - if !strings.Contains(err.Error(), "timeout") { - t.Errorf("expected ErrTimeout got %#v", err) + if err == nil { + t.Errorf("expected ErrTimeout got nil, req url: %s, read resp body: %s, status: %d", string(req.URI().FullURI()), string(res.Body()), res.StatusCode()) + } else { + if !strings.Contains(err.Error(), "timeout") { + t.Errorf("expected ErrTimeout got %#v", err) + } } } @@ -488,7 +537,12 @@ func TestClientDefaultUserAgent(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) req := protocol.AcquireRequest() @@ -522,7 +576,12 @@ func TestClientSetUserAgent(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } userAgent := "I'm not hertz" c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, time.Second, nil)), WithName(userAgent)) @@ -553,7 +612,12 @@ func TestClientNoUserAgent(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, time.Second, nil)), WithDialTimeout(1*time.Second), WithNoDefaultUserAgentHeader(true)) req := protocol.AcquireRequest() @@ -634,7 +698,12 @@ func TestClientDoWithCustomHeaders(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } // make sure that the client sends all the request headers and body. c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil))) @@ -679,7 +748,12 @@ func TestClientDoTimeoutDisablePathNormalizing(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, time.Second, nil)), WithDisablePathNormalizing(true)) urlWithEncodedPath := "http://example.com/encoded/Y%2BY%2FY%3D/stuff" @@ -809,7 +883,12 @@ func TestHostClientMaxConnsWithDeadline(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -878,7 +957,12 @@ func TestHostClientMaxConnDuration(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -923,7 +1007,12 @@ func TestHostClientMultipleAddrs(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } dialsCount := make(map[string]int) c := &http1.HostClient{ @@ -990,7 +1079,7 @@ func TestClientFollowRedirects(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + time.Sleep(time.Second * 2) c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -1084,7 +1173,12 @@ func TestHostClientMaxConnWaitTimeoutSuccess(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -1153,7 +1247,12 @@ func TestHostClientMaxConnWaitTimeoutError(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + for { + time.Sleep(1 * time.Second) + if engine.IsRunning() { + break + } + } c := &http1.HostClient{ ClientOptions: &http1.ClientOptions{ @@ -1215,7 +1314,10 @@ func TestNewClient(t *testing.T) { ctx.SetBodyString("pong") }) go engine.Run() - time.Sleep(time.Millisecond * 500) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) client, err := NewClient(WithDialTimeout(2 * time.Second)) if err != nil { @@ -1240,7 +1342,10 @@ func TestUseShortConnection(t *testing.T) { engine.GET("/", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(time.Millisecond * 500) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) c, _ := NewClient(WithKeepAlive(false)) var wg sync.WaitGroup @@ -1284,8 +1389,11 @@ func TestPostWithFormData(t *testing.T) { ctx.Data(consts.StatusOK, "text/plain; charset=utf-8", []byte(ans)) }) go engine.Run() + defer func() { + engine.Close() + }() - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) client, _ := NewClient() req := protocol.AcquireRequest() rsp := protocol.AcquireResponse() @@ -1335,8 +1443,11 @@ func TestPostWithMultipartField(t *testing.T) { t.Log(req.GetHTTP1Request(&ctx.Request).String()) }) go engine.Run() + defer func() { + engine.Close() + }() - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) client, _ := NewClient() req := protocol.AcquireRequest() rsp := protocol.AcquireResponse() @@ -1378,8 +1489,11 @@ func TestSetFiles(t *testing.T) { ctx.String(consts.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)+2)) }) go engine.Run() + defer func() { + engine.Close() + }() - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) client, _ := NewClient() req := protocol.AcquireRequest() rsp := protocol.AcquireResponse() @@ -1426,8 +1540,11 @@ func TestSetMultipartFields(t *testing.T) { ctx.String(consts.StatusOK, fmt.Sprintf("%d files uploaded!", 2)) }) go engine.Run() + defer func() { + engine.Close() + }() - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) client, _ := NewClient(WithDialTimeout(50 * time.Millisecond)) req := protocol.AcquireRequest() rsp := protocol.AcquireResponse() @@ -1478,7 +1595,10 @@ func TestClientReadResponseBodyStream(t *testing.T) { c.String(consts.StatusOK, part1+part2) }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) client, _ := NewClient(WithResponseBodyStream(true)) req, resp := protocol.AcquireRequest(), protocol.AcquireResponse() @@ -1528,7 +1648,10 @@ func TestWithBasicAuth(t *testing.T) { } }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) client, _ := NewClient() req := protocol.AcquireRequest() rsp := protocol.AcquireResponse() @@ -1896,7 +2019,10 @@ func TestClientReadResponseBodyStreamWithDoubleRequest(t *testing.T) { c.String(consts.StatusOK, part1+part2) }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) client, _ := NewClient(WithResponseBodyStream(true)) req, resp := protocol.AcquireRequest(), protocol.AcquireResponse() @@ -1966,7 +2092,10 @@ func TestClientReadResponseBodyStreamWithConnectionClose(t *testing.T) { c.String(consts.StatusOK, part1) }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) client, _ := NewClient(WithResponseBodyStream(true)) @@ -2276,7 +2405,7 @@ func TestClientDoWithDialFunc(t *testing.T) { defer func() { engine.Close() }() - time.Sleep(time.Millisecond * 500) + time.Sleep(1 * time.Second) c, _ := NewClient(WithDialFunc(func(addr string) (network.Conn, error) { return dialer.DialConnection(opt.Network, opt.Addr, time.Second, nil) @@ -2307,11 +2436,14 @@ func TestClientDoWithDialFunc(t *testing.T) { func TestClientState(t *testing.T) { opt := config.NewOptions([]config.Option{}) - opt.Addr = ":10037" + opt.Addr = "127.0.0.1:10037" engine := route.NewEngine(opt) go engine.Run() + defer func() { + engine.Close() + }() - time.Sleep(time.Millisecond) + time.Sleep(1 * time.Second) state := int32(0) client, _ := NewClient( @@ -2351,14 +2483,16 @@ func TestClientRetryErr(t *testing.T) { ctx.SetStatusCode(200) }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) c, _ := NewClient(WithRetryConfig(retry.WithMaxAttemptTimes(3))) _, _, err := c.Get(context.Background(), nil, "http://127.0.0.1:10136/ping") assert.Nil(t, err) l.Lock() assert.DeepEqual(t, 1, retryNum) l.Unlock() - engine.Close() }) t.Run("502", func(t *testing.T) { @@ -2374,7 +2508,10 @@ func TestClientRetryErr(t *testing.T) { ctx.SetStatusCode(502) }) go engine.Run() - time.Sleep(100 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) c, _ := NewClient(WithRetryConfig(retry.WithMaxAttemptTimes(3))) c.SetRetryIfFunc(func(req *protocol.Request, resp *protocol.Response, err error) bool { return resp.StatusCode() == 502 @@ -2384,6 +2521,5 @@ func TestClientRetryErr(t *testing.T) { l.Lock() assert.DeepEqual(t, 3, retryNum) l.Unlock() - engine.Close() }) } diff --git a/pkg/app/server/binding/internal/decoder/text_decoder.go b/pkg/app/server/binding/internal/decoder/text_decoder.go index 8b53c2bf5..fb598239a 100644 --- a/pkg/app/server/binding/internal/decoder/text_decoder.go +++ b/pkg/app/server/binding/internal/decoder/text_decoder.go @@ -87,7 +87,7 @@ func SelectTextDecoder(rt reflect.Type) (TextDecoder, error) { return &interfaceDecoder{}, nil } - return nil, fmt.Errorf("unsupported type " + rt.String()) + return nil, fmt.Errorf("unsupported type %s", rt.String()) } type boolDecoder struct{} diff --git a/pkg/app/server/hertz_test.go b/pkg/app/server/hertz_test.go index d20db2f96..09e77dd40 100644 --- a/pkg/app/server/hertz_test.go +++ b/pkg/app/server/hertz_test.go @@ -158,7 +158,10 @@ func TestLoadHTMLGlob(t *testing.T) { }) }) go engine.Run() - time.Sleep(200 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) resp, _ := http.Get("http://127.0.0.1:8893/index") assert.DeepEqual(t, consts.StatusOK, resp.StatusCode) b := make([]byte, 100) @@ -182,7 +185,10 @@ func TestLoadHTMLFiles(t *testing.T) { }) }) go engine.Run() - time.Sleep(200 * time.Millisecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) resp, _ := http.Get("http://127.0.0.1:8891/raw") assert.DeepEqual(t, consts.StatusOK, resp.StatusCode) b := make([]byte, 100) @@ -227,7 +233,7 @@ func TestServer_Run(t *testing.T) { ctx.Redirect(consts.StatusMovedPermanently, []byte("http://127.0.0.1:8899/test")) }) go hertz.Run() - time.Sleep(100 * time.Microsecond) + time.Sleep(1 * time.Second) resp, err := http.Get("http://127.0.0.1:8899/test") assert.Nil(t, err) assert.DeepEqual(t, consts.StatusOK, resp.StatusCode) @@ -260,7 +266,10 @@ func TestNotAbsolutePath(t *testing.T) { ctx.Write(ctx.Request.Body()) }) go engine.Run() - time.Sleep(200 * time.Microsecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) s := "POST ?a=b HTTP/1.1\r\nHost: a.b.c\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" zr := mock.NewZeroCopyReader(s) @@ -299,7 +308,10 @@ func TestNotAbsolutePathWithRawPath(t *testing.T) { engine.POST("/a", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(200 * time.Microsecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) s := "POST ?a=b HTTP/1.1\r\nHost: a.b.c\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" zr := mock.NewZeroCopyReader(s) @@ -374,7 +386,10 @@ func TestWithBasePath(t *testing.T) { engine.POST("/test", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(500 * time.Microsecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) var r http.Request r.ParseForm() r.Form.Add("xxxxxx", "xxx") @@ -389,7 +404,10 @@ func TestNotEnoughBodySize(t *testing.T) { engine.POST("/test", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(200 * time.Microsecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) var r http.Request r.ParseForm() r.Form.Add("xxxxxx", "xxx") @@ -406,7 +424,10 @@ func TestEnoughBodySize(t *testing.T) { engine.POST("/test", func(c context.Context, ctx *app.RequestContext) { }) go engine.Run() - time.Sleep(200 * time.Microsecond) + defer func() { + engine.Close() + }() + time.Sleep(1 * time.Second) var r http.Request r.ParseForm() r.Form.Add("xxxxxx", "xxx") diff --git a/pkg/common/utils/env.go b/pkg/common/utils/env.go new file mode 100644 index 000000000..291b5e3bd --- /dev/null +++ b/pkg/common/utils/env.go @@ -0,0 +1,36 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "os" + "strconv" + "strings" + + "github.com/cloudwego/hertz/pkg/common/errors" +) + +// Get bool from env +func GetBoolFromEnv(key string) (bool, error) { + value, isExist := os.LookupEnv(key) + if !isExist { + return false, errors.NewPublic("env not exist") + } + + value = strings.TrimSpace(value) + return strconv.ParseBool(value) +} diff --git a/pkg/protocol/http1/server.go b/pkg/protocol/http1/server.go index 3ea659603..eb46f6533 100644 --- a/pkg/protocol/http1/server.go +++ b/pkg/protocol/http1/server.go @@ -32,6 +32,7 @@ import ( errs "github.com/cloudwego/hertz/pkg/common/errors" "github.com/cloudwego/hertz/pkg/common/tracer/stats" "github.com/cloudwego/hertz/pkg/common/tracer/traceinfo" + "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/network" "github.com/cloudwego/hertz/pkg/protocol" "github.com/cloudwego/hertz/pkg/protocol/consts" @@ -41,6 +42,12 @@ import ( "github.com/cloudwego/hertz/pkg/protocol/suite" ) +func init() { + if b, err := utils.GetBoolFromEnv("HERTZ_DISABLE_REQUEST_CONTEXT_POOL"); err == nil { + disabaleRequestContextPool = b + } +} + // NextProtoTLS is the NPN/ALPN protocol negotiated during // HTTP/1.1's TLS setup. // Also used for server addressing @@ -51,6 +58,8 @@ var ( errIdleTimeout = errs.New(errs.ErrIdleTimeout, errs.ErrorTypePrivate, nil) errShortConnection = errs.New(errs.ErrShortConnection, errs.ErrorTypePublic, "server is going to close the connection") errUnexpectedEOF = errs.NewPublic(io.ErrUnexpectedEOF.Error() + " when reading request") + + disabaleRequestContextPool = false ) type Option struct { @@ -80,6 +89,21 @@ type Server struct { eventStackPool *sync.Pool } +func (s Server) getRequestContext() *app.RequestContext { + if disabaleRequestContextPool { + return &app.RequestContext{} + } + return s.Core.GetCtxPool().Get().(*app.RequestContext) +} + +func (s Server) putRequestContext(ctx *app.RequestContext) { + if disabaleRequestContextPool { + return + } + ctx.Reset() + s.Core.GetCtxPool().Put(ctx) +} + func (s Server) Serve(c context.Context, conn network.Conn) (err error) { var ( zr network.Reader @@ -97,8 +121,8 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) { // 1. Get a request context // 2. Prepare it // 3. Process it - // 4. Reset and recycle - ctx = s.Core.GetCtxPool().Get().(*app.RequestContext) + // 4. Reset and recycle(in pooled mode) + ctx = s.getRequestContext() traceCtl = s.Core.GetTracer() eventsToTrigger *eventStack @@ -138,8 +162,7 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) { return } - ctx.Reset() - s.Core.GetCtxPool().Put(ctx) + s.putRequestContext(ctx) }() ctx.HTMLRender = s.HTMLRender diff --git a/pkg/protocol/http1/server_test.go b/pkg/protocol/http1/server_test.go index 2263ece77..d478b36fc 100644 --- a/pkg/protocol/http1/server_test.go +++ b/pkg/protocol/http1/server_test.go @@ -218,6 +218,46 @@ func TestDefaultWriter(t *testing.T) { assert.DeepEqual(t, "hello, hertz", string(response.Body())) } +func TestServerDisableReqCtxPool(t *testing.T) { + server := &Server{} + reqCtx := &app.RequestContext{} + server.Core = &mockCore{ + ctxPool: &sync.Pool{New: func() interface{} { + reqCtx.Set("POOL_KEY", "in pool") + return reqCtx + }}, + mockHandler: func(c context.Context, ctx *app.RequestContext) { + if ctx.GetString("POOL_KEY") != "in pool" { + t.Fatal("reqCtx is not in pool") + } + }, + isRunning: true, + } + defaultConn := mock.NewConn("GET / HTTP/1.1\nHost: foobar.com\n\n") + err := server.Serve(context.TODO(), defaultConn) + assert.Nil(t, err) + disabaleRequestContextPool = true + defer func() { + // reset global variable + disabaleRequestContextPool = false + }() + server.Core = &mockCore{ + ctxPool: &sync.Pool{New: func() interface{} { + reqCtx.Set("POOL_KEY", "in pool") + return reqCtx + }}, + mockHandler: func(c context.Context, ctx *app.RequestContext) { + if len(ctx.GetString("POOL_KEY")) != 0 { + t.Fatal("must not get pool key") + } + }, + isRunning: true, + } + defaultConn = mock.NewConn("GET / HTTP/1.1\nHost: foobar.com\n\n") + err = server.Serve(context.TODO(), defaultConn) + assert.Nil(t, err) +} + func TestHijackResponseWriter(t *testing.T) { server := &Server{} reqCtx := &app.RequestContext{} diff --git a/pkg/route/engine.go b/pkg/route/engine.go index 4881ee9cf..2a7b60ca6 100644 --- a/pkg/route/engine.go +++ b/pkg/route/engine.go @@ -349,11 +349,6 @@ func (engine *Engine) Run() (err error) { return err } - if err = engine.MarkAsRunning(); err != nil { - return err - } - defer atomic.StoreUint32(&engine.status, statusClosed) - // trigger hooks if any ctx := context.Background() for i := range engine.OnRun { @@ -362,6 +357,11 @@ func (engine *Engine) Run() (err error) { } } + if err = engine.MarkAsRunning(); err != nil { + return err + } + defer atomic.StoreUint32(&engine.status, statusClosed) + return engine.listenAndServe() } diff --git a/pkg/route/engine_test.go b/pkg/route/engine_test.go index ea1bc5fd9..a5da5dc56 100644 --- a/pkg/route/engine_test.go +++ b/pkg/route/engine_test.go @@ -875,20 +875,22 @@ func TestEngineShutdown(t *testing.T) { defaultTransporter = standard.NewTransporter mockCtxCallback := func(ctx context.Context) {} // Test case 1: serve not running error - engine := NewEngine(config.NewOptions(nil)) + opt := config.NewOptions(nil) + opt.Addr = "127.0.0.1:10027" + engine := NewEngine(opt) ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second) defer cancel1() err := engine.Shutdown(ctx1) assert.DeepEqual(t, errStatusNotRunning, err) // Test case 2: serve successfully running and shutdown - engine = NewEngine(config.NewOptions(nil)) + engine = NewEngine(opt) engine.OnShutdown = []CtxCallback{mockCtxCallback} go func() { engine.Run() }() // wait for engine to start - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second) defer cancel2() @@ -897,14 +899,14 @@ func TestEngineShutdown(t *testing.T) { assert.DeepEqual(t, statusClosed, atomic.LoadUint32(&engine.status)) // Test case 3: serve successfully running and shutdown with deregistry error - engine = NewEngine(config.NewOptions(nil)) + engine = NewEngine(opt) engine.OnShutdown = []CtxCallback{mockCtxCallback} engine.options.Registry = &mockDeregsitryErr{} go func() { engine.Run() }() // wait for engine to start - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) ctx3, cancel3 := context.WithTimeout(context.Background(), time.Second) defer cancel3() From 4a8a710e92599b690496953ba374257d32470b7e Mon Sep 17 00:00:00 2001 From: Snowykami Date: Mon, 2 Sep 2024 15:45:29 +0800 Subject: [PATCH 08/11] feat: Add method PostFormArray to app.RequestContext. (#1172) --- pkg/app/context.go | 40 +++++++++++++++++++++++++++++++++++++++ pkg/app/context_test.go | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/pkg/app/context.go b/pkg/app/context.go index 369ece736..1d925b7a5 100644 --- a/pkg/app/context.go +++ b/pkg/app/context.go @@ -694,6 +694,17 @@ func (ctx *RequestContext) multipartFormValue(key string) (string, bool) { return "", false } +func (ctx *RequestContext) multipartFormValueArray(key string) ([]string, bool) { + mf, err := ctx.MultipartForm() + if err == nil && mf.Value != nil { + vv := mf.Value[key] + if len(vv) > 0 { + return vv, true + } + } + return nil, false +} + func (ctx *RequestContext) RequestBodyStream() io.Reader { return ctx.Request.BodyStream() } @@ -1366,6 +1377,13 @@ func (ctx *RequestContext) PostForm(key string) string { return value } +// PostFormArray returns the specified key from a POST urlencoded form or multipart form +// when it exists, otherwise it returns an empty array `([])`. +func (ctx *RequestContext) PostFormArray(key string) []string { + values, _ := ctx.GetPostFormArray(key) + return values +} + // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns the specified defaultValue string. // @@ -1393,6 +1411,28 @@ func (ctx *RequestContext) GetPostForm(key string) (string, bool) { return ctx.multipartFormValue(key) } +// GetPostFormArray is like PostFormArray(key). It returns the specified key from a POST urlencoded +// form or multipart form when it exists `([]string, true)` (even when the value is an empty string), +// otherwise it returns ([]string(nil), false). +// +// For example, during a PATCH request to update the item's tags: +// +// tag=tag1 tag=tag2 tag=tag3 --> (["tag1", "tag2", "tag3"], true) := GetPostFormArray("tags") // set tags to ["tag1", "tag2", "tag3"] +// tags= --> (nil, true) := GetPostFormArray("tags") // set tags to nil +// --> (nil, false) := GetPostFormArray("tags") // do nothing with tags +func (ctx *RequestContext) GetPostFormArray(key string) ([]string, bool) { + vs := ctx.PostArgs().PeekAll(key) + values := make([]string, len(vs)) + for i, v := range vs { + values[i] = string(v) + } + if len(values) == 0 { + return ctx.multipartFormValueArray(key) + } else { + return values, true + } +} + // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. func bodyAllowedForStatus(status int) bool { switch { diff --git a/pkg/app/context_test.go b/pkg/app/context_test.go index 1317a062c..28e54ce6e 100644 --- a/pkg/app/context_test.go +++ b/pkg/app/context_test.go @@ -367,6 +367,40 @@ hello=world`) } } +func TestPostFormArray(t *testing.T) { + t.Parallel() + + ctx := makeCtxByReqString(t, `POST /upload HTTP/1.1 +Host: localhost:10000 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg +Content-Length: 521 + +------WebKitFormBoundaryJwfATyF8tmxSJnLg +Content-Disposition: form-data; name="tag" + +red +------WebKitFormBoundaryJwfATyF8tmxSJnLg +Content-Disposition: form-data; name="tag" + +green +------WebKitFormBoundaryJwfATyF8tmxSJnLg +Content-Disposition: form-data; name="tag" + +blue +------WebKitFormBoundaryJwfATyF8tmxSJnLg-- +`) + assert.DeepEqual(t, []string{"red", "green", "blue"}, ctx.PostFormArray("tag")) + + ctx = makeCtxByReqString(t, `POST /upload HTTP/1.1 +Host: localhost:10000 +Content-Type: application/x-www-form-urlencoded; charset=UTF-8 +Content-Length: 26 + +tag=red&tag=green&tag=blue +`) + assert.DeepEqual(t, []string{"red", "green", "blue"}, ctx.PostFormArray("tag")) +} + func TestDefaultPostForm(t *testing.T) { ctx := makeCtxByReqString(t, `POST /upload HTTP/1.1 Host: localhost:10000 @@ -930,6 +964,14 @@ func TestGetPostForm(t *testing.T) { assert.DeepEqual(t, true, exists) } +func TestGetPostFormArray(t *testing.T) { + c := NewContext(0) + c.Request.Header.SetContentTypeBytes([]byte(consts.MIMEApplicationHTMLForm)) + c.Request.SetBodyString("a=1&b=2&b=3") + v, _ := c.GetPostFormArray("b") + assert.DeepEqual(t, []string{"2", "3"}, v) +} + func TestRemoteAddr(t *testing.T) { c := NewContext(0) c.Request.SetRequestURI("http://aaa.com?a=1&b=") From 63f9ab50b10bd474dbff791e5ec5c500066eca3c Mon Sep 17 00:00:00 2001 From: Elvis_LEE <41870265+ElvisWai@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:45:58 +0800 Subject: [PATCH 09/11] fix: update ut for assert.NotNil (#1181) Co-authored-by: ElvisWai --- pkg/app/context_test.go | 8 ++++++-- pkg/common/test/assert/assert.go | 2 +- pkg/common/utils/ioutil_test.go | 8 ++++---- pkg/protocol/http1/req/header_test.go | 8 ++++++-- pkg/protocol/multipart_test.go | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pkg/app/context_test.go b/pkg/app/context_test.go index 28e54ce6e..b2aef633f 100644 --- a/pkg/app/context_test.go +++ b/pkg/app/context_test.go @@ -542,7 +542,9 @@ func TestContextRenderFileFromFS(t *testing.T) { assert.DeepEqual(t, consts.StatusOK, ctx.Response.StatusCode()) assert.True(t, strings.Contains(resp.GetHTTP1Response(&ctx.Response).String(), "func (fs *FS) initRequestHandler() {")) - assert.DeepEqual(t, consts.MIMETextPlainUTF8, string(ctx.Response.Header.Peek("Content-Type"))) + // when Go version <= 1.16, mime.TypeByExtension will return Content-Type='text/plain; charset=utf-8', + // otherwise it will return Content-Type='text/x-go; charset=utf-8' + assert.NotEqual(t, "", string(ctx.Response.Header.Peek("Content-Type"))) assert.DeepEqual(t, "/some/path", string(ctx.Request.URI().Path())) } @@ -559,7 +561,9 @@ func TestContextRenderFile(t *testing.T) { assert.DeepEqual(t, consts.StatusOK, ctx.Response.StatusCode()) assert.True(t, strings.Contains(resp.GetHTTP1Response(&ctx.Response).String(), "func (fs *FS) initRequestHandler() {")) - assert.DeepEqual(t, consts.MIMETextPlainUTF8, string(ctx.Response.Header.Peek("Content-Type"))) + // when Go version <= 1.16, mime.TypeByExtension will return Content-Type='text/plain; charset=utf-8', + // otherwise it will return Content-Type='text/x-go; charset=utf-8' + assert.NotEqual(t, "", string(ctx.Response.Header.Peek("Content-Type"))) } func TestContextRenderAttachment(t *testing.T) { diff --git a/pkg/common/test/assert/assert.go b/pkg/common/test/assert/assert.go index ed157835c..c82d84c00 100644 --- a/pkg/common/test/assert/assert.go +++ b/pkg/common/test/assert/assert.go @@ -62,7 +62,7 @@ func Nil(t testing.TB, data interface{}) { func NotNil(t testing.TB, data interface{}) { t.Helper() - if data == nil { + if data != nil { return } diff --git a/pkg/common/utils/ioutil_test.go b/pkg/common/utils/ioutil_test.go index e9a573b47..ed7ebf86d 100644 --- a/pkg/common/utils/ioutil_test.go +++ b/pkg/common/utils/ioutil_test.go @@ -153,7 +153,7 @@ func TestIoutilCopyBufferWithIoReaderFrom(t *testing.T) { assert.DeepEqual(t, true, ok) written, err := CopyBuffer(ioReaderFrom, src, buf) assert.DeepEqual(t, written, int64(0)) - assert.NotNil(t, err) + assert.Nil(t, err) assert.DeepEqual(t, []byte(nil), writeBuffer.Bytes()) } @@ -182,7 +182,7 @@ func TestIoutilCopyBufferWithNilBuffer(t *testing.T) { written, err := CopyBuffer(dst, src, nil) assert.DeepEqual(t, written, srcLen) - assert.NotNil(t, err) + assert.Nil(t, err) assert.DeepEqual(t, []byte(str), writeBuffer.Bytes()) } @@ -196,7 +196,7 @@ func TestIoutilCopyBufferWithNilBufferAndIoLimitedReader(t *testing.T) { written, err := CopyBuffer(dst, &reader, nil) assert.DeepEqual(t, written, srcLen) - assert.NotNil(t, err) + assert.Nil(t, err) assert.DeepEqual(t, []byte(str), writeBuffer.Bytes()) // test l.N < 1 @@ -209,7 +209,7 @@ func TestIoutilCopyBufferWithNilBufferAndIoLimitedReader(t *testing.T) { written, err = CopyBuffer(dst, &reader, nil) assert.DeepEqual(t, written, srcLen) - assert.NotNil(t, err) + assert.Nil(t, err) assert.DeepEqual(t, []byte(str), writeBuffer.Bytes()) } diff --git a/pkg/protocol/http1/req/header_test.go b/pkg/protocol/http1/req/header_test.go index d0978b3c4..29192c7c3 100644 --- a/pkg/protocol/http1/req/header_test.go +++ b/pkg/protocol/http1/req/header_test.go @@ -441,7 +441,7 @@ func TestTryRead(t *testing.T) { s := "P" zr := mock.NewZeroCopyReader(s) err := tryRead(&rh, zr, 0) - assert.NotNil(t, err) + assert.Nil(t, err) } func TestParseFirstLine(t *testing.T) { @@ -481,7 +481,11 @@ func TestParseFirstLine(t *testing.T) { for _, tc := range tests { header := &protocol.RequestHeader{} _, err := parseFirstLine(header, tc.input) - assert.NotNil(t, err) + if tc.err != nil { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } } } diff --git a/pkg/protocol/multipart_test.go b/pkg/protocol/multipart_test.go index 6b96ae86f..f6e4c1dca 100644 --- a/pkg/protocol/multipart_test.go +++ b/pkg/protocol/multipart_test.go @@ -174,7 +174,7 @@ func TestWriteMultipartFormFile(t *testing.T) { assert.True(t, strings.Contains(bodyBuffer.String(), string(buf1))) // test file not found - assert.NotNil(t, WriteMultipartFormFile(w, multipartFile.ParamName, "test.go", multipartFile.Reader)) + assert.Nil(t, WriteMultipartFormFile(w, multipartFile.ParamName, "test.go", multipartFile.Reader)) // Test Add File Function err = AddFile(w, "responseCode", "./response.go") From 986797ee011b8a494dcd84ec67827f08d1de2ff4 Mon Sep 17 00:00:00 2001 From: Xin Hao Date: Thu, 5 Sep 2024 11:30:03 +0800 Subject: [PATCH 10/11] build: add Go 1.23 to unit tests CI (#1171) --- .github/workflows/tests.yml | 4 ++-- .gitignore | 1 + go.mod | 4 ++-- go.sum | 7 ++++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7c97b982e..54ce8b96e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: unit-test: strategy: matrix: - version: ["1.20", "1.21", "1.22"] + version: ["1.20", "1.21", "1.22", "1.23"] runs-on: [self-hosted, X64] steps: - uses: actions/checkout@v4 @@ -42,7 +42,7 @@ jobs: ut-windows: strategy: matrix: - version: ["1.20", "1.21", "1.22"] + version: ["1.20", "1.21", "1.22", "1.23"] runs-on: windows-latest steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 02e193d54..338957806 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea .vscode pkg/app/fs.go.hertz.gz +coverage.txt coverage.out diff --git a/go.mod b/go.mod index 0fd7648ad..cc537142f 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,13 @@ go 1.17 require ( github.com/bytedance/go-tagexpr/v2 v2.9.2 github.com/bytedance/gopkg v0.1.0 - github.com/bytedance/mockey v1.2.10 + github.com/bytedance/mockey v1.2.12 github.com/bytedance/sonic v1.12.0 github.com/cloudwego/netpoll v0.6.2 github.com/fsnotify/fsnotify v1.5.4 github.com/tidwall/gjson v1.14.4 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 + golang.org/x/sys v0.24.0 google.golang.org/protobuf v1.27.1 ) diff --git a/go.sum b/go.sum index f20c60c76..446891e45 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2q github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= github.com/bytedance/gopkg v0.1.0 h1:aAxB7mm1qms4Wz4sp8e1AtKDOeFLtdqvGiUe7aonRJs= github.com/bytedance/gopkg v0.1.0/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= -github.com/bytedance/mockey v1.2.10 h1:4JlMpkm7HMXmTUtItid+iCu2tm61wvq+ca1X2u7ymzE= -github.com/bytedance/mockey v1.2.10/go.mod h1:bNrUnI1u7+pAc0TYDgPATM+wF2yzHxmNH+iDXg4AOCU= +github.com/bytedance/mockey v1.2.12 h1:aeszOmGw8CPX8CRx1DZ/Glzb1yXvhjDh6jdFBNZjsU4= +github.com/bytedance/mockey v1.2.12/go.mod h1:3ZA4MQasmqC87Tw0w7Ygdy7eHIc2xgpZ8Pona5rsYIk= github.com/bytedance/sonic v1.12.0 h1:YGPgxF9xzaCNvd/ZKdQ28yRovhfMFZQjuk6fKBzZ3ls= github.com/bytedance/sonic v1.12.0/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -76,8 +76,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= From 0bb52fb078ecc6579af428f24e448c0592c345c2 Mon Sep 17 00:00:00 2001 From: alice <90381261+alice-yyds@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:55:36 +0800 Subject: [PATCH 11/11] chore: update version v0.9.3 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 3a0529dfc..1f5fabefb 100644 --- a/version.go +++ b/version.go @@ -19,5 +19,5 @@ package hertz // Name and Version info of this framework, used for statistics and debug const ( Name = "Hertz" - Version = "v0.9.2" + Version = "v0.9.3" )