Skip to content

Commit 43d9140

Browse files
committed
test: add comprehensive unit tests for session registry operations
Introduced extensive test coverage for `Registry` methods, including `ReadSessions` and `WriteSessions`. Added scenarios for session reading, writing, cookie management, error handling, and integration flows to improve reliability and maintainability.
1 parent ac435f6 commit 43d9140

1 file changed

Lines changed: 297 additions & 0 deletions

File tree

session/registry_test.go

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package session
22

33
import (
4+
"net/http"
5+
"net/http/httptest"
46
"testing"
7+
"time"
58

69
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/mock"
711
)
812

913
func TestNewRegistry(t *testing.T) {
@@ -251,6 +255,299 @@ func TestRegistry_SpecialCookieNames(t *testing.T) {
251255
}
252256
}
253257

258+
func TestRegistry_ReadSessions(t *testing.T) {
259+
session1 := createTestSession("session1")
260+
session2 := createTestSession("session2")
261+
session3 := createTestSession("session3")
262+
263+
tests := []struct {
264+
name string
265+
sessions []*Session
266+
setup func(*testing.T, *http.Request)
267+
expectError bool
268+
errorMsg string
269+
cookieCount int
270+
}{
271+
{
272+
name: "read all sessions successfully",
273+
sessions: []*Session{session1, session2, session3},
274+
setup: func(t *testing.T, req *http.Request) {
275+
req.AddCookie(&http.Cookie{Name: "session1", Value: "token1"})
276+
req.AddCookie(&http.Cookie{Name: "session2", Value: "token2"})
277+
req.AddCookie(&http.Cookie{Name: "session3", Value: "token3"})
278+
},
279+
cookieCount: 3,
280+
},
281+
{
282+
name: "read with partial cookies",
283+
sessions: []*Session{session1, session2, session3},
284+
setup: func(t *testing.T, req *http.Request) {
285+
req.AddCookie(&http.Cookie{Name: "session2", Value: "token2"})
286+
},
287+
cookieCount: 1,
288+
},
289+
{
290+
name: "read with no cookies",
291+
sessions: []*Session{session1, session2, session3},
292+
setup: func(t *testing.T, req *http.Request) {},
293+
cookieCount: 0,
294+
},
295+
{
296+
name: "empty registry reads successfully",
297+
sessions: []*Session{},
298+
setup: func(t *testing.T, req *http.Request) {},
299+
cookieCount: 0,
300+
},
301+
{
302+
name: "single session",
303+
sessions: []*Session{session1},
304+
setup: func(t *testing.T, req *http.Request) {
305+
req.AddCookie(&http.Cookie{Name: "session1", Value: "token1"})
306+
},
307+
cookieCount: 1,
308+
},
309+
}
310+
311+
for _, tt := range tests {
312+
t.Run(tt.name, func(t *testing.T) {
313+
mockStore := new(MockStore)
314+
mockStore.On("Find", mock.Anything, mock.Anything).Return([]byte{}, false, nil)
315+
316+
registry := NewRegistry(tt.sessions...)
317+
318+
for _, s := range registry.All() {
319+
s.store = mockStore
320+
}
321+
322+
req := httptest.NewRequest(http.MethodGet, "/", nil)
323+
tt.setup(t, req)
324+
325+
got, err := registry.ReadSessions(req)
326+
327+
if tt.expectError {
328+
assert.Error(t, err)
329+
assert.Contains(t, err.Error(), tt.errorMsg)
330+
} else {
331+
assert.NoError(t, err)
332+
assert.NotNil(t, got)
333+
}
334+
335+
if len(tt.sessions) > 0 {
336+
mockStore.AssertNumberOfCalls(t, "Find", tt.cookieCount)
337+
}
338+
})
339+
}
340+
}
341+
342+
func TestRegistry_WriteSessions(t *testing.T) {
343+
tests := []struct {
344+
name string
345+
sessions []*Session
346+
modifySession func(*testing.T, *http.Request, *Registry)
347+
expectError bool
348+
verifyCookies func(*testing.T, *http.Response)
349+
}{
350+
{
351+
name: "write modified session",
352+
sessions: []*Session{createTestSession("session1")},
353+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {
354+
registry.All()[0].Put(req.Context(), "key", "value")
355+
},
356+
verifyCookies: func(t *testing.T, resp *http.Response) {
357+
cookies := resp.Cookies()
358+
assert.Len(t, cookies, 1)
359+
assert.Equal(t, "session1", cookies[0].Name)
360+
},
361+
},
362+
{
363+
name: "write destroyed session",
364+
sessions: []*Session{createTestSession("session1")},
365+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {
366+
err := registry.All()[0].Destroy(req.Context())
367+
assert.NoError(t, err)
368+
},
369+
verifyCookies: func(t *testing.T, resp *http.Response) {
370+
cookies := resp.Cookies()
371+
assert.Len(t, cookies, 1)
372+
assert.Equal(t, "session1", cookies[0].Name)
373+
assert.Equal(t, -1, cookies[0].MaxAge)
374+
},
375+
},
376+
{
377+
name: "unmodified session - default case",
378+
sessions: []*Session{createTestSession("session1")},
379+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {},
380+
verifyCookies: func(t *testing.T, resp *http.Response) {
381+
cookies := resp.Cookies()
382+
assert.Len(t, cookies, 0)
383+
},
384+
},
385+
{
386+
name: "multiple sessions with mixed statuses",
387+
sessions: []*Session{createTestSession("session1"), createTestSession("session2"), createTestSession("session3")},
388+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {
389+
sessions := registry.All()
390+
sessions[0].Put(req.Context(), "key1", "value1")
391+
err := sessions[1].Destroy(req.Context())
392+
assert.NoError(t, err)
393+
},
394+
verifyCookies: func(t *testing.T, resp *http.Response) {
395+
cookies := resp.Cookies()
396+
assert.Len(t, cookies, 2)
397+
},
398+
},
399+
{
400+
name: "empty registry writes successfully",
401+
sessions: []*Session{},
402+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {},
403+
verifyCookies: func(t *testing.T, resp *http.Response) {
404+
cookies := resp.Cookies()
405+
assert.Len(t, cookies, 0)
406+
},
407+
},
408+
}
409+
410+
for _, tt := range tests {
411+
t.Run(tt.name, func(t *testing.T) {
412+
mockStore := new(MockStore)
413+
mockStore.On("Find", mock.Anything, mock.Anything).Return([]byte{}, false, nil)
414+
mockStore.On("Commit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
415+
mockStore.On("Delete", mock.Anything, mock.Anything).Return(nil)
416+
417+
registry := NewRegistry(tt.sessions...)
418+
419+
req := httptest.NewRequest(http.MethodGet, "/", nil)
420+
w := httptest.NewRecorder()
421+
422+
for _, s := range registry.All() {
423+
s.store = mockStore
424+
}
425+
426+
req, err := registry.ReadSessions(req)
427+
assert.NoError(t, err)
428+
429+
tt.modifySession(t, req, registry)
430+
431+
err = registry.WriteSessions(w, req)
432+
433+
if tt.expectError {
434+
assert.Error(t, err)
435+
} else {
436+
assert.NoError(t, err)
437+
}
438+
439+
tt.verifyCookies(t, w.Result())
440+
})
441+
}
442+
}
443+
444+
func TestRegistry_WriteSessions_ErrorHandling(t *testing.T) {
445+
tests := []struct {
446+
name string
447+
modifySession func(*testing.T, *http.Request, *Registry)
448+
errorContains string
449+
}{
450+
{
451+
name: "commit error is joined and returned",
452+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {
453+
registry.All()[0].Put(req.Context(), "key", "value")
454+
},
455+
errorContains: "session session1",
456+
},
457+
{
458+
name: "multiple commit errors are joined",
459+
modifySession: func(t *testing.T, req *http.Request, registry *Registry) {
460+
sessions := registry.All()
461+
sessions[0].Put(req.Context(), "key1", "value1")
462+
sessions[1].Put(req.Context(), "key2", "value2")
463+
},
464+
errorContains: "session session1",
465+
},
466+
}
467+
468+
for _, tt := range tests {
469+
t.Run(tt.name, func(t *testing.T) {
470+
mockStore := new(MockStore)
471+
mockStore.On("Find", mock.Anything, mock.Anything).Return([]byte{}, false, nil)
472+
mockStore.On("Commit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(assert.AnError)
473+
474+
registry := NewRegistry(createTestSession("session1"), createTestSession("session2"))
475+
476+
req := httptest.NewRequest(http.MethodGet, "/", nil)
477+
w := httptest.NewRecorder()
478+
479+
for _, s := range registry.All() {
480+
s.store = mockStore
481+
}
482+
483+
req, err := registry.ReadSessions(req)
484+
assert.NoError(t, err)
485+
486+
tt.modifySession(t, req, registry)
487+
488+
err = registry.WriteSessions(w, req)
489+
assert.Error(t, err)
490+
assert.Contains(t, err.Error(), tt.errorContains)
491+
})
492+
}
493+
}
494+
495+
func TestRegistry_Integration_ReadWriteSessions(t *testing.T) {
496+
mockStore := new(MockStore)
497+
mockStore.On("Find", mock.Anything, mock.Anything).Return([]byte{}, false, nil)
498+
mockStore.On("Commit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
499+
500+
sessions := []*Session{createTestSession("session1"), createTestSession("session2")}
501+
registry := NewRegistry(sessions...)
502+
503+
for _, s := range registry.All() {
504+
s.store = mockStore
505+
}
506+
507+
req := httptest.NewRequest(http.MethodGet, "/", nil)
508+
w := httptest.NewRecorder()
509+
510+
req, err := registry.ReadSessions(req)
511+
assert.NoError(t, err)
512+
513+
sessions[0].Put(req.Context(), "key1", "value1")
514+
515+
err = registry.WriteSessions(w, req)
516+
assert.NoError(t, err)
517+
518+
cookies := w.Result().Cookies()
519+
assert.Len(t, cookies, 1)
520+
assert.Equal(t, "session1", cookies[0].Name)
521+
}
522+
523+
func TestRegistry_WriteSessions_DestroyedExpiry(t *testing.T) {
524+
mockStore := new(MockStore)
525+
mockStore.On("Find", mock.Anything, mock.Anything).Return([]byte{}, false, nil)
526+
mockStore.On("Delete", mock.Anything, mock.Anything).Return(nil)
527+
528+
session := createTestSession("session1")
529+
session.store = mockStore
530+
531+
registry := NewRegistry(session)
532+
533+
req := httptest.NewRequest(http.MethodGet, "/", nil)
534+
w := httptest.NewRecorder()
535+
536+
req, err := registry.ReadSessions(req)
537+
assert.NoError(t, err)
538+
539+
err = session.Destroy(req.Context())
540+
assert.NoError(t, err)
541+
542+
err = registry.WriteSessions(w, req)
543+
assert.NoError(t, err)
544+
545+
cookies := w.Result().Cookies()
546+
assert.Len(t, cookies, 1)
547+
assert.Equal(t, -1, cookies[0].MaxAge)
548+
assert.True(t, cookies[0].Expires.Equal(time.Unix(1, 0).UTC()))
549+
}
550+
254551
func createTestSession(cookieName string) *Session {
255552
config := Config{
256553
Cookie: Cookie{

0 commit comments

Comments
 (0)