address review feedback on cache and session store

This commit is contained in:
bcmmbaga
2026-08-07 15:14:10 +03:00
parent de6bf481e6
commit 3d7e835046
3 changed files with 12 additions and 6 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ func (s *SessionStore) RegisterToken(ctx context.Context, token string, expiresA
key := usedTokenKeyPrefix + hashToken(token) key := usedTokenKeyPrefix + hashToken(token)
created, err := s.cache.SetNX(ctx, key, usedTokenMarker, ttl) created, err := s.cache.SetNX(ctx, key, usedTokenMarker, ttl)
if err != nil { if err != nil {
return fmt.Errorf("failed to store used token entry: %w", err) return fmt.Errorf("store used token entry: %w", err)
} }
if !created { if !created {
return ErrTokenAlreadyUsed return ErrTokenAlreadyUsed
+5 -5
View File
@@ -64,12 +64,12 @@ func TestSessionStore_ConcurrentRegistrationAllowsOneCaller(t *testing.T) {
case errors.Is(err, ErrTokenAlreadyUsed): case errors.Is(err, ErrTokenAlreadyUsed):
alreadyUsed++ alreadyUsed++
default: default:
require.NoError(t, err) require.NoError(t, err, "concurrent registration returned an unexpected error")
} }
} }
assert.Equal(t, 1, succeeded) assert.Equal(t, 1, succeeded, "exactly one concurrent caller should register the token")
assert.Equal(t, attempts-1, alreadyUsed) assert.Equal(t, attempts-1, alreadyUsed, "every other caller should be rejected as already used")
} }
func TestSessionStore_RegisterDifferentTokensAreIndependent(t *testing.T) { func TestSessionStore_RegisterDifferentTokensAreIndependent(t *testing.T) {
@@ -119,8 +119,8 @@ func TestSessionStore_CacheErrorIsReturned(t *testing.T) {
s := NewSessionStore(failingTokenCache{err: cacheErr}) s := NewSessionStore(failingTokenCache{err: cacheErr})
err := s.RegisterToken(context.Background(), "token", time.Now().Add(time.Hour)) err := s.RegisterToken(context.Background(), "token", time.Now().Add(time.Hour))
require.Error(t, err) require.Error(t, err, "cache failure should be surfaced to the caller")
assert.ErrorIs(t, err, cacheErr) assert.ErrorIs(t, err, cacheErr, "cache error should be wrapped, not replaced")
} }
func TestHashToken_StableAndDoesNotLeak(t *testing.T) { func TestHashToken_StableAndDoesNotLeak(t *testing.T) {
+6
View File
@@ -33,6 +33,12 @@ func (s *goCacheStore) SetNX(_ context.Context, key, value string, ttl time.Dura
return true, nil return true, nil
} }
// GetDel reads the value under key and removes it. go-cache has no native read-and-delete
// and releases its own lock between the two calls, so mu holds the pair together and no
// value is consumed twice.
//
// Writes do not take mu: a Set landing mid-pair is lost, since GetDel returns the prior
// value and deletes the new one. Callers must write a consumed key only once.
func (s *goCacheStore) GetDel(_ context.Context, key string) (string, bool, error) { func (s *goCacheStore) GetDel(_ context.Context, key string) (string, bool, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()