package session import ( "errors" "sync" "testing" "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/internal/storage/memory" "github.com/gofiber/fiber/v2/utils" "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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // Get a new session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, true, sess.Fresh()) token := sess.ID() err = sess.Save() utils.AssertEqual(t, nil, err) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) // set session ctx.Request().Header.SetCookie(store.sessionName, token) // get session sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, sess.Fresh()) // get keys keys := sess.Keys() utils.AssertEqual(t, []string{}, keys) // get value name := sess.Get("name") utils.AssertEqual(t, nil, name) // set value sess.Set("name", "john") // get value name = sess.Get("name") utils.AssertEqual(t, "john", name) keys = sess.Keys() utils.AssertEqual(t, []string{"name"}, keys) // delete key sess.Delete("name") // get value name = sess.Get("name") utils.AssertEqual(t, nil, name) // get keys keys = sess.Keys() utils.AssertEqual(t, []string{}, keys) // get id id := sess.ID() utils.AssertEqual(t, token, id) // save the old session first err = sess.Save() utils.AssertEqual(t, nil, err) app.ReleaseCtx(ctx) // requesting entirely new context to prevent falsy tests ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, true, sess.Fresh()) // this id should be randomly generated as session key was deleted utils.AssertEqual(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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // request the server with the old session ctx.Request().Header.SetCookie(store.sessionName, id) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, sess.Fresh()) utils.AssertEqual(t, sess.id, id) } // go test -run Test_Session_Types // //nolint:forcetypeassert // TODO: Do not force-type assert func Test_Session_Types(t *testing.T) { t.Parallel() // session store store := New() // fiber instance app := fiber.New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // set cookie ctx.Request().Header.SetCookie(store.sessionName, "123") // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, true, sess.Fresh()) // the session string is no longer be 123 newSessionIDString := sess.ID() type User struct { Name string } store.RegisterType(User{}) vuser := User{ Name: "John", } // set value var ( vbool = true vstring = "str" vint = 13 vint8 int8 = 13 vint16 int16 = 13 vint32 int32 = 13 vint64 int64 = 13 vuint uint = 13 vuint8 uint8 = 13 vuint16 uint16 = 13 vuint32 uint32 = 13 vuint64 uint64 = 13 vuintptr uintptr = 13 vbyte byte = 'k' vrune = 'k' vfloat32 float32 = 13 vfloat64 float64 = 13 vcomplex64 complex64 = 13 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() utils.AssertEqual(t, nil, err) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) ctx.Request().Header.SetCookie(store.sessionName, newSessionIDString) // get session sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, sess.Fresh()) // get value utils.AssertEqual(t, vuser, sess.Get("vuser").(User)) utils.AssertEqual(t, vbool, sess.Get("vbool").(bool)) utils.AssertEqual(t, vstring, sess.Get("vstring").(string)) utils.AssertEqual(t, vint, sess.Get("vint").(int)) utils.AssertEqual(t, vint8, sess.Get("vint8").(int8)) utils.AssertEqual(t, vint16, sess.Get("vint16").(int16)) utils.AssertEqual(t, vint32, sess.Get("vint32").(int32)) utils.AssertEqual(t, vint64, sess.Get("vint64").(int64)) utils.AssertEqual(t, vuint, sess.Get("vuint").(uint)) utils.AssertEqual(t, vuint8, sess.Get("vuint8").(uint8)) utils.AssertEqual(t, vuint16, sess.Get("vuint16").(uint16)) utils.AssertEqual(t, vuint32, sess.Get("vuint32").(uint32)) utils.AssertEqual(t, vuint64, sess.Get("vuint64").(uint64)) utils.AssertEqual(t, vuintptr, sess.Get("vuintptr").(uintptr)) utils.AssertEqual(t, vbyte, sess.Get("vbyte").(byte)) utils.AssertEqual(t, vrune, sess.Get("vrune").(rune)) utils.AssertEqual(t, vfloat32, sess.Get("vfloat32").(float32)) utils.AssertEqual(t, vfloat64, sess.Get("vfloat64").(float64)) utils.AssertEqual(t, vcomplex64, sess.Get("vcomplex64").(complex64)) utils.AssertEqual(t, vcomplex128, sess.Get("vcomplex128").(complex128)) app.ReleaseCtx(ctx) } // 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.AcquireCtx(&fasthttp.RequestCtx{}) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) // make sure its new utils.AssertEqual(t, true, sess.Fresh()) // set value & save sess.Set("hello", "world") ctx.Request().Header.SetCookie(store.sessionName, sess.ID()) utils.AssertEqual(t, nil, sess.Save()) // reset store utils.AssertEqual(t, nil, store.Reset()) id := sess.ID() app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) ctx.Request().Header.SetCookie(store.sessionName, id) // make sure the session is recreated sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, true, sess.Fresh()) utils.AssertEqual(t, nil, 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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) // set value sess.Set("name", "john") // save session err = sess.Save() utils.AssertEqual(t, nil, 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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) // set value sess.Set("name", "john") // save session err = sess.Save() utils.AssertEqual(t, nil, err) utils.AssertEqual(t, store.getSessionID(ctx), string(ctx.Response().Header.Peek(store.sessionName))) utils.AssertEqual(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) { const sessionDuration = 5 * time.Second t.Parallel() // session store store := New() // fiber instance app := fiber.New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) // set value sess.Set("name", "john") token := sess.ID() // expire this session in 5 seconds sess.SetExpiry(sessionDuration) // save session err = sess.Save() utils.AssertEqual(t, nil, err) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) // here you need to get the old session yet ctx.Request().Header.SetCookie(store.sessionName, token) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, "john", sess.Get("name")) // just to make sure the session has been expired time.Sleep(sessionDuration + (10 * time.Millisecond)) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // here you should get a new session ctx.Request().Header.SetCookie(store.sessionName, token) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, sess.Get("name")) utils.AssertEqual(t, true, sess.ID() != token) }) } // go test -run Test_Session_Destroy func Test_Session_Destroy(t *testing.T) { t.Parallel() t.Run("destroy from cookie", func(t *testing.T) { t.Parallel() // session store store := New() // fiber instance app := fiber.New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) sess.Set("name", "fenny") utils.AssertEqual(t, nil, sess.Destroy()) name := sess.Get("name") utils.AssertEqual(t, nil, name) }) t.Run("destroy from header", func(t *testing.T) { t.Parallel() // session store store := New(Config{ KeyLookup: "header:session_id", }) // fiber instance app := fiber.New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) // set value & save sess.Set("name", "fenny") id := sess.ID() utils.AssertEqual(t, nil, sess.Save()) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session ctx.Request().Header.Set(store.sessionName, id) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) err = sess.Destroy() utils.AssertEqual(t, nil, err) utils.AssertEqual(t, "", string(ctx.Response().Header.Peek(store.sessionName))) utils.AssertEqual(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" }}) utils.AssertEqual(t, time.Hour, store.Expiration) utils.AssertEqual(t, "very random", store.KeyGenerator()) store = New(Config{Expiration: 0}) utils.AssertEqual(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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, sess.Save()) // cookie should be set on Save ( even if empty data ) utils.AssertEqual(t, 84, len(ctx.Response().Header.PeekCookie(store.sessionName))) } // go test -run Test_Session_Cookie_In_Response // Regression: https://github.com/gofiber/fiber/pull/1191 func Test_Session_Cookie_In_Middleware_Chain(t *testing.T) { t.Parallel() store := New() app := fiber.New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // get session sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) sess.Set("id", "1") id := sess.ID() utils.AssertEqual(t, true, sess.Fresh()) utils.AssertEqual(t, nil, sess.Save()) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) sess.Set("name", "john") utils.AssertEqual(t, true, sess.Fresh()) utils.AssertEqual(t, id, sess.ID()) // session id should be the same utils.AssertEqual(t, sess.ID() != "1", true) utils.AssertEqual(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.AcquireCtx(&fasthttp.RequestCtx{}) sess, err := store.Get(ctx) utils.AssertEqual(t, nil, err) id := sess.ID() sess.Set("id", "1") utils.AssertEqual(t, nil, sess.Save()) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) ctx.Request().Header.SetCookie(store.sessionName, id) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) sess.Delete("id") utils.AssertEqual(t, nil, sess.Save()) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) ctx.Request().Header.SetCookie(store.sessionName, id) sess, err = store.Get(ctx) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, sess.Fresh()) utils.AssertEqual(t, nil, sess.Get("id")) app.ReleaseCtx(ctx) } // go test -run Test_Session_Reset func Test_Session_Reset(t *testing.T) { t.Parallel() // fiber instance app := fiber.New() // session store store := New() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) t.Run("reset session data and id, and set fresh to be true", func(t *testing.T) { t.Parallel() // fiber context ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // a random session uuid originalSessionUUIDString := "" // now the session is in the storage freshSession, err := store.Get(ctx) utils.AssertEqual(t, nil, err) originalSessionUUIDString = freshSession.ID() // set a value freshSession.Set("name", "fenny") freshSession.Set("email", "fenny@example.com") err = freshSession.Save() utils.AssertEqual(t, nil, err) app.ReleaseCtx(ctx) ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) // 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) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, acquiredSession.Fresh()) err = acquiredSession.Reset() utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, acquiredSession.ID() == originalSessionUUIDString) utils.AssertEqual(t, false, acquiredSession.ID() == "") // acquiredSession.fresh should be true after resetting utils.AssertEqual(t, true, acquiredSession.Fresh()) // Check that the session data has been reset keys := acquiredSession.Keys() utils.AssertEqual(t, []string{}, keys) // Set a new value for 'name' and check that it's updated acquiredSession.Set("name", "john") utils.AssertEqual(t, "john", acquiredSession.Get("name")) utils.AssertEqual(t, nil, acquiredSession.Get("email")) // Save after resetting err = acquiredSession.Save() utils.AssertEqual(t, nil, err) // Check that the session id is not in the header or cookie anymore utils.AssertEqual(t, "", string(ctx.Response().Header.Peek(store.sessionName))) utils.AssertEqual(t, "", string(ctx.Request().Header.Peek(store.sessionName))) app.ReleaseCtx(ctx) }) } // go test -run Test_Session_Regenerate // Regression: https://github.com/gofiber/fiber/issues/1395 func Test_Session_Regenerate(t *testing.T) { t.Parallel() // 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.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) // now the session is in the storage freshSession, err := store.Get(ctx) utils.AssertEqual(t, nil, err) originalSessionUUIDString = freshSession.ID() err = freshSession.Save() utils.AssertEqual(t, nil, err) // release the context app.ReleaseCtx(ctx) // acquire a new context ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) // 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) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, acquiredSession.Fresh()) err = acquiredSession.Regenerate() utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, acquiredSession.ID() == originalSessionUUIDString) // acquiredSession.fresh should be true after regenerating utils.AssertEqual(t, true, acquiredSession.Fresh()) // release the context app.ReleaseCtx(ctx) }) } // go test -v -run=^$ -bench=Benchmark_Session -benchmem -count=4 func Benchmark_Session(b *testing.B) { app, store := fiber.New(), New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) c.Request().Header.SetCookie(store.sessionName, "12356789") var err error b.Run("default", func(b *testing.B) { b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") err = sess.Save() } utils.AssertEqual(b, nil, err) }) 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) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") err = sess.Save() } utils.AssertEqual(b, nil, err) }) } // go test -v -run=^$ -bench=Benchmark_Session_Parallel -benchmem -count=4 func Benchmark_Session_Parallel(b *testing.B) { b.Run("default", func(b *testing.B) { app, store := fiber.New(), New() b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.SetCookie(store.sessionName, "12356789") sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") _ = sess.Save() //nolint:errcheck // We're inside a benchmark app.ReleaseCtx(c) } }) }) b.Run("storage", func(b *testing.B) { app := fiber.New() store := New(Config{ Storage: memory.New(), }) b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.SetCookie(store.sessionName, "12356789") sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") _ = sess.Save() //nolint:errcheck // We're inside a benchmark app.ReleaseCtx(c) } }) }) } // go test -v -run=^$ -bench=Benchmark_Session_Asserted -benchmem -count=4 func Benchmark_Session_Asserted(b *testing.B) { b.Run("default", func(b *testing.B) { app, store := fiber.New(), New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) c.Request().Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { sess, err := store.Get(c) utils.AssertEqual(b, nil, err) sess.Set("john", "doe") err = sess.Save() utils.AssertEqual(b, nil, err) } }) b.Run("storage", func(b *testing.B) { app := fiber.New() store := New(Config{ Storage: memory.New(), }) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) c.Request().Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { sess, err := store.Get(c) utils.AssertEqual(b, nil, err) sess.Set("john", "doe") err = sess.Save() utils.AssertEqual(b, nil, err) } }) } // go test -v -run=^$ -bench=Benchmark_Session_Asserted_Parallel -benchmem -count=4 func Benchmark_Session_Asserted_Parallel(b *testing.B) { b.Run("default", func(b *testing.B) { app, store := fiber.New(), New() b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.SetCookie(store.sessionName, "12356789") sess, err := store.Get(c) utils.AssertEqual(b, nil, err) sess.Set("john", "doe") utils.AssertEqual(b, nil, sess.Save()) app.ReleaseCtx(c) } }) }) b.Run("storage", func(b *testing.B) { app := fiber.New() store := New(Config{ Storage: memory.New(), }) b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.SetCookie(store.sessionName, "12356789") sess, err := store.Get(c) utils.AssertEqual(b, nil, err) sess.Set("john", "doe") utils.AssertEqual(b, nil, sess.Save()) app.ReleaseCtx(c) } }) }) } // go test -v -race -run Test_Session_Concurrency ./... func Test_Session_Concurrency(t *testing.T) { t.Parallel() app := fiber.New() store := New() var wg sync.WaitGroup errChan := make(chan error, 10) // Buffered channel to collect errors const numGoroutines = 10 // Number of concurrent goroutines to test // Start numGoroutines goroutines for i := 0; i < numGoroutines; i++ { wg.Add(1) go func() { defer wg.Done() localCtx := app.AcquireCtx(&fasthttp.RequestCtx{}) sess, err := store.Get(localCtx) if err != nil { errChan <- err return } // Set a value sess.Set("name", "john") // get the session id id := sess.ID() // Check if the session is fresh if !sess.Fresh() { errChan <- errors.New("session should be fresh") return } // Save the session if err := sess.Save(); err != nil { errChan <- err return } // Release the context app.ReleaseCtx(localCtx) // Acquire a new context localCtx = app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(localCtx) // Set the session id in the header localCtx.Request().Header.SetCookie(store.sessionName, id) // Get the session sess, err = store.Get(localCtx) if err != nil { errChan <- err return } // Get the value name := sess.Get("name") if name != "john" { errChan <- errors.New("name should be john") return } // Get ID from the session if sess.ID() != id { errChan <- errors.New("id should be the same") return } // Check if the session is fresh if sess.Fresh() { errChan <- errors.New("session should not be fresh") return } // Delete the key sess.Delete("name") // Get the value name = sess.Get("name") if name != nil { errChan <- errors.New("name should be nil") return } // Destroy the session if err := sess.Destroy(); err != nil { errChan <- err return } }() } wg.Wait() // Wait for all goroutines to finish close(errChan) // Close the channel to signal no more errors will be sent // Check for errors sent to errChan for err := range errChan { utils.AssertEqual(t, nil, err) } }