Skip to content

test: add unit tests for pkg/common/utils #1310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions pkg/common/utils/chunk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,128 @@ func TestChunkReadFalseCRLF(t *testing.T) {
err := SkipCRLF(zr)
assert.DeepEqual(t, errBrokenChunk, err)
}

// TestParseChunkSize tests the chunk size parsing functionality with various input formats
func TestParseChunkSize(t *testing.T) {
testCases := []struct {
name string
input string
expectSize int
expectError bool
}{
{
name: "valid hex with CRLF",
input: "a\r\n",
expectSize: 10,
expectError: false,
},
{
name: "valid hex with spaces and CRLF",
input: "10 \r\n",
expectSize: 16,
expectError: false,
},
{
name: "empty input",
input: "",
expectSize: -1,
expectError: true,
},
{
name: "missing CR",
input: "a\n",
expectSize: -1,
expectError: true,
},
{
name: "missing LF",
input: "a\r",
expectSize: -1,
expectError: true,
},
{
name: "invalid hex",
input: "xyz\r\n",
expectSize: -1,
expectError: true,
},
{
name: "invalid char after size",
input: "a#\r\n",
expectSize: -1,
expectError: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := mock.NewZeroCopyReader(tc.input)
size, err := ParseChunkSize(r)

if tc.expectError {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
}
assert.DeepEqual(t, tc.expectSize, size)
})
}
}

// TestSkipCRLF tests the CRLF skipping functionality with different input sequences
func TestSkipCRLF(t *testing.T) {
testCases := []struct {
name string
input string
expectError bool
}{
{
name: "valid CRLF",
input: "\r\n",
expectError: false,
},
{
name: "only CR",
input: "\r",
expectError: true,
},
{
name: "only LF",
input: "\n",
expectError: true,
},
{
name: "empty input",
input: "",
expectError: true,
},
{
name: "invalid sequence",
input: "ab",
expectError: true,
},
{
name: "CRLF with extra data",
input: "\r\ndata",
expectError: false,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := mock.NewZeroCopyReader(tc.input)
err := SkipCRLF(r)

if tc.expectError {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
if len(tc.input) > 2 {
// Verify that CRLF was correctly skipped by checking remaining data
remaining, _ := r.Peek(len(tc.input) - 2)
assert.DeepEqual(t, tc.input[2:], string(remaining))
}
}
})
}
}
85 changes: 85 additions & 0 deletions pkg/common/utils/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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"
"testing"

"github.com/cloudwego/hertz/pkg/common/test/assert"
)

// TestGetBoolFromEnv tests the functionality of getting boolean values from environment variables
func TestGetBoolFromEnv(t *testing.T) {
// Test case: environment variable does not exist
nonExistKey := "HERTZ_TEST_NON_EXIST_KEY"
os.Unsetenv(nonExistKey) // Ensure the environment variable doesn't exist
val, err := GetBoolFromEnv(nonExistKey)
assert.NotNil(t, err)
assert.DeepEqual(t, false, val)
assert.DeepEqual(t, "env not exist", err.Error())

// Test case: environment variable value is "true"
trueKey := "HERTZ_TEST_TRUE_KEY"
os.Setenv(trueKey, "true")
val, err = GetBoolFromEnv(trueKey)
assert.Nil(t, err)
assert.DeepEqual(t, true, val)

// Test case: environment variable value is "false"
falseKey := "HERTZ_TEST_FALSE_KEY"
os.Setenv(falseKey, "false")
val, err = GetBoolFromEnv(falseKey)
assert.Nil(t, err)
assert.DeepEqual(t, false, val)

// Test case: environment variable value is "1" (should parse as true)
oneKey := "HERTZ_TEST_ONE_KEY"
os.Setenv(oneKey, "1")
val, err = GetBoolFromEnv(oneKey)
assert.Nil(t, err)
assert.DeepEqual(t, true, val)

// Test case: environment variable value is "0" (should parse as false)
zeroKey := "HERTZ_TEST_ZERO_KEY"
os.Setenv(zeroKey, "0")
val, err = GetBoolFromEnv(zeroKey)
assert.Nil(t, err)
assert.DeepEqual(t, false, val)

// Test case: environment variable value contains whitespace
spaceKey := "HERTZ_TEST_SPACE_KEY"
os.Setenv(spaceKey, " true ")
val, err = GetBoolFromEnv(spaceKey)
assert.Nil(t, err)
assert.DeepEqual(t, true, val)

// Test case: environment variable value is an invalid boolean
invalidKey := "HERTZ_TEST_INVALID_KEY"
os.Setenv(invalidKey, "not-a-bool")
val, err = GetBoolFromEnv(invalidKey)
assert.NotNil(t, err)
assert.DeepEqual(t, false, val)

// Cleanup test environment variables
os.Unsetenv(trueKey)
os.Unsetenv(falseKey)
os.Unsetenv(oneKey)
os.Unsetenv(zeroKey)
os.Unsetenv(spaceKey)
os.Unsetenv(invalidKey)
}
49 changes: 49 additions & 0 deletions pkg/common/utils/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,52 @@
assert.DeepEqual(t, got, expectedIP)
}
}

// TestGetLocalIp tests the getLocalIp function with different network interface scenarios
func TestGetLocalIp(t *testing.T) {
// Since getLocalIp is not exported, we can test it indirectly through LocalIP
// The actual value will depend on the test environment, but we can at least
// verify that it returns a non-empty value that is not the unknown marker
ip := LocalIP()
assert.NotEqual(t, "", ip)

// We can also verify that the returned IP is either a valid IP or the unknown marker
if ip != UNKNOWN_IP_ADDR {
parsedIP := net.ParseIP(ip)

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.19)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.20)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (stable)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.19)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (stable)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / ut-windows

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / code-cov

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.20)

undefined: net

Check failure on line 66 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (oldstable)

undefined: net
assert.NotNil(t, parsedIP, "LocalIP should return a valid IP address")

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (stable)

too many arguments in call to assert.NotNil

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (stable)

too many arguments in call to assert.NotNil

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / ut-windows

too many arguments in call to assert.NotNil

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / code-cov

too many arguments in call to assert.NotNil

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / lint

too many arguments in call to assert.NotNil

Check failure on line 67 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (oldstable)

too many arguments in call to assert.NotNil
}
}

// TestTLSRecordHeaderLooksLikeHTTPWithEdgeCases tests additional edge cases for TLS header detection
func TestTLSRecordHeaderLooksLikeHTTPWithEdgeCases(t *testing.T) {
// Test with partial HTTP method matches
partialMatches := [][5]byte{
{'G', 'E', 'T', 'x', '/'}, // Almost "GET /"
{'H', 'E', 'A', 'x', ' '}, // Almost "HEAD "
{'P', 'O', 'S', 'x', ' '}, // Almost "POST "
{'P', 'U', 'T', 'x', '/'}, // Almost "PUT /"
{'O', 'P', 'T', 'x', 'O'}, // Almost "OPTIO"
}

for _, header := range partialMatches {
assert.False(t, TLSRecordHeaderLooksLikeHTTP(header),
"Partial HTTP method match should not be detected as HTTP")

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.19)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.20)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (stable)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.19)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (stable)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / ut-windows

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / code-cov

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / lint

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.20)

too many arguments in call to assert.False

Check failure on line 84 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (oldstable)

too many arguments in call to assert.False
}

// Test with empty header
emptyHeader := [5]byte{}
assert.False(t, TLSRecordHeaderLooksLikeHTTP(emptyHeader),
"Empty header should not be detected as HTTP")

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.19)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.20)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (stable)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.19)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (stable)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / ut-windows

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / code-cov

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / lint

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.20)

too many arguments in call to assert.False

Check failure on line 90 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (oldstable)

too many arguments in call to assert.False

// Test with other common HTTP methods that are not in the list
otherMethods := [][5]byte{
{'D', 'E', 'L', 'E', 'T'}, // DELETE
{'P', 'A', 'T', 'C', 'H'}, // PATCH
{'T', 'R', 'A', 'C', 'E'}, // TRACE
}

for _, header := range otherMethods {
assert.False(t, TLSRecordHeaderLooksLikeHTTP(header),
"Other HTTP methods should not be detected as HTTP by this function")

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.19)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (1.20)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (stable)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.19)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (stable)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / ut-windows

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / code-cov

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / lint

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-arm64 (1.20)

too many arguments in call to assert.False

Check failure on line 101 in pkg/common/utils/network_test.go

View workflow job for this annotation

GitHub Actions / unit-test-x64 (oldstable)

too many arguments in call to assert.False
}
}
42 changes: 42 additions & 0 deletions pkg/common/utils/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,45 @@ func TestPathAddMissingPort(t *testing.T) {
assert.DeepEqual(t, ip+customizedPort, AddMissingPort(ip+customizedPort, false))
}
}

// TestBufApp tests different branch logic of bufApp function
// Handles buffer creation and management when modifying strings
func TestBufApp(t *testing.T) {
var buf []byte
s := "test"
w := 1

// Test case when buffer is empty and next char is same as original string
bufApp(&buf, s, w, 'e')
assert.DeepEqual(t, 0, len(buf)) // Buffer should remain empty as no modification needed

// Test case when buffer is empty and next char differs from original string
bufApp(&buf, s, w, 'x')
assert.DeepEqual(t, len(s), len(buf)) // New buffer should be created
assert.DeepEqual(t, byte('x'), buf[w]) // New char should be written to buffer
assert.DeepEqual(t, byte('t'), buf[0]) // Original string prefix should be copied

// Test case when buffer already exists
bufApp(&buf, s, 2, 'y')
assert.DeepEqual(t, byte('y'), buf[2]) // New char should be written to buffer

// Test case with index w = 0 (first character)
var buf2 []byte
bufApp(&buf2, s, 0, 'X')
assert.DeepEqual(t, len(s), len(buf2))
assert.DeepEqual(t, byte('X'), buf2[0])

// Test case with large string (exceeding stack buffer size)
var buf3 []byte
largeString := string(make([]byte, 256)) // Larger than stackBufSize (128)
bufApp(&buf3, largeString, 100, 'Z')
assert.DeepEqual(t, len(largeString), len(buf3))
assert.DeepEqual(t, byte('Z'), buf3[100])

// Test edge case: when w is at the end of string
var buf4 []byte
lastIndex := len(s) - 1
bufApp(&buf4, s, lastIndex, 'L')
assert.DeepEqual(t, len(s), len(buf4))
assert.DeepEqual(t, byte('L'), buf4[lastIndex])
}
Loading