New unit tests for timedCache

This commit is contained in:
Pengfei Ni 2018-02-07 17:05:51 +08:00
parent 259dbf8da7
commit 035c8da63d

View File

@ -17,80 +17,123 @@ limitations under the License.
package azure package azure
import ( import (
"sync/atomic" "sync"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
) )
func TestCacheReturnsSameObject(t *testing.T) { var (
type cacheTestingStruct struct{} fakeCacheTTL = 2 * time.Second
c := newTimedcache(1 * time.Minute) )
o1 := cacheTestingStruct{}
get1, _ := c.GetOrCreate("b1", func() interface{} { type fakeDataObj struct{}
return o1
}) type fakeDataSource struct {
o2 := cacheTestingStruct{} data map[string]*fakeDataObj
get2, _ := c.GetOrCreate("b1", func() interface{} { lock sync.Mutex
return o2
})
if get1 != get2 {
t.Error("Get not equal")
}
} }
func TestCacheCallsCreateFuncOnce(t *testing.T) { func (fake *fakeDataSource) get(key string) (interface{}, error) {
var callsCount uint32 fake.lock.Lock()
f1 := func() interface{} { defer fake.lock.Unlock()
atomic.AddUint32(&callsCount, 1)
return 1 if v, ok := fake.data[key]; ok {
} return v, nil
c := newTimedcache(500 * time.Millisecond)
for index := 0; index < 20; index++ {
_, _ = c.GetOrCreate("b1", f1)
} }
if callsCount != 1 { return nil, nil
t.Error("Count not match")
}
time.Sleep(500 * time.Millisecond)
c.GetOrCreate("b1", f1)
if callsCount != 2 {
t.Error("Count not match")
}
} }
func TestCacheExpires(t *testing.T) { func (fake *fakeDataSource) set(data map[string]*fakeDataObj) {
f1 := func() interface{} { fake.lock.Lock()
return 1 defer fake.lock.Unlock()
fake.data = data
}
func newFakeCache(t *testing.T) (*fakeDataSource, *timedCache) {
dataSource := &fakeDataSource{
data: make(map[string]*fakeDataObj),
} }
c := newTimedcache(500 * time.Millisecond) getter := dataSource.get
get1, _ := c.GetOrCreate("b1", f1) cache, err := newTimedcache(fakeCacheTTL, getter)
if get1 != 1 { assert.NoError(t, err)
t.Error("Value not equal") return dataSource, cache
}
func TestCacheGet(t *testing.T) {
val := &fakeDataObj{}
cases := []struct {
name string
data map[string]*fakeDataObj
key string
expected interface{}
}{
{
name: "cache should return nil for empty data source",
key: "key1",
expected: nil,
},
{
name: "cache should return nil for non exist key",
data: map[string]*fakeDataObj{"key2": val},
key: "key1",
expected: nil,
},
{
name: "cache should return data for existing key",
data: map[string]*fakeDataObj{"key1": val},
key: "key1",
expected: val,
},
} }
time.Sleep(500 * time.Millisecond)
get1, _ = c.GetOrCreate("b1", nil) for _, c := range cases {
if get1 != nil { dataSource, cache := newFakeCache(t)
t.Error("value not expired") dataSource.set(c.data)
val, err := cache.Get(c.key)
assert.NoError(t, err, c.name)
assert.Equal(t, c.expected, val, c.name)
} }
} }
func TestCacheDelete(t *testing.T) { func TestCacheDelete(t *testing.T) {
f1 := func() interface{} { key := "key1"
return 1 val := &fakeDataObj{}
} data := map[string]*fakeDataObj{
c := newTimedcache(500 * time.Millisecond) key: val,
get1, _ := c.GetOrCreate("b1", f1)
if get1 != 1 {
t.Error("Value not equal")
}
get1, _ = c.GetOrCreate("b1", nil)
if get1 != 1 {
t.Error("Value not equal")
}
c.Delete("b1")
get1, _ = c.GetOrCreate("b1", nil)
if get1 != nil {
t.Error("value not deleted")
} }
dataSource, cache := newFakeCache(t)
dataSource.set(data)
v, err := cache.Get(key)
assert.NoError(t, err)
assert.Equal(t, val, v, "cache should get correct data")
dataSource.set(nil)
cache.Delete(key)
v, err = cache.Get(key)
assert.NoError(t, err)
assert.Equal(t, nil, v, "cache should get nil after data is removed")
}
func TestCacheExpired(t *testing.T) {
key := "key1"
val := &fakeDataObj{}
data := map[string]*fakeDataObj{
key: val,
}
dataSource, cache := newFakeCache(t)
dataSource.set(data)
v, err := cache.Get(key)
assert.NoError(t, err)
assert.Equal(t, val, v, "cache should get correct data")
time.Sleep(fakeCacheTTL)
v, err = cache.Get(key)
assert.NoError(t, err)
assert.Equal(t, val, v, "cache should get correct data even after expired")
} }