diff --git a/.travis.yml b/.travis.yml index c8f0d21..63798b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: + - "1.16.x" - "1.15.x" - - "1.14.x" git: depth: 1 diff --git a/cache.go b/cache.go index 89dd917..51ff261 100644 --- a/cache.go +++ b/cache.go @@ -369,6 +369,23 @@ return length } +// GetKeys returns all keys of items in the cache. Returns nil when the cache has been closed. +func (cache *Cache) GetKeys() []string { + cache.mutex.Lock() + defer cache.mutex.Unlock() + + if cache.isShutDown { + return nil + } + keys := make([]string, len(cache.items)) + i := 0 + for k := range cache.items { + keys[i] = k + i++ + } + return keys +} + // SetTTL sets the global TTL value for items in the cache, which can be overridden at the item level. func (cache *Cache) SetTTL(ttl time.Duration) error { cache.mutex.Lock() @@ -465,6 +482,18 @@ return cache.metrics } +// Touch resets the TTL of the key when it exists, returns ErrNotFound if the key is not present. +func (cache *Cache) Touch(key string) error { + cache.mutex.Lock() + defer cache.mutex.Unlock() + item, exists := cache.items[key] + if !exists { + return ErrNotFound + } + item.touch() + return nil +} + func min(duration time.Duration, second time.Duration) time.Duration { if duration < second { return duration diff --git a/cache_test.go b/cache_test.go index 235a009..6e770c4 100644 --- a/cache_test.go +++ b/cache_test.go @@ -55,6 +55,50 @@ <-sync assert.Equal(t, Closed, reason) +} + +func TestCache_TestTouch(t *testing.T) { + t.Parallel() + cache := NewCache() + defer cache.Close() + + lock := sync.Mutex{} + + lock.Lock() + expired := false + lock.Unlock() + + cache.SkipTTLExtensionOnHit(true) + cache.SetExpirationCallback(func(key string, value interface{}) { + lock.Lock() + defer lock.Unlock() + expired = true + }) + + cache.SetWithTTL("key", "data", time.Millisecond*900) + <-time.After(time.Millisecond * 500) + + // no Touch + // cache.Touch("key") + + <-time.After(time.Millisecond * 500) + lock.Lock() + assert.Equal(t, true, expired) + lock.Unlock() + cache.Remove("key") + + lock.Lock() + expired = false + lock.Unlock() + + cache.SetWithTTL("key", "data", time.Millisecond*900) + <-time.After(time.Millisecond * 500) + cache.Touch("key") + + <-time.After(time.Millisecond * 500) + lock.Lock() + assert.Equal(t, false, expired) + lock.Unlock() } // Issue #37: Cache metrics @@ -611,6 +655,21 @@ assert.Equal(t, "world", (data.(string)), "Expected data content to be 'world'") } +func TestCacheGetKeys(t *testing.T) { + t.Parallel() + + cache := NewCache() + defer cache.Close() + + keys := cache.GetKeys() + assert.Empty(t, keys, "Expected keys to be empty") + + cache.Set("hello", "world") + keys = cache.GetKeys() + assert.NotEmpty(t, keys, "Expected keys to be not empty") + assert.Equal(t, []string{"hello"}, keys, "Expected keys contains 'hello'") +} + func TestCacheExpirationCallbackFunction(t *testing.T) { t.Parallel() diff --git a/evictionreason_enumer_test.go b/evictionreason_enumer_test.go new file mode 100644 index 0000000..1ec04ad --- /dev/null +++ b/evictionreason_enumer_test.go @@ -0,0 +1,18 @@ +package ttlcache + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestError(t *testing.T) { + assert.Equal(t, "key not found", ErrNotFound.Error()) + +} + +func TestEvictionError(t *testing.T) { + assert.Equal(t, "Removed", Removed.String()) + assert.Equal(t, "Expired", Expired.String()) + +}