Skip to content

Commit

Permalink
add proper teardown to tests to prevent goroutine leak
Browse files Browse the repository at this point in the history
  • Loading branch information
paskal committed Apr 26, 2020
1 parent b70c2db commit 6f83ced
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 50 deletions.
52 changes: 34 additions & 18 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func TestStat_String(t *testing.T) {
}

func TestCache_Get(t *testing.T) {
caches := cachesTestList(t)
caches, teardown := cachesTestList(t)
defer teardown()

for _, c := range caches {
c := c
Expand Down Expand Up @@ -99,7 +100,8 @@ func TestCache_Get(t *testing.T) {
}

func TestCache_MaxValueSize(t *testing.T) {
caches := cachesTestList(t, MaxKeys(5), MaxValSize(10))
caches, teardown := cachesTestList(t, MaxKeys(5), MaxValSize(10))
defer teardown()

for _, c := range caches {
c := c
Expand Down Expand Up @@ -156,7 +158,8 @@ func TestCache_MaxValueSize(t *testing.T) {
}

func TestCache_MaxCacheSize(t *testing.T) {
caches := cachesTestList(t, MaxKeys(50), MaxCacheSize(20))
caches, teardown := cachesTestList(t, MaxKeys(50), MaxCacheSize(20))
defer teardown()

for _, c := range caches {
c := c
Expand Down Expand Up @@ -204,8 +207,8 @@ func TestCache_MaxCacheSize(t *testing.T) {
}

func TestCache_MaxCacheSizeParallel(t *testing.T) {

caches := cachesTestList(t, MaxCacheSize(123), MaxKeys(10000))
caches, teardown := cachesTestList(t, MaxCacheSize(123), MaxKeys(10000))
defer teardown()

for _, c := range caches {
c := c
Expand Down Expand Up @@ -235,7 +238,8 @@ func TestCache_MaxCacheSizeParallel(t *testing.T) {
}

func TestCache_MaxKeySize(t *testing.T) {
caches := cachesTestList(t, MaxKeySize(5))
caches, teardown := cachesTestList(t, MaxKeySize(5))
defer teardown()

for _, c := range caches {
c := c
Expand Down Expand Up @@ -268,7 +272,9 @@ func TestCache_MaxKeySize(t *testing.T) {
}

func TestCache_Peek(t *testing.T) {
caches := cachesTestList(t)
caches, teardown := cachesTestList(t)
defer teardown()

for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand All @@ -286,11 +292,12 @@ func TestCache_Peek(t *testing.T) {
assert.Equal(t, "result", r.(string))
})
}

}

func TestLruCache_ParallelHits(t *testing.T) {
caches := cachesTestList(t)
caches, teardown := cachesTestList(t)
defer teardown()

for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand Down Expand Up @@ -323,8 +330,9 @@ func TestLruCache_ParallelHits(t *testing.T) {
}

func TestCache_Purge(t *testing.T) {
caches, teardown := cachesTestList(t)
defer teardown()

caches := cachesTestList(t)
for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand All @@ -348,8 +356,9 @@ func TestCache_Purge(t *testing.T) {
}

func TestCache_Invalidate(t *testing.T) {
caches, teardown := cachesTestList(t)
defer teardown()

caches := cachesTestList(t)
for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand Down Expand Up @@ -390,8 +399,9 @@ func TestCache_Invalidate(t *testing.T) {
}

func TestCache_Delete(t *testing.T) {
caches, teardown := cachesTestList(t)
defer teardown()

caches := cachesTestList(t)
for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand Down Expand Up @@ -426,7 +436,9 @@ func TestCache_DeleteWithEvent(t *testing.T) {
evCount++
}

caches := cachesTestList(t, OnEvicted(onEvict))
caches, teardown := cachesTestList(t, OnEvicted(onEvict))
defer teardown()

for _, c := range caches {
c := c

Expand Down Expand Up @@ -456,7 +468,9 @@ func TestCache_DeleteWithEvent(t *testing.T) {
}

func TestCache_Stats(t *testing.T) {
caches := cachesTestList(t)
caches, teardown := cachesTestList(t)
defer teardown()

for _, c := range caches {
c := c
t.Run(strings.Replace(fmt.Sprintf("%T", c), "*lcw.", "", 1), func(t *testing.T) {
Expand Down Expand Up @@ -509,7 +523,6 @@ func TestCache_Stats(t *testing.T) {
assert.Equal(t, CacheStat{Hits: 1, Misses: 101, Keys: 101, Size: 893, Errors: 1}, c.Stat())
}
})

}
}

Expand Down Expand Up @@ -541,14 +554,14 @@ func ExampleLoadingCache_Get() {
}

func ExampleLoadingCache_Delete() {

// make expirable cache (30m TTL) with up to 10 keys. Set callback on eviction event
c, err := NewExpirableCache(MaxKeys(10), TTL(time.Minute*30), OnEvicted(func(key string, value Value) {
fmt.Println("key " + key + " evicted")
}))
if err != nil {
panic("can' make cache")
}
defer c.Close()

// try to get from cache and because mykey is not in will put it
_, _ = c.Get("mykey", func() (Value, error) {
Expand All @@ -571,7 +584,7 @@ type countedCache interface {
counts
}

func cachesTestList(t *testing.T, opts ...Option) []countedCache {
func cachesTestList(t *testing.T, opts ...Option) ([]countedCache, func()) {
var caches []countedCache
ec, err := NewExpirableCache(opts...)
require.NoError(t, err, "can't make exp cache")
Expand All @@ -587,7 +600,10 @@ func cachesTestList(t *testing.T, opts ...Option) []countedCache {
require.NoError(t, err, "can't make redis cache")
caches = append(caches, rc)

return caches
return caches, func() {
_ = client.Close()
server.Close()
}
}

type sizedString string
Expand Down
1 change: 0 additions & 1 deletion expirable_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func TestExpirableCache(t *testing.T) {
time.Sleep(210 * time.Millisecond)
assert.Equal(t, 0, lc.keys())
assert.Equal(t, []string{}, lc.Keys())

}

func TestExpirableCache_MaxKeys(t *testing.T) {
Expand Down
68 changes: 39 additions & 29 deletions redis_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,58 +29,64 @@ type fakeString string

func TestExpirableRedisCache(t *testing.T) {
server := newTestRedisServer()
defer server.Close()
client := redis.NewClient(&redis.Options{
Addr: server.Addr()})
lc, err := NewRedisCache(client, MaxKeys(5), TTL(time.Second*6))
defer client.Close()
rc, err := NewRedisCache(client, MaxKeys(5), TTL(time.Second*6))
if err != nil {
log.Fatalf("can't make redis cache, %v", err)
}
defer rc.Close()
require.NoError(t, err)
for i := 0; i < 5; i++ {
i := i
_, e := lc.Get(fmt.Sprintf("key-%d", i), func() (Value, error) {
_, e := rc.Get(fmt.Sprintf("key-%d", i), func() (Value, error) {
return fmt.Sprintf("result-%d", i), nil
})
assert.NoError(t, e)
server.FastForward(1000 * time.Millisecond)
}

assert.Equal(t, 5, lc.Stat().Keys)
assert.Equal(t, int64(5), lc.Stat().Misses)
assert.Equal(t, 5, rc.Stat().Keys)
assert.Equal(t, int64(5), rc.Stat().Misses)

keys := lc.Keys()[:]
keys := rc.Keys()[:]
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
assert.EqualValues(t, []string{"key-0", "key-1", "key-2", "key-3", "key-4"}, keys)

_, e := lc.Get("key-xx", func() (Value, error) {
_, e := rc.Get("key-xx", func() (Value, error) {
return "result-xx", nil
})
assert.NoError(t, e)
assert.Equal(t, 5, lc.Stat().Keys)
assert.Equal(t, int64(6), lc.Stat().Misses)
assert.Equal(t, 5, rc.Stat().Keys)
assert.Equal(t, int64(6), rc.Stat().Misses)

server.FastForward(1000 * time.Millisecond)
assert.Equal(t, 4, lc.Stat().Keys)
assert.Equal(t, 4, rc.Stat().Keys)

server.FastForward(4000 * time.Millisecond)
assert.Equal(t, 0, lc.keys())
assert.Equal(t, 0, rc.keys())

}

func TestRedisCache(t *testing.T) {
var coldCalls int32

server := newTestRedisServer()
defer server.Close()
client := redis.NewClient(&redis.Options{
Addr: server.Addr()})
lc, err := NewRedisCache(client, MaxKeys(5), MaxValSize(10), MaxKeySize(10))
defer client.Close()
rc, err := NewRedisCache(client, MaxKeys(5), MaxValSize(10), MaxKeySize(10))
if err != nil {
log.Fatalf("can't make redis cache, %v", err)
}
defer rc.Close()
// put 5 keys to cache
for i := 0; i < 5; i++ {
i := i
res, e := lc.Get(fmt.Sprintf("key-%d", i), func() (Value, error) {
res, e := rc.Get(fmt.Sprintf("key-%d", i), func() (Value, error) {
atomic.AddInt32(&coldCalls, 1)
return fmt.Sprintf("result-%d", i), nil
})
Expand All @@ -90,83 +96,87 @@ func TestRedisCache(t *testing.T) {
}

// check if really cached
res, err := lc.Get("key-3", func() (Value, error) {
res, err := rc.Get("key-3", func() (Value, error) {
return "result-blah", nil
})
assert.NoError(t, err)
assert.Equal(t, "result-3", res.(string), "should be cached")

// try to cache after maxKeys reached
res, err = lc.Get("key-X", func() (Value, error) {
res, err = rc.Get("key-X", func() (Value, error) {
return "result-X", nil
})
assert.NoError(t, err)
assert.Equal(t, "result-X", res.(string))
assert.Equal(t, int64(5), lc.backend.DBSize().Val())
assert.Equal(t, int64(5), rc.backend.DBSize().Val())

// put to cache and make sure it cached
res, err = lc.Get("key-Z", func() (Value, error) {
res, err = rc.Get("key-Z", func() (Value, error) {
return "result-Z", nil
})
assert.NoError(t, err)
assert.Equal(t, "result-Z", res.(string))

res, err = lc.Get("key-Z", func() (Value, error) {
res, err = rc.Get("key-Z", func() (Value, error) {
return "result-Zzzz", nil
})
assert.NoError(t, err)
assert.Equal(t, "result-Zzzz", res.(string), "got non-cached value")
assert.Equal(t, 5, lc.keys())
assert.Equal(t, 5, rc.keys())

res, err = lc.Get("key-Zzzzzzz", func() (Value, error) {
res, err = rc.Get("key-Zzzzzzz", func() (Value, error) {
return "result-Zzzz", nil
})
assert.NoError(t, err)
assert.Equal(t, "result-Zzzz", res.(string), "got non-cached value")
assert.Equal(t, 5, lc.keys())
assert.Equal(t, 5, rc.keys())

res, ok := lc.Peek("error-key-Z2")
res, ok := rc.Peek("error-key-Z2")
assert.False(t, ok)
assert.Nil(t, res)
}

func TestRedisCacheErrors(t *testing.T) {

server := newTestRedisServer()
defer server.Close()
client := redis.NewClient(&redis.Options{
Addr: server.Addr()})
lc, err := NewRedisCache(client)
defer client.Close()
rc, err := NewRedisCache(client)
if err != nil {
log.Fatalf("can't make redis cache, %v", err)
}
defer rc.Close()

res, err := lc.Get("error-key-Z", func() (Value, error) {
res, err := rc.Get("error-key-Z", func() (Value, error) {
return "error-result-Z", errors.New("some error")
})
assert.Error(t, err)
assert.Equal(t, "error-result-Z", res.(string))
assert.Equal(t, int64(1), lc.Stat().Errors)
assert.Equal(t, int64(1), rc.Stat().Errors)

res, err = lc.Get("error-key-Z2", func() (Value, error) {
res, err = rc.Get("error-key-Z2", func() (Value, error) {
return fakeString("error-result-Z2"), nil
})
assert.Error(t, err)
assert.Equal(t, fakeString("error-result-Z2"), res.(fakeString))
assert.Equal(t, int64(2), lc.Stat().Errors)
assert.Equal(t, int64(2), rc.Stat().Errors)

server.Close()
res, err = lc.Get("error-key-Z3", func() (Value, error) {
res, err = rc.Get("error-key-Z3", func() (Value, error) {
return fakeString("error-result-Z3"), nil
})
assert.Error(t, err)
assert.Equal(t, "", res.(string))
assert.Equal(t, int64(3), lc.Stat().Errors)
assert.Equal(t, int64(3), rc.Stat().Errors)
}

func TestRedisCache_BadOptions(t *testing.T) {
server := newTestRedisServer()
defer server.Close()
client := redis.NewClient(&redis.Options{
Addr: server.Addr()})
defer client.Close()

_, err := NewRedisCache(client, MaxCacheSize(-1))
assert.EqualError(t, err, "failed to set cache option: negative max cache size")
Expand Down
1 change: 0 additions & 1 deletion scache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ func TestScope_Key(t *testing.T) {
}

func TestScache_Parallel(t *testing.T) {

var coldCalls int32
lru, err := NewLruCache()
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 6f83ced

Please sign in to comment.