//go:build unit // +build unit // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package async import ( "fmt" "math/rand" "testing" "time" "github.com/stretchr/testify/assert" ) func TestLRUSimple(t *testing.T) { lru := NewLRUCache(10, time.Minute) lru.Set("foo", "bar") bar, ok := lru.Get("foo") assert.True(t, ok) assert.Equal(t, bar, "bar") baz, ok := lru.Get("fooz") assert.False(t, ok) assert.Nil(t, baz) lru.Delete("foo") bar, ok = lru.Get("foo") assert.False(t, ok) assert.Nil(t, bar) } func TestLRUSetDelete(t *testing.T) { lru := NewLRUCache(10, time.Minute) lru.Set("foo", "bar") bar, ok := lru.Get("foo") assert.True(t, ok) assert.Equal(t, bar, "bar") lru.Set("foo", "bar2") bar, ok = lru.Get("foo") assert.True(t, ok) assert.Equal(t, bar, "bar2") lru.Delete("foo") bar, ok = lru.Get("foo") assert.False(t, ok) assert.Nil(t, bar) } func TestLRUTTlPurge(t *testing.T) { lru := NewLRUCache(10, 20*time.Millisecond) lru.Set("foo", "bar") bar, ok := lru.Get("foo") assert.True(t, ok) assert.Equal(t, bar, "bar") time.Sleep(100 * time.Millisecond) bar, ok = lru.Get("foo") assert.False(t, ok) assert.Nil(t, bar) } func TestLRUSizePurge(t *testing.T) { lru := NewLRUCache(1, time.Minute) lru.Set("foo", "bar") bar, ok := lru.Get("foo") assert.True(t, ok) assert.Equal(t, bar, "bar") lru.Set("bar", "baz") baz, ok := lru.Get("bar") assert.True(t, ok) assert.Equal(t, baz, "baz") bar, ok = lru.Get("foo") assert.False(t, ok) assert.Nil(t, bar) } func BenchmarkLRUCacheConcurrency(b *testing.B) { // prime a cache with %80 size size := 10000 lru := NewLRUCache(size/80, 30*time.Minute) for i := 0; i < size; i++ { lru.Set(fmt.Sprintf("%d", i), true) } // fetch or set up to 5x concurrently for n := 0; n < 5; n++ { go func() { for i := 0; i < size; i++ { // 1 in 5 times, set the value if rand.Intn(5) == 0 { lru.Set(fmt.Sprintf("%d", i), true) } else { lru.Get(fmt.Sprintf("%d", i)) } } }() } } func BenchmarkLRUCacheSet(b *testing.B) { // prime a cache as large as the data set lru := NewLRUCache(b.N, 30*time.Minute) for i := 0; i < b.N; i++ { lru.Set(fmt.Sprintf("%d", i), true) } } func BenchmarkLRUCacheFull(b *testing.B) { // prime a cache as large as the data set lru := NewLRUCache(b.N, 30*time.Minute) for i := 0; i < b.N; i++ { lru.Set(fmt.Sprintf("%d", i), true) } // fetch up to 5x concurrently for n := 0; n < 5; n++ { go func() { for i := 0; i < b.N; i++ { lru.Get(fmt.Sprintf("%d", i)) } }() } } func BenchmarkLRUCacheHalf(b *testing.B) { // prime a cache as large as the data set lru := NewLRUCache(b.N/2, 30*time.Minute) for i := 0; i < b.N; i++ { lru.Set(fmt.Sprintf("%d", i), true) } // fetch up to 5x concurrently for n := 0; n < 5; n++ { go func() { for i := 0; i < b.N; i++ { lru.Get(fmt.Sprintf("%d", i)) } }() } } func BenchmarkLRUCacheWorst(b *testing.B) { // prime a cache with only one element lru := NewLRUCache(1, 30*time.Minute) for i := 0; i < b.N; i++ { lru.Set(fmt.Sprintf("%d", i), true) } // fetch up to 5x concurrently for n := 0; n < 5; n++ { go func() { for i := 0; i < b.N; i++ { lru.Get(fmt.Sprintf("%d", i)) } }() } } func BenchmarkLRUCacheTTLExpiry(b *testing.B) { // prime a cache with everything expired immediately lru := NewLRUCache(b.N, 0) for i := 0; i < b.N; i++ { lru.Set(fmt.Sprintf("%d", i), true) } // fetch up to 5x concurrently for n := 0; n < 5; n++ { go func() { for i := 0; i < b.N; i++ { lru.Get(fmt.Sprintf("%d", i)) } }() } }