diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..811507c --- /dev/null +++ b/helpers.go @@ -0,0 +1,40 @@ +package cache + +import ( + "time" +) + +type timeOutResult struct { + r interface{} + e error +} + +func WithTimeout(f cacheGetterFunc, t time.Duration, err error) cacheGetterFunc { + return func(v interface{}) (interface{}, error) { + c := make(chan timeOutResult) + go func() { + r, e := f(v) + c <- timeOutResult{r, e} + }() + select { + case r := <-c: + return r.r, r.e + case <-time.After(t): + } + return nil, err + } +} + +func WithRetry(f cacheGetterFunc, n int) cacheGetterFunc { + return func(v interface{}) (interface{}, error) { + var lastError error + for i := 0; i < n; i++ { + r, e := f(v) + if e == nil { + return r, e + } + lastError = e + } + return nil, lastError + } +} diff --git a/helpers_test.go b/helpers_test.go new file mode 100644 index 0000000..51df1b9 --- /dev/null +++ b/helpers_test.go @@ -0,0 +1,53 @@ +package cache + +import ( + "errors" + "testing" + "time" +) + +func TestTimeout(t *testing.T) { + // Func which waits v and returns OK + f := func(v interface{}) (interface{}, error) { + time.Sleep(v.(time.Duration)) + return "OK", nil + } + + // Returns err if call is more than 100ms + f = WithTimeout(f, 100*time.Millisecond, errors.New("timed out")) + + // Call with 50ms, should return 'OK' + if v, e := f(50 * time.Millisecond); v.(string) != "OK" || e != nil { + t.Fatalf("Should have returned OK, nil; received: %v, %v", v, e) + } + + // Call with 200ms, should return 'timed out' + if v, e := f(200 * time.Millisecond); v != nil || e == nil || e.Error() != "timed out" { + t.Fatalf("Should have returned nil, 'timed out'; received: %v, %v", v, e) + } +} + +func TestRetry(t *testing.T) { + nbCalled := 0 + // Func which returns OK only at the second call + f := func(v interface{}) (interface{}, error) { + nbCalled++ + if nbCalled == 2 { + return "OK", nil + } + return nil, errors.New("not second") + } + + // Try to call func 3 times + f = WithRetry(f, 3) + + // First try, should call the function 2 times and return success + if v, e := f(nil); nbCalled != 2 || v.(string) != "OK" || e != nil { + t.Fatalf("Should have returned 2, OK, nil; received: %v, %v, %v", nbCalled, v, e) + } + + // Second try, should call the function 3 times and return error + if v, e := f(nil); nbCalled != 5 || v != nil || e == nil || e.Error() != "not second" { + t.Fatalf("Should have returned 5, nil, 'not second'; received: %v, %v, %v", nbCalled, v, e) + } +}