Skip to content
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

Use the gin.CreateTestContext in test, could not get the param in the route. #2778

Closed
Hanaasagi opened this issue Jul 5, 2021 · 6 comments
Closed

Comments

@Hanaasagi
Copy link

  • With issues:
    • Use the search tool before opening a new issue.
    • Please provide source code and commit sha if you found a bug.
    • Review existing issues and provide feedback or react to them.

Description

#2755 only fixes the slice bounds out of range panic. Route params are not be handled correctly in test context. I can explain what happened.

When call CreateTestContext, it will call New function to create a Engine. The maxParams will be the default value 0.

gin/test_helpers.go

Lines 9 to 16 in 9c27053

// CreateTestContext returns a fresh engine and context for testing purposes
func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
r = New()
c = r.allocateContext()
c.reset()
c.writermem.reset(w)
return
}

Then allocateContext init the Params. The cap and len are both 0. params is the reference of Params.

gin/gin.go

Lines 202 to 205 in 9c27053

func (engine *Engine) allocateContext() *Context {
v := make(Params, 0, engine.maxParams)
return &Context{engine: engine, params: &v}
}

Even if we add a route, it only incrs the maxParams value, it has not effect on the Context we created by CreateTestContext before. The condition will always be false.

gin/tree.go

Lines 462 to 479 in 9c27053

if params != nil && cap(*params) > 0 {
if value.params == nil {
value.params = params
}
// Expand slice within preallocated capacity
i := len(*value.params)
*value.params = (*value.params)[:i+1]
val := path[:end]
if unescape {
if v, err := url.QueryUnescape(val); err == nil {
val = v
}
}
(*value.params)[i] = Param{
Key: n.path[1:],
Value: val,
}
}

How to reproduce

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/gin-gonic/gin"
)

func main() {
	w := httptest.NewRecorder()
	ctx, engine := gin.CreateTestContext(w)
	engine.GET("/hello/:name", func(ctx *gin.Context) {
		fmt.Printf("Param name is %s\n", ctx.Param("name"))
		ctx.String(http.StatusOK, "Hello %s", ctx.Param("name"))
	})
	var err error
	ctx.Request, err = http.NewRequest(http.MethodGet, "/hello/world", nil)
	if err != nil {
		panic(err)
	}
	engine.HandleContext(ctx)
}

Expectations

Get following output after running the code.

[GIN-debug] GET    /hello/:name              --> main.main.func1 (1 handlers)
Param name is world

Actual result

[GIN-debug] GET    /hello/:name              --> main.main.func1 (1 handlers)
Param name is 

ctx.Param("name") returns a empty string.

Environment

  • go version: go version go1.16 darwin/amd64
  • gin version (or commit ref): v1.7.2-0.20210704023713-9c27053243cb
  • operating system: macOs Big Sur 11.4, Darwin Kernel Version 20.5.0
@Hanaasagi
Copy link
Author

One way to fix this problem is check the cap of params everytime when we use.

图片

@Hanaasagi
Copy link
Author

Hello, Any thoughts on this?

@RoCry
Copy link
Contributor

RoCry commented Aug 3, 2021

Hello, Any thoughts on this?

@Hanaasagi We met the same issue and fixed it #2803, please feel free to leave suggestions.

@alochym01
Copy link

@Hanaasagi i have same issue, is there any work around
#2833

@jlaneve
Copy link

jlaneve commented Jul 19, 2022

Here's a workaround for now:

gin.SetMode(gin.TestMode)

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

c.Params = []gin.Param{gin.Param{Key: "k", Value: "v"}}

foo(c)

if w.Code != 200 {
    b, _ := ioutil.ReadAll(w.Body)
    t.Error(w.Code, string(b))
}

@appleboy
Copy link
Member

fixed in #2803 and released in v1.8.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants