Merge branch 'master' into feature/ctx-support-chain

This commit is contained in:
Bo-Yi Wu 2025-11-30 15:40:06 +08:00 committed by GitHub
commit 39122a594e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 90 additions and 16 deletions

View File

@ -70,9 +70,10 @@ func TestRunEmpty(t *testing.T) {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.NoError(t, router.Run())
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
// Wait for server to be ready with exponential backoff
err := waitForServerReady("http://localhost:8080/example", 10)
require.NoError(t, err, "server should start successfully")
require.Error(t, router.Run(":8080"))
testRequest(t, "http://localhost:8080/example")
@ -213,9 +214,10 @@ func TestRunEmptyWithEnv(t *testing.T) {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.NoError(t, router.Run())
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
// Wait for server to be ready with exponential backoff
err := waitForServerReady("http://localhost:3123/example", 10)
require.NoError(t, err, "server should start successfully")
require.Error(t, router.Run(":3123"))
testRequest(t, "http://localhost:3123/example")
@ -234,9 +236,10 @@ func TestRunWithPort(t *testing.T) {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.NoError(t, router.Run(":5150"))
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
// Wait for server to be ready with exponential backoff
err := waitForServerReady("http://localhost:5150/example", 10)
require.NoError(t, err, "server should start successfully")
require.Error(t, router.Run(":5150"))
testRequest(t, "http://localhost:5150/example")

View File

@ -545,6 +545,29 @@ func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
}
func TestRebuild404Handlers(t *testing.T) {
var middleware0 HandlerFunc = func(c *Context) {}
var middleware1 HandlerFunc = func(c *Context) {}
router := New()
// Initially, allNoRoute should be nil
assert.Nil(t, router.allNoRoute)
// Set NoRoute handlers
router.NoRoute(middleware0)
assert.Len(t, router.allNoRoute, 1)
assert.Len(t, router.noRoute, 1)
compareFunc(t, router.allNoRoute[0], middleware0)
// Add Use middleware should trigger rebuild404Handlers
router.Use(middleware1)
assert.Len(t, router.allNoRoute, 2)
assert.Len(t, router.Handlers, 1)
assert.Len(t, router.noRoute, 1)
// Global middleware should come first
compareFunc(t, router.allNoRoute[0], middleware1)
compareFunc(t, router.allNoRoute[1], middleware0)
}
func TestNoMethodWithGlobalHandlers(t *testing.T) {

4
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/mattn/go-isatty v0.0.20
github.com/modern-go/reflect2 v1.0.2
github.com/pelletier/go-toml/v2 v2.2.4
github.com/quic-go/quic-go v0.56.0
github.com/quic-go/quic-go v0.57.1
github.com/stretchr/testify v1.11.1
github.com/ugorji/go/codec v1.3.1
golang.org/x/net v0.47.0
@ -32,7 +32,7 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.45.0 // indirect

8
go.sum
View File

@ -49,10 +49,10 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY=
github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=
github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View File

@ -41,6 +41,15 @@ func TestBytesToString(t *testing.T) {
}
}
func TestBytesToStringEmpty(t *testing.T) {
if got := BytesToString([]byte{}); got != "" {
t.Fatalf("BytesToString([]byte{}) = %q; want empty string", got)
}
if got := BytesToString(nil); got != "" {
t.Fatalf("BytesToString(nil) = %q; want empty string", got)
}
}
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
@ -78,6 +87,16 @@ func TestStringToBytes(t *testing.T) {
}
}
func TestStringToBytesEmpty(t *testing.T) {
b := StringToBytes("")
if len(b) != 0 {
t.Fatalf(`StringToBytes("") length = %d; want 0`, len(b))
}
if !bytes.Equal(b, []byte("")) {
t.Fatalf(`StringToBytes("") = %v; want []byte("")`, b)
}
}
// go test -v -run=none -bench=^BenchmarkBytesConv -benchmem=true
func BenchmarkBytesConvBytesToStrRaw(b *testing.B) {

View File

@ -4,7 +4,11 @@
package gin
import "net/http"
import (
"fmt"
"net/http"
"time"
)
// CreateTestContext returns a fresh Engine and a Context associated with it.
// This is useful for tests that need to set up a new Gin engine instance
@ -29,3 +33,28 @@ func CreateTestContextOnly(w http.ResponseWriter, r *Engine) (c *Context) {
c.writermem.reset(w)
return
}
// waitForServerReady waits for a server to be ready by making HTTP requests
// with exponential backoff. This is more reliable than time.Sleep() for testing.
func waitForServerReady(url string, maxAttempts int) error {
client := &http.Client{
Timeout: 100 * time.Millisecond,
}
for i := 0; i < maxAttempts; i++ {
resp, err := client.Get(url)
if err == nil {
resp.Body.Close()
return nil
}
// Exponential backoff: 10ms, 20ms, 40ms, 80ms, 160ms...
backoff := time.Duration(10*(1<<uint(i))) * time.Millisecond
if backoff > 500*time.Millisecond {
backoff = 500 * time.Millisecond
}
time.Sleep(backoff)
}
return fmt.Errorf("server at %s did not become ready after %d attempts", url, maxAttempts)
}