Repository: cloudwego/hertz
Pull request #1312 (2025-03-25 03:14:43)

ci: deprecate tj-actions
#### What type of PR is this?
ci

<!--
Add one of the following kinds:

build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
docs: Documentation only changes
feat: A new feature
optimize: A new optimization
fix: A bug fix
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc)
test: Adding missing tests or correcting existing tests
chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
-->

#### Check the PR title.
<!--
The description of the title will be attached in Release Notes, 
so please describe it from user-oriented, what this PR does / why we need it.
Please check your PR title with the below requirements:
-->
- [x] This PR title match the format: \<type\>(optional scope): \<description\>
- [x] The description of this PR title is user-oriented and clear enough for others to understand.
- [ ] Attach the PR updating the user documentation if the current PR requires user awareness at the usage level. [User docs repo](https://github.com/cloudwego/cloudwego.github.io)


#### (Optional) Translate the PR title into Chinese.


#### (Optional) More detailed description for this PR(en: English/zh: Chinese).
<!--
Provide more detailed info for review(e.g., it's recommended to provide perf data if this is a perf type PR).
-->
en:
zh(optional):

#### (Optional) Which issue(s) this PR fixes:
<!--
Automatically closes linked issue when PR is merged.
Eg: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->

#### (Optional) The PR that updates user documentation:
<!--
If the current PR requires user awareness at the usage level, please submit a PR to update user docs. [User docs repo](https://github.com/cloudwego/cloudwego.github.io)
-->

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cloudwego/hertz/pull/1312?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 72.36%. Comparing base [(`576bc6f`)](https://app.codecov.io/gh/cloudwego/hertz/commit/576bc6f962a130e5bb7d66f337131953e2d60b58?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) to head [(`f174ce1`)](https://app.codecov.io/gh/cloudwego/hertz/commit/f174ce194bac603bfdf6a47347350210881feb87?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop    #1312      +/-   ##
===========================================
- Coverage    72.38%   72.36%   -0.02%     
===========================================
  Files          139      139              
  Lines        16235    16235              
===========================================
- Hits         11752    11749       -3     
- Misses        3888     3889       +1     
- Partials       595      597       +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cloudwego/hertz/pull/1312?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/pkg/common/bytebufferpool/bytebuffer.go b/pkg/common/bytebufferpool/bytebuffer.go
index 6561746..2254cbb 100644
--- a/pkg/common/bytebufferpool/bytebuffer.go
+++ b/pkg/common/bytebufferpool/bytebuffer.go
@@ -61,6 +61,10 @@ func (b *ByteBuffer) Len() int {
 	return len(b.B)
 }
 
+func (b *ByteBuffer) Cap() int {
+	return cap(b.B)
+}
+
 // ReadFrom implements io.ReaderFrom.
 //
 // The function appends all the data read from r to b.
diff --git a/pkg/protocol/request.go b/pkg/protocol/request.go
index 8e4b40b..0c1c3f4 100644
--- a/pkg/protocol/request.go
+++ b/pkg/protocol/request.go
@@ -411,7 +411,7 @@ func (req *Request) ResetBody() {
 	req.RemoveMultipartFormFiles()
 	req.CloseBodyStream() //nolint:errcheck
 	if req.body != nil {
-		if req.body.Len() <= req.maxKeepBodySize {
+		if req.body.Cap() <= req.maxKeepBodySize {
 			req.body.Reset()
 			return
 		}
diff --git a/pkg/protocol/response.go b/pkg/protocol/response.go
index ccace13..174ae4f 100644
--- a/pkg/protocol/response.go
+++ b/pkg/protocol/response.go
@@ -296,7 +296,7 @@ func (resp *Response) ResetBody() {
 	resp.bodyRaw = nil
 	resp.CloseBodyStream() //nolint:errcheck
 	if resp.body != nil {
-		if resp.body.Len() <= resp.maxKeepBodySize {
+		if resp.body.Cap() <= resp.maxKeepBodySize {
 			resp.body.Reset()
 			return
 		}


Test patch:
diff --git a/.github/workflows/cmd-tests.yml b/.github/workflows/cmd-tests.yml
new file mode 100644
index 0000000..047785b
--- /dev/null
+++ b/.github/workflows/cmd-tests.yml
@@ -0,0 +1,55 @@
+name: Cmd Tests
+
+on:
+  push:
+    paths:
+      - 'cmd/**'
+  pull_request:
+    paths:
+      - 'cmd/**'
+
+jobs:
+  hz-test-unix:
+    runs-on: [ self-hosted, Linux, 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: Setup Environment
+        run: |
+          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
+          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
+
+      - name: Hz Test
+        run: |
+          cd cmd/hz
+          sh test_hz_unix.sh
+
+
+  hz-test-windows:
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: stable
+
+      - name: Install Protobuf
+        shell: pwsh
+        run: |
+          Invoke-WebRequest https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip -OutFile protoc-3.19.4-win64.zip
+          Expand-Archive protoc-3.19.4-win64.zip -DestinationPath protoc-3.19.4-win64
+          $GOPATH=go env GOPATH
+          Copy-Item -Path protoc-3.19.4-win64\bin\protoc.exe -Destination $GOPATH\bin
+          Copy-Item -Path protoc-3.19.4-win64\include\* -Destination cmd\hz\testdata\include\google -Recurse
+          protoc --version
+
+      - name: Hz Test
+        run: |
+          cd cmd/hz
+          sh test_hz_windows.sh
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
deleted file mode 100644
index 0079d89..0000000
--- a/.github/workflows/tests.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-name: Tests
-
-on: [push, pull_request]
-
-jobs:
-  unit-test-x64:
-    strategy:
-      matrix:
-        version: ["1.19", "1.20", oldstable, stable]
-    runs-on: [self-hosted, Linux, X64]
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up Go
-        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 ./...
-
-  unit-test-arm64:
-    strategy:
-      matrix:
-        version: ["1.19", "1.20", oldstable, stable]
-    runs-on: [self-hosted, ARM64]
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up Go
-        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 ./...
-
-  ut-windows:
-    runs-on: [self-hosted, Windows]
-    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: Unit Test
-        run: go test -race ./...
-
-  code-cov:
-    runs-on: [self-hosted, Linux, 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: Unit Test
-        run: go test -covermode=atomic -coverprofile=coverage.txt ./...
-
-      - uses: codecov/codecov-action@v5
-        with:
-          fail_ci_if_error: true
-
-  hz-test-unix:
-    runs-on: [ self-hosted, Linux, 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: Setup Environment
-        run: |
-          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
-          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
-
-      - name: Get changed files
-        id: changed-files
-        uses: tj-actions/changed-files@v41
-
-      - name: Hz Test
-        if: contains(steps.changed-files.outputs.all_changed_files, 'cmd/hz')
-        run: |
-          cd cmd/hz
-          sh test_hz_unix.sh
-
-
-  hz-test-windows:
-    runs-on: windows-latest
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up Go
-        uses: actions/setup-go@v5
-        with:
-          go-version: stable
-
-      - name: Get changed files
-        id: changed-files
-        uses: tj-actions/changed-files@v41
-
-      - name: Install Protobuf
-        shell: pwsh
-        run: |
-          Invoke-WebRequest https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip -OutFile protoc-3.19.4-win64.zip
-          Expand-Archive protoc-3.19.4-win64.zip -DestinationPath protoc-3.19.4-win64
-          $GOPATH=go env GOPATH
-          Copy-Item -Path protoc-3.19.4-win64\bin\protoc.exe -Destination $GOPATH\bin
-          Copy-Item -Path protoc-3.19.4-win64\include\* -Destination cmd\hz\testdata\include\google -Recurse
-          protoc --version
-
-      - name: Hz Test
-        if: contains(steps.changed-files.outputs.all_changed_files, 'cmd/hz')
-        run: |
-          cd cmd/hz
-          sh test_hz_windows.sh
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
new file mode 100644
index 0000000..601ba0f
--- /dev/null
+++ b/.github/workflows/unit-tests.yml
@@ -0,0 +1,66 @@
+name: Unit Tests
+
+on: [push, pull_request]
+
+jobs:
+  unit-test-x64:
+    strategy:
+      matrix:
+        version: ["1.19", "1.20", oldstable, stable]
+    runs-on: [self-hosted, Linux, X64]
+    steps:
+      - uses: actions/checkout@v4
+      - name: Set up Go
+        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 ./...
+
+  unit-test-arm64:
+    strategy:
+      matrix:
+        version: ["1.19", "1.20", oldstable, stable]
+    runs-on: [self-hosted, ARM64]
+    steps:
+      - uses: actions/checkout@v4
+      - name: Set up Go
+        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 ./...
+
+  ut-windows:
+    runs-on: [self-hosted, Windows]
+    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: Unit Test
+        run: go test -race ./...
+
+  code-cov:
+    runs-on: [self-hosted, Linux, 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: Unit Test
+        run: go test -covermode=atomic -coverprofile=coverage.txt ./...
+
+      - uses: codecov/codecov-action@v5
+        with:
+          fail_ci_if_error: true
diff --git a/pkg/common/bytebufferpool/bytebuffer_test.go b/pkg/common/bytebufferpool/bytebuffer_test.go
index 0cd4bf5..7727354 100644
--- a/pkg/common/bytebufferpool/bytebuffer_test.go
+++ b/pkg/common/bytebufferpool/bytebuffer_test.go
@@ -47,6 +47,8 @@ import (
 	"io"
 	"testing"
 	"time"
+
+	"github.com/cloudwego/hertz/pkg/common/test/assert"
 )
 
 func TestByteBufferReadFrom(t *testing.T) {
@@ -73,6 +75,7 @@ func TestByteBufferReadFrom(t *testing.T) {
 		if bbLen != expectedLen {
 			t.Fatalf("unexpected byteBuffer length: %d. Expecting %d", bbLen, expectedLen)
 		}
+		assert.True(t, bb.Cap() >= int(expectedLen))
 		for j := 0; j < i; j++ {
 			start := prefixLen + int64(j)*expectedN
 			b := bb.B[start : start+expectedN]
@@ -104,6 +107,7 @@ func TestByteBufferWriteTo(t *testing.T) {
 			t.Fatalf("unexpected string written %q. Expecting %q", s, expectedS)
 		}
 		w.Reset()
+		assert.True(t, bb.Cap() >= len(expectedS))
 	}
 }
 
diff --git a/pkg/protocol/request_test.go b/pkg/protocol/request_test.go
index fda96cd..48ef4be 100644
--- a/pkg/protocol/request_test.go
+++ b/pkg/protocol/request_test.go
@@ -703,6 +703,26 @@ func TestRequestSetMaxKeepBodySize(t *testing.T) {
 	assert.DeepEqual(t, 1024, r.maxKeepBodySize)
 }
 
+func TestRequestBodyReuse(t *testing.T) {
+	req := Request{}
+	req.maxKeepBodySize = 1024
+
+	buf := req.BodyBuffer()
+	// set a big body
+	buf.Write(make([]byte, req.maxKeepBodySize+1))
+	req.ResetBody()
+	assert.Nil(t, req.body)
+	// NOTICE: bytebufferpool may not get a big enough buffer,
+	// so we just mock a new one here
+	req.body = &bytebufferpool.ByteBuffer{
+		B: make([]byte, 0, req.maxKeepBodySize+1),
+	}
+	// set a small body
+	buf.Write(make([]byte, 1))
+	req.ResetBody()
+	assert.Nil(t, req.body)
+}
+
 func TestRequestGetBodyAfterGetBodyStream(t *testing.T) {
 	req := AcquireRequest()
 	req.SetBodyString("abc")
diff --git a/pkg/protocol/response_test.go b/pkg/protocol/response_test.go
index 6495130..5ecf5a0 100644
--- a/pkg/protocol/response_test.go
+++ b/pkg/protocol/response_test.go
@@ -172,6 +172,26 @@ func TestResponseResetBody(t *testing.T) {
 	assert.Nil(t, resp.body)
 }
 
+func TestResponseBodyReuse(t *testing.T) {
+	resp := Response{}
+	resp.maxKeepBodySize = 1024
+
+	buf := resp.BodyBuffer()
+	// set a big body
+	buf.Write(make([]byte, resp.maxKeepBodySize+1))
+	resp.ResetBody()
+	assert.Nil(t, resp.body)
+	// NOTICE: bytebufferpool may not get a big enough buffer,
+	// so we just mock a new one here
+	resp.body = &bytebufferpool.ByteBuffer{
+		B: make([]byte, 0, resp.maxKeepBodySize+1),
+	}
+	// set a small body
+	buf.Write(make([]byte, 1))
+	resp.ResetBody()
+	assert.Nil(t, resp.body)
+}
+
 func testResponseCopyTo(t *testing.T, src *Response) {
 	var dst Response
 	src.CopyTo(&dst)