fiber/middleware/session/session_test.go

505 lines
12 KiB
Go

package session
import (
"testing"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/internal/storage/memory"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
)
// go test -run Test_Session
func Test_Session(t *testing.T) {
t.Parallel()
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// set session
ctx.Request().Header.SetCookie(store.sessionName, "123")
// get session
sess, err := store.Get(ctx)
require.NoError(t, err)
require.True(t, sess.Fresh())
// get keys
keys := sess.Keys()
require.Equal(t, []string{}, keys)
// get value
name := sess.Get("name")
require.Nil(t, name)
// set value
sess.Set("name", "john")
// get value
name = sess.Get("name")
require.Equal(t, "john", name)
keys = sess.Keys()
require.Equal(t, []string{"name"}, keys)
// delete key
sess.Delete("name")
// get value
name = sess.Get("name")
require.Nil(t, name)
// get keys
keys = sess.Keys()
require.Equal(t, []string{}, keys)
// get id
id := sess.ID()
require.Equal(t, "123", id)
// save the old session first
err = sess.Save()
require.NoError(t, err)
// requesting entirely new context to prevent falsy tests
ctx = app.NewCtx(&fasthttp.RequestCtx{})
sess, err = store.Get(ctx)
require.NoError(t, err)
require.True(t, sess.Fresh())
// this id should be randomly generated as session key was deleted
require.Equal(t, 36, len(sess.ID()))
// when we use the original session for the second time
// the session be should be same if the session is not expired
ctx = app.NewCtx(&fasthttp.RequestCtx{})
// request the server with the old session
ctx.Request().Header.SetCookie(store.sessionName, id)
sess, err = store.Get(ctx)
require.NoError(t, err)
require.False(t, sess.Fresh())
require.Equal(t, sess.id, id)
}
// go test -run Test_Session_Types
func Test_Session_Types(t *testing.T) {
t.Parallel()
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// set cookie
ctx.Request().Header.SetCookie(store.sessionName, "123")
// get session
sess, err := store.Get(ctx)
require.NoError(t, err)
require.True(t, sess.Fresh())
// the session string is no longer be 123
newSessionIDString := sess.ID()
ctx.Request().Header.SetCookie(store.sessionName, newSessionIDString)
type User struct {
Name string
}
store.RegisterType(User{})
vuser := User{
Name: "John",
}
// set value
var vbool bool = true
var vstring string = "str"
var vint int = 13
var vint8 int8 = 13
var vint16 int16 = 13
var vint32 int32 = 13
var vint64 int64 = 13
var vuint uint = 13
var vuint8 uint8 = 13
var vuint16 uint16 = 13
var vuint32 uint32 = 13
var vuint64 uint64 = 13
var vuintptr uintptr = 13
var vbyte byte = 'k'
var vrune rune = 'k'
var vfloat32 float32 = 13
var vfloat64 float64 = 13
var vcomplex64 complex64 = 13
var vcomplex128 complex128 = 13
sess.Set("vuser", vuser)
sess.Set("vbool", vbool)
sess.Set("vstring", vstring)
sess.Set("vint", vint)
sess.Set("vint8", vint8)
sess.Set("vint16", vint16)
sess.Set("vint32", vint32)
sess.Set("vint64", vint64)
sess.Set("vuint", vuint)
sess.Set("vuint8", vuint8)
sess.Set("vuint16", vuint16)
sess.Set("vuint32", vuint32)
sess.Set("vuint32", vuint32)
sess.Set("vuint64", vuint64)
sess.Set("vuintptr", vuintptr)
sess.Set("vbyte", vbyte)
sess.Set("vrune", vrune)
sess.Set("vfloat32", vfloat32)
sess.Set("vfloat64", vfloat64)
sess.Set("vcomplex64", vcomplex64)
sess.Set("vcomplex128", vcomplex128)
// save session
err = sess.Save()
require.NoError(t, err)
// get session
sess, err = store.Get(ctx)
require.NoError(t, err)
require.False(t, sess.Fresh())
// get value
require.Equal(t, vuser, sess.Get("vuser").(User))
require.Equal(t, vbool, sess.Get("vbool").(bool))
require.Equal(t, vstring, sess.Get("vstring").(string))
require.Equal(t, vint, sess.Get("vint").(int))
require.Equal(t, vint8, sess.Get("vint8").(int8))
require.Equal(t, vint16, sess.Get("vint16").(int16))
require.Equal(t, vint32, sess.Get("vint32").(int32))
require.Equal(t, vint64, sess.Get("vint64").(int64))
require.Equal(t, vuint, sess.Get("vuint").(uint))
require.Equal(t, vuint8, sess.Get("vuint8").(uint8))
require.Equal(t, vuint16, sess.Get("vuint16").(uint16))
require.Equal(t, vuint32, sess.Get("vuint32").(uint32))
require.Equal(t, vuint64, sess.Get("vuint64").(uint64))
require.Equal(t, vuintptr, sess.Get("vuintptr").(uintptr))
require.Equal(t, vbyte, sess.Get("vbyte").(byte))
require.Equal(t, vrune, sess.Get("vrune").(rune))
require.Equal(t, vfloat32, sess.Get("vfloat32").(float32))
require.Equal(t, vfloat64, sess.Get("vfloat64").(float64))
require.Equal(t, vcomplex64, sess.Get("vcomplex64").(complex64))
require.Equal(t, vcomplex128, sess.Get("vcomplex128").(complex128))
}
// go test -run Test_Session_Store_Reset
func Test_Session_Store_Reset(t *testing.T) {
t.Parallel()
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
// make sure its new
require.True(t, sess.Fresh())
// set value & save
sess.Set("hello", "world")
ctx.Request().Header.SetCookie(store.sessionName, sess.ID())
sess.Save()
// reset store
store.Reset()
// make sure the session is recreated
sess, _ = store.Get(ctx)
require.True(t, sess.Fresh())
require.Nil(t, sess.Get("hello"))
}
// go test -run Test_Session_Save
func Test_Session_Save(t *testing.T) {
t.Parallel()
t.Run("save to cookie", func(t *testing.T) {
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
// set value
sess.Set("name", "john")
// save session
err := sess.Save()
require.NoError(t, err)
})
t.Run("save to header", func(t *testing.T) {
// session store
store := New(Config{
KeyLookup: "header:session_id",
})
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
// set value
sess.Set("name", "john")
// save session
err := sess.Save()
require.NoError(t, err)
require.Equal(t, store.getSessionID(ctx), string(ctx.Response().Header.Peek(store.sessionName)))
require.Equal(t, store.getSessionID(ctx), string(ctx.Request().Header.Peek(store.sessionName)))
})
}
func Test_Session_Save_Expiration(t *testing.T) {
t.Parallel()
t.Run("save to cookie", func(t *testing.T) {
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
// set value
sess.Set("name", "john")
// expire this session in 5 seconds
sess.SetExpiry(time.Second * 5)
// save session
err := sess.Save()
require.NoError(t, err)
// here you need to get the old session yet
sess, _ = store.Get(ctx)
require.Equal(t, "john", sess.Get("name"))
// just to make sure the session has been expired
time.Sleep(time.Second * 5)
// here you should get a new session
sess, _ = store.Get(ctx)
require.Nil(t, sess.Get("name"))
})
}
// go test -run Test_Session_Reset
func Test_Session_Reset(t *testing.T) {
t.Parallel()
t.Run("reset from cookie", func(t *testing.T) {
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
sess.Set("name", "fenny")
sess.Destroy()
name := sess.Get("name")
require.Nil(t, name)
})
t.Run("reset from header", func(t *testing.T) {
// session store
store := New(Config{
KeyLookup: "header:session_id",
})
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
// set value & save
sess.Set("name", "fenny")
_ = sess.Save()
sess, _ = store.Get(ctx)
err := sess.Destroy()
require.NoError(t, err)
require.Equal(t, "", string(ctx.Response().Header.Peek(store.sessionName)))
require.Equal(t, "", string(ctx.Request().Header.Peek(store.sessionName)))
})
}
// go test -run Test_Session_Custom_Config
func Test_Session_Custom_Config(t *testing.T) {
t.Parallel()
store := New(Config{Expiration: time.Hour, KeyGenerator: func() string { return "very random" }})
require.Equal(t, time.Hour, store.Expiration)
require.Equal(t, "very random", store.KeyGenerator())
store = New(Config{Expiration: 0})
require.Equal(t, ConfigDefault.Expiration, store.Expiration)
}
// go test -run Test_Session_Cookie
func Test_Session_Cookie(t *testing.T) {
t.Parallel()
// session store
store := New()
// fiber instance
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
sess.Save()
// cookie should be set on Save ( even if empty data )
require.Equal(t, 84, len(ctx.Response().Header.PeekCookie(store.sessionName)))
}
// go test -run Test_Session_Cookie_In_Response
func Test_Session_Cookie_In_Response(t *testing.T) {
t.Parallel()
store := New()
app := fiber.New()
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// get session
sess, _ := store.Get(ctx)
sess.Set("id", "1")
require.True(t, sess.Fresh())
sess.Save()
sess, _ = store.Get(ctx)
sess.Set("name", "john")
require.True(t, sess.Fresh())
require.Equal(t, "1", sess.Get("id"))
require.Equal(t, "john", sess.Get("name"))
}
// go test -run Test_Session_Deletes_Single_Key
// Regression: https://github.com/gofiber/fiber/issues/1365
func Test_Session_Deletes_Single_Key(t *testing.T) {
t.Parallel()
store := New()
app := fiber.New()
ctx := app.NewCtx(&fasthttp.RequestCtx{})
sess, err := store.Get(ctx)
require.NoError(t, err)
ctx.Request().Header.SetCookie(store.sessionName, sess.ID())
sess.Set("id", "1")
require.Nil(t, sess.Save())
sess, err = store.Get(ctx)
require.NoError(t, err)
sess.Delete("id")
require.Nil(t, sess.Save())
sess, err = store.Get(ctx)
require.NoError(t, err)
require.False(t, sess.Fresh())
require.Nil(t, sess.Get("id"))
}
// go test -run Test_Session_Regenerate
// Regression: https://github.com/gofiber/fiber/issues/1395
func Test_Session_Regenerate(t *testing.T) {
// fiber instance
app := fiber.New()
t.Run("set fresh to be true when regenerating a session", func(t *testing.T) {
// session store
store := New()
// a random session uuid
originalSessionUUIDString := ""
// fiber context
ctx := app.NewCtx(&fasthttp.RequestCtx{})
// now the session is in the storage
freshSession, err := store.Get(ctx)
require.NoError(t, err)
originalSessionUUIDString = freshSession.ID()
err = freshSession.Save()
require.NoError(t, err)
// set cookie
ctx.Request().Header.SetCookie(store.sessionName, originalSessionUUIDString)
// as the session is in the storage, session.fresh should be false
acquiredSession, err := store.Get(ctx)
require.NoError(t, err)
require.False(t, acquiredSession.Fresh())
err = acquiredSession.Regenerate()
require.NoError(t, err)
if acquiredSession.ID() == originalSessionUUIDString {
t.Fatal("regenerate should generate another different id")
}
// acquiredSession.fresh should be true after regenerating
require.True(t, acquiredSession.Fresh())
})
}
// go test -v -run=^$ -bench=Benchmark_Session -benchmem -count=4
func Benchmark_Session(b *testing.B) {
app, store := fiber.New(), New()
c := app.NewCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
c.Request().Header.SetCookie(store.sessionName, "12356789")
b.Run("default", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
sess, _ := store.Get(c)
sess.Set("john", "doe")
_ = sess.Save()
}
})
b.Run("storage", func(b *testing.B) {
store = New(Config{
Storage: memory.New(),
})
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
sess, _ := store.Get(c)
sess.Set("john", "doe")
_ = sess.Save()
}
})
}