Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace runtime panics with bundled errors #44

Closed
wants to merge 12 commits into from
34 changes: 26 additions & 8 deletions arc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import (
"time"
)

func buildARCache(size int) Cache {
func buildARCache(size int) (Cache, error) {
return New(size).
ARC().
EvictedFunc(evictedFuncForARC).
Build()
}

func buildLoadingARCache(size int) Cache {
func buildLoadingARCache(size int) (Cache, error) {
return New(size).
ARC().
LoaderFunc(loader).
EvictedFunc(evictedFuncForARC).
Build()
}

func buildLoadingARCacheWithExpiration(size int, ep time.Duration) Cache {
func buildLoadingARCacheWithExpiration(size int, ep time.Duration) (Cache, error) {
return New(size).
ARC().
Expiration(ep).
Expand All @@ -36,19 +36,30 @@ func evictedFuncForARC(key, value interface{}) {

func TestARCGet(t *testing.T) {
size := 1000
gc := buildARCache(size)
gc, err := buildARCache(size)
if err != nil {
t.Error(err)
}
testSetCache(t, gc, size)
testGetCache(t, gc, size)
}

func TestLoadingARCGet(t *testing.T) {
size := 1000
numbers := 1000
testGetCache(t, buildLoadingARCache(size), numbers)
gc, err := buildLoadingARCache(size)
if err != nil {
t.Error(err)
}
testGetCache(t, gc, numbers)
}

func TestARCLength(t *testing.T) {
gc := buildLoadingARCacheWithExpiration(2, time.Millisecond)
gc, err := buildLoadingARCacheWithExpiration(2, time.Millisecond)
if err != nil {
t.Error(err)
}

gc.Get("test1")
gc.Get("test2")
gc.Get("test3")
Expand All @@ -69,7 +80,10 @@ func TestARCLength(t *testing.T) {
func TestARCEvictItem(t *testing.T) {
cacheSize := 10
numbers := cacheSize + 1
gc := buildLoadingARCache(cacheSize)
gc, err := buildLoadingARCache(cacheSize)
if err != nil {
t.Error(err)
}

for i := 0; i < numbers; i++ {
_, err := gc.Get(fmt.Sprintf("Key-%d", i))
Expand All @@ -82,14 +96,18 @@ func TestARCEvictItem(t *testing.T) {
func TestARCPurgeCache(t *testing.T) {
cacheSize := 10
purgeCount := 0
gc := New(cacheSize).
gc, err := New(cacheSize).
ARC().
LoaderFunc(loader).
PurgeVisitorFunc(func(k, v interface{}) {
purgeCount++
}).
Build()

if err != nil {
t.Error(err)
}

for i := 0; i < cacheSize; i++ {
_, err := gc.Get(fmt.Sprintf("Key-%d", i))
if err != nil {
Expand Down
18 changes: 10 additions & 8 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const (
)

var KeyNotFoundError = errors.New("Key not found.")
var InvalidCacheSizeError = errors.New("Invalid Cache size")
var UnknownCacheTypeError = errors.New("Unknown Cache type")

type Cache interface {
Set(interface{}, interface{}) error
Expand Down Expand Up @@ -151,26 +153,26 @@ func (cb *CacheBuilder) Expiration(expiration time.Duration) *CacheBuilder {
return cb
}

func (cb *CacheBuilder) Build() Cache {
func (cb *CacheBuilder) Build() (Cache, error) {
if cb.size <= 0 && cb.tp != TYPE_SIMPLE {
panic("gcache: Cache size <= 0")
return newSimpleCache(cb), InvalidCacheSizeError
}

return cb.build()
}

func (cb *CacheBuilder) build() Cache {
func (cb *CacheBuilder) build() (Cache, error) {
switch cb.tp {
case TYPE_SIMPLE:
return newSimpleCache(cb)
return newSimpleCache(cb), nil
case TYPE_LRU:
return newLRUCache(cb)
return newLRUCache(cb), nil
case TYPE_LFU:
return newLFUCache(cb)
return newLFUCache(cb), nil
case TYPE_ARC:
return newARC(cb)
return newARC(cb), nil
default:
panic("gcache: Unknown type " + cb.tp)
return newSimpleCache(cb), UnknownCacheTypeError
}
}

Expand Down
59 changes: 54 additions & 5 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,36 @@ import (
"time"
)

func TestInvalidCacheSize(t *testing.T) {
var invalidBuilders = []*CacheBuilder{
New(0).ARC(),
New(-1).ARC(),
New(0).LFU(),
New(-1).LFU(),
New(0).LRU(),
New(-1).LRU(),
}

for _, builder := range invalidBuilders {
_, err := builder.Build()
if err == nil {
t.Errorf("Building a %v-cache with size %v should fail", builder.tp, builder.size)
}
}

var validBuilders = []*CacheBuilder{
New(0).Simple(),
New(-1).Simple(),
}

for _, builder := range validBuilders {
_, err := builder.Build()
if err != nil {
t.Errorf("Build a SimpleCache with size %v <= 0 is a valid operation", builder.size)
}
}
}

func TestLoaderFunc(t *testing.T) {
size := 2
var testCaches = []*CacheBuilder{
Expand All @@ -20,7 +50,7 @@ func TestLoaderFunc(t *testing.T) {
for _, builder := range testCaches {
var testCounter int64
counter := 1000
cache := builder.
cache, err := builder.
LoaderFunc(func(key interface{}) (interface{}, error) {
time.Sleep(10 * time.Millisecond)
return atomic.AddInt64(&testCounter, 1), nil
Expand All @@ -29,6 +59,10 @@ func TestLoaderFunc(t *testing.T) {
panic(key)
}).Build()

if err != nil {
t.Error(err)
}

var wg sync.WaitGroup
for i := 0; i < counter; i++ {
wg.Add(1)
Expand Down Expand Up @@ -59,14 +93,17 @@ func TestLoaderExpireFuncWithoutExpire(t *testing.T) {
for _, builder := range testCaches {
var testCounter int64
counter := 1000
cache := builder.
cache, err := builder.
LoaderExpireFunc(func(key interface{}) (interface{}, *time.Duration, error) {
return atomic.AddInt64(&testCounter, 1), nil, nil
}).
EvictedFunc(func(key, value interface{}) {
panic(key)
}).Build()

if err != nil {
t.Error(err)
}
var wg sync.WaitGroup
for i := 0; i < counter; i++ {
wg.Add(1)
Expand Down Expand Up @@ -99,12 +136,16 @@ func TestLoaderExpireFuncWithExpire(t *testing.T) {
var testCounter int64
counter := 1000
expire := 200 * time.Millisecond
cache := builder.
cache, err := builder.
LoaderExpireFunc(func(key interface{}) (interface{}, *time.Duration, error) {
return atomic.AddInt64(&testCounter, 1), &expire, nil
}).
Build()

if err != nil {
t.Error(err)
}

var wg sync.WaitGroup
for i := 0; i < counter; i++ {
wg.Add(1)
Expand Down Expand Up @@ -163,7 +204,7 @@ func TestLoaderPurgeVisitorFunc(t *testing.T) {
for _, test := range tests {
var purgeCounter, evictCounter, loaderCounter int64
counter := 1000
cache := test.cacheBuilder.
cache, err := test.cacheBuilder.
LoaderFunc(func(key interface{}) (interface{}, error) {
return atomic.AddInt64(&loaderCounter, 1), nil
}).
Expand All @@ -175,6 +216,10 @@ func TestLoaderPurgeVisitorFunc(t *testing.T) {
}).
Build()

if err != nil {
t.Error(err)
}

var wg sync.WaitGroup
for i := 0; i < counter; i++ {
i := i
Expand Down Expand Up @@ -218,7 +263,7 @@ func TestDeserializeFunc(t *testing.T) {
for _, cs := range cases {
key1, value1 := "key1", "value1"
key2, value2 := "key2", "value2"
cc := New(32).
cc, err := New(32).
EvictType(cs.tp).
LoaderFunc(func(k interface{}) (interface{}, error) {
return value1, nil
Expand All @@ -239,6 +284,10 @@ func TestDeserializeFunc(t *testing.T) {
return buf.Bytes(), err
}).
Build()

if err != nil {
t.Error(err)
}
v, err := cc.Get(key1)
if err != nil {
t.Fatal(err)
Expand Down
6 changes: 3 additions & 3 deletions examples/autoloading_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
)

func main() {
gc := gcache.New(10).
gc, _ := gcache.New(10).
LFU().
LoaderFunc(func(key interface{}) (interface{}, error) {
return fmt.Sprintf("%v-value", key), nil
}).
return fmt.Sprintf("%v-value", key), nil
}).
Build()

v, err := gc.Get("key")
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_expiration.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func main() {
gc := gcache.New(10).
gc, _ := gcache.New(10).
LFU().
Build()

Expand Down
2 changes: 1 addition & 1 deletion examples/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func main() {
gc := gcache.New(10).
gc, _ := gcache.New(10).
LFU().
Build()
gc.Set("key", "ok")
Expand Down
15 changes: 12 additions & 3 deletions helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func testSetCache(t *testing.T, gc Cache, numbers int) {
value, err := loader(key)
if err != nil {
t.Error(err)
return
}

gc.Set(key, value)
}
}
Expand All @@ -37,7 +37,7 @@ func testGetCache(t *testing.T, gc Cache, numbers int) {
}

func testGetIFPresent(t *testing.T, evT string) {
cache :=
cache, err :=
New(8).
EvictType(evT).
LoaderFunc(
Expand All @@ -46,6 +46,10 @@ func testGetIFPresent(t *testing.T, evT string) {
}).
Build()

if err != nil {
t.Error(err)
}

v, err := cache.GetIFPresent("key")
if err != KeyNotFoundError {
t.Errorf("err should not be %v", err)
Expand All @@ -64,11 +68,16 @@ func testGetIFPresent(t *testing.T, evT string) {

func testGetALL(t *testing.T, evT string) {
size := 8
cache :=
cache, err :=
New(size).
Expiration(time.Millisecond).
EvictType(evT).
Build()

if err != nil {
t.Error(err)
}

for i := 0; i < size; i++ {
cache.Set(i, i*i)
}
Expand Down
Loading