Files
gitea/modules/session/virtual_test.go
T

161 lines
4.3 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package session
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestVirtualStore_BasicOperations(t *testing.T) {
p := &VirtualSessionProvider{provider: &mockProvider{}}
store := NewVirtualStore(p, "test-sid", make(map[any]any))
assert.Equal(t, "test-sid", store.ID())
require.NoError(t, store.Set("uid", int64(42)))
assert.Equal(t, int64(42), store.Get("uid"))
require.NoError(t, store.Delete("uid"))
assert.Nil(t, store.Get("uid"))
}
func TestInertVirtualStore_IgnoresWrites(t *testing.T) {
store := NewInertVirtualStore("dead-sid")
assert.Equal(t, "dead-sid", store.ID())
// Set should be silently ignored
require.NoError(t, store.Set("uid", int64(42)))
assert.Nil(t, store.Get("uid"))
// Release should be a no-op
require.NoError(t, store.Release())
}
func TestVirtualSessionProvider_DestroyTombstone(t *testing.T) {
mp := &mockProvider{sessions: map[string]map[any]any{
"sid-1": {"uid": int64(1)},
}}
vsp := &VirtualSessionProvider{provider: mp}
// Before destroy, Read returns data from the mock provider
store, err := vsp.Read("sid-1")
require.NoError(t, err)
assert.Equal(t, int64(1), store.Get("uid"))
// Destroy the session
require.NoError(t, vsp.Destroy("sid-1"))
// Simulate concurrent request recreating the session file:
// the mock provider now has the session again
mp.sessions["sid-1"] = map[any]any{"uid": int64(1)}
// Read after destroy should return inert store due to tombstone
store, err = vsp.Read("sid-1")
require.NoError(t, err)
assert.Nil(t, store.Get("uid"), "tombstoned session should return empty store")
// The inert store should ignore writes and releases
require.NoError(t, store.Set("uid", int64(99)))
assert.Nil(t, store.Get("uid"))
require.NoError(t, store.Release())
}
func TestVirtualSessionProvider_ReadNonExistent(t *testing.T) {
mp := &mockProvider{sessions: map[string]map[any]any{}}
vsp := &VirtualSessionProvider{provider: mp}
// Read for a session that doesn't exist returns a VirtualStore
store, err := vsp.Read("no-such-sid")
require.NoError(t, err)
assert.Nil(t, store.Get("uid"))
assert.Equal(t, "no-such-sid", store.ID())
}
func TestVirtualSessionProvider_ExistAlwaysTrue(t *testing.T) {
vsp := &VirtualSessionProvider{provider: &mockProvider{}}
exists, err := vsp.Exist("anything")
require.NoError(t, err)
assert.True(t, exists)
}
func TestDestroySessionByID_NilProvider(t *testing.T) {
// Ensure DestroySessionByID doesn't panic when globalProvider is nil
old := globalProvider
globalProvider = nil
defer func() { globalProvider = old }()
assert.NoError(t, DestroySessionByID("anything"))
}
// mockProvider is a minimal in-memory session.Provider for testing
type mockProvider struct {
sessions map[string]map[any]any
}
func (m *mockProvider) Init(_ int64, _ string) error { return nil }
func (m *mockProvider) Read(sid string) (RawStore, error) {
if m.sessions == nil {
m.sessions = make(map[string]map[any]any)
}
data, ok := m.sessions[sid]
if !ok {
data = make(map[any]any)
m.sessions[sid] = data
}
return &mockStore{sid: sid, data: data}, nil
}
func (m *mockProvider) Exist(sid string) (bool, error) {
if m.sessions == nil {
return false, nil
}
_, ok := m.sessions[sid]
return ok, nil
}
func (m *mockProvider) Destroy(sid string) error {
delete(m.sessions, sid)
return nil
}
func (m *mockProvider) Regenerate(oldsid, sid string) (RawStore, error) {
data := m.sessions[oldsid]
delete(m.sessions, oldsid)
if data == nil {
data = make(map[any]any)
}
m.sessions[sid] = data
return &mockStore{sid: sid, data: data}, nil
}
func (m *mockProvider) Count() (int, error) {
return len(m.sessions), nil
}
func (m *mockProvider) GC() {}
// mockStore is a minimal in-memory RawStore for testing
type mockStore struct {
sid string
data map[any]any
}
func (s *mockStore) Set(key, val any) error { s.data[key] = val; return nil }
func (s *mockStore) Get(key any) any { return s.data[key] }
func (s *mockStore) Delete(key any) error { delete(s.data, key); return nil }
func (s *mockStore) ID() string { return s.sid }
func (s *mockStore) Release() error { return nil }
func (s *mockStore) Flush() error {
for k := range s.data {
delete(s.data, k)
}
return nil
}