diff --git a/cache.go b/cache.go index b4073a0..5938074 100644 --- a/cache.go +++ b/cache.go @@ -110,18 +110,22 @@ func (cfg *Config[K, T]) SanitizeValidate() error { } type Payload[T any] struct { - // cacheExpireAt is an atomic pointer to avoid race condition + // ExpireAt is an atomic pointer to avoid race condition // while concurrently reading the timestamp - cacheExpireAt *atomic.Pointer[time.Time] - payload T + ExpireAt *atomic.Pointer[time.Time] + Payload T } func (pyl *Payload[T]) Expiry() time.Time { - return *pyl.cacheExpireAt.Load() + if pyl.ExpireAt == nil { + return time.Time{} + } + + return *pyl.ExpireAt.Load() } func (pyl *Payload[T]) Value() T { - return pyl.payload + return pyl.Payload } type Tuple[K comparable, T any] struct { @@ -232,7 +236,7 @@ func (ch *Cache[K, T]) Get(key K) Value[T] { return v } - expireAt := cp.cacheExpireAt.Load() + expireAt := cp.ExpireAt.Load() delta := time.Since(*expireAt) if delta >= 0 && ch.disableServeStale { // cache expired and should be removed @@ -246,7 +250,7 @@ func (ch *Cache[K, T]) Get(key K) Value[T] { } v.Found = true - v.V = cp.payload + v.V = cp.Payload return v } @@ -261,8 +265,8 @@ func (ch *Cache[K, T]) Add(key K, value T) (evicted bool) { cea.Store(&expireAt) return ch.store.Add(key, &Payload[T]{ - cacheExpireAt: &cea, - payload: value, + ExpireAt: &cea, + Payload: value, }) } diff --git a/cache_test.go b/cache_test.go index 4e3cb84..17ed73d 100644 --- a/cache_test.go +++ b/cache_test.go @@ -325,16 +325,47 @@ func TestSanitize(tt *testing.T) { func TestPayload(tt *testing.T) { asserter := assert.New(tt) - expireAt := time.Now().Add(time.Minute) - cea := atomic.Pointer[time.Time]{} - cea.Store(&expireAt) - value := "hello world" - - pyl := Payload[string]{ - cacheExpireAt: &cea, - payload: value, - } - - asserter.Equal(value, pyl.Value()) - asserter.EqualValues(expireAt, pyl.Expiry()) + tt.Run("expiry & payload available", func(t *testing.T) { + expireAt := time.Now().Add(time.Minute) + cea := atomic.Pointer[time.Time]{} + cea.Store(&expireAt) + value := "hello world" + pyl := Payload[string]{ + ExpireAt: &cea, + Payload: value, + } + asserter.Equal(value, pyl.Value()) + asserter.EqualValues(expireAt, pyl.Expiry()) + }) + + tt.Run("expiry not available", func(t *testing.T) { + value := "hello world" + pyl := Payload[string]{ + ExpireAt: nil, + Payload: value, + } + asserter.Equal(value, pyl.Value()) + asserter.EqualValues(time.Time{}, pyl.Expiry()) + }) + + tt.Run("value not available", func(t *testing.T) { + expireAt := time.Now().Add(time.Minute) + cea := atomic.Pointer[time.Time]{} + cea.Store(&expireAt) + pyl := Payload[any]{ + ExpireAt: &cea, + Payload: nil, + } + asserter.Equal(nil, pyl.Value()) + asserter.EqualValues(expireAt, pyl.Expiry()) + }) + + tt.Run("expiry & value not available", func(t *testing.T) { + pyl := Payload[any]{ + ExpireAt: nil, + Payload: nil, + } + asserter.Equal(nil, pyl.Value()) + asserter.EqualValues(time.Time{}, pyl.Expiry()) + }) }