valyala / fasthttp

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
MIT License
21.91k stars 1.76k forks source link

What is a correct way to create a proper fasthttp.RequestCtx in the unit tests? #1740

Closed renta closed 8 months ago

renta commented 8 months ago

Hello. I write my own function for checking origin for fasthttp/websocket:

func checkOrigin(ctx *fasthttp.RequestCtx) bool {
    origin := ctx.Request.Header.Peek("Origin")
    if len(origin) == 0 {
        return true
    }
    u, err := url.Parse(strconv.B2S(origin))
    if err != nil {
        return false
    }
    if equalASCIIFold(u.Host, strconv.B2S(ctx.Host())) || equalASCIIFold(
        getBaseHost(u.Host), getBaseHost(strconv.B2S(ctx.Host())),
    ) {
        return true
    }
    return false
}

Now I want to provide a set of unit tests to verify its behaviour. Like these:

func Test_checkOrigin(t *testing.T) {
  tests := []struct {
    name   string
    host   string
    uri    string
    origin string
    want   bool
  }{
    {
      "same host and origin",
      "some.example.com",
      "/api/v1/something",
      "https://some.example.com",
      true,
    },
    // more cases skip
  }
  for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
      var h fasthttp.RequestHeader
      h.SetHost(tt.host)
      h.SetRequestURI(tt.uri)
      if tt.origin != "" {
        h.Set("Origin", tt.origin)
      }
      ctx := &fasthttp.RequestCtx{
        Request: fasthttp.Request{Header: h}, // <- HERE IS THE PROBLEM
      }
      if got := checkOrigin(ctx); got != tt.want {
        t.Errorf("checkOrigin() = %v, want %v", got, tt.want)
      }
    })
  }
}

These tests are green. But in golangci-lint (go vet) I get this issue: copylocks: literal copies lock value from h: github.com/valyala/fasthttp.RequestHeader contains github.com/valyala/fasthttp.noCopy (govet) Request: fasthttp.Request{Header: h} Ok, I try to rewrite body of the test like this:

t.Run(tt.name, func(t *testing.T) {
  var r fasthttp.Request
  if tt.origin != "" {
    r.Header.Set("Origin", tt.origin)
  }
  r.SetHost(tt.host)
  r.SetRequestURI(tt.uri)
  ctx := &fasthttp.RequestCtx{}
  ctx.Init(&r, nil, nil)
  if got := checkOrigin(ctx); got != tt.want {
    t.Errorf("checkOrigin() = %v, want %v", got, tt.want)
  }
})

But now my tests are red. Because of empty ctx.URI().Host() function and req.parsedURI is true. So my question is - what is a correct way of manual creation of RequestCtx object in the unit tests?

renta commented 8 months ago

Here is a right way:

ctx := new(fasthttp.RequestCtx)
ctx.Request.Header.SetHost(tt.host)
ctx.Request.Header.SetRequestURI(tt.uri)
if tt.origin != "" {
  ctx.Request.Header.Set("Origin", tt.origin)
}