Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / cache / cache_test.go
diff --git a/src/foundation/api/revel/cache/cache_test.go b/src/foundation/api/revel/cache/cache_test.go
new file mode 100644 (file)
index 0000000..bc54617
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
+// Revel Framework source code and usage is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package cache
+
+import (
+       "math"
+       "testing"
+       "time"
+)
+
+// Tests against a generic Cache interface.
+// They should pass for all implementations.
+type cacheFactory func(*testing.T, time.Duration) Cache
+
+// Test typical cache interactions
+func typicalGetSet(t *testing.T, newCache cacheFactory) {
+       var err error
+       cache := newCache(t, time.Hour)
+
+       value := "foo"
+       if err = cache.Set("value", value, DefaultExpiryTime); err != nil {
+               t.Errorf("Error setting a value: %s", err)
+       }
+
+       value = ""
+       err = cache.Get("value", &value)
+       if err != nil {
+               t.Errorf("Error getting a value: %s", err)
+       }
+       if value != "foo" {
+               t.Errorf("Expected to get foo back, got %s", value)
+       }
+}
+
+// Test the increment-decrement cases
+func incrDecr(t *testing.T, newCache cacheFactory) {
+       var err error
+       cache := newCache(t, time.Hour)
+
+       // Normal increment / decrement operation.
+       if err = cache.Set("int", 10, ForEverNeverExpiry); err != nil {
+               t.Errorf("Error setting int: %s", err)
+       }
+       time.Sleep(time.Second)
+       newValue, err := cache.Increment("int", 50)
+       if err != nil {
+               t.Errorf("Error incrementing int: %s", err)
+       }
+       if newValue != 60 {
+               t.Errorf("Expected 60, was %d", newValue)
+       }
+
+       if newValue, err = cache.Decrement("int", 50); err != nil {
+               t.Errorf("Error decrementing: %s", err)
+       }
+       if newValue != 10 {
+               t.Errorf("Expected 10, was %d", newValue)
+       }
+
+       // Increment wraparound
+       newValue, err = cache.Increment("int", math.MaxUint64-5)
+       if err != nil {
+               t.Errorf("Error wrapping around: %s", err)
+       }
+       if newValue != 4 {
+               t.Errorf("Expected wraparound 4, got %d", newValue)
+       }
+
+       // Decrement capped at 0
+       newValue, err = cache.Decrement("int", 25)
+       if err != nil {
+               t.Errorf("Error decrementing below 0: %s", err)
+       }
+       if newValue != 0 {
+               t.Errorf("Expected capped at 0, got %d", newValue)
+       }
+}
+
+func expiration(t *testing.T, newCache cacheFactory) {
+       // memcached does not support expiration times less than 1 second.
+       var err error
+       cache := newCache(t, time.Second)
+       // Test Set w/ DefaultExpiryTime
+       value := 10
+       if err = cache.Set("int", value, DefaultExpiryTime); err != nil {
+               t.Errorf("Set failed: %s", err)
+       }
+       time.Sleep(2 * time.Second)
+       if err = cache.Get("int", &value); err != ErrCacheMiss {
+               t.Errorf("Expected CacheMiss, but got: %s", err)
+       }
+
+       // Test Set w/ short time
+       if err = cache.Set("int", value, time.Second); err != nil {
+               t.Errorf("Set failed: %s", err)
+       }
+       time.Sleep(2 * time.Second)
+       if err = cache.Get("int", &value); err != ErrCacheMiss {
+               t.Errorf("Expected CacheMiss, but got: %s", err)
+       }
+
+       // Test Set w/ longer time.
+       if err = cache.Set("int", value, time.Hour); err != nil {
+               t.Errorf("Set failed: %s", err)
+       }
+       time.Sleep(2 * time.Second)
+       if err = cache.Get("int", &value); err != nil {
+               t.Errorf("Expected to get the value, but got: %s", err)
+       }
+
+       // Test Set w/ forever.
+       if err = cache.Set("int", value, ForEverNeverExpiry); err != nil {
+               t.Errorf("Set failed: %s", err)
+       }
+       time.Sleep(2 * time.Second)
+       if err = cache.Get("int", &value); err != nil {
+               t.Errorf("Expected to get the value, but got: %s", err)
+       }
+}
+
+func emptyCache(t *testing.T, newCache cacheFactory) {
+       var err error
+       cache := newCache(t, time.Hour)
+
+       err = cache.Get("notexist", 0)
+       if err == nil {
+               t.Errorf("Error expected for non-existent key")
+       }
+       if err != ErrCacheMiss {
+               t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
+       }
+
+       err = cache.Delete("notexist")
+       if err != ErrCacheMiss {
+               t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
+       }
+
+       _, err = cache.Increment("notexist", 1)
+       if err != ErrCacheMiss {
+               t.Errorf("Expected cache miss incrementing non-existent key: %s", err)
+       }
+
+       _, err = cache.Decrement("notexist", 1)
+       if err != ErrCacheMiss {
+               t.Errorf("Expected cache miss decrementing non-existent key: %s", err)
+       }
+}
+
+func testReplace(t *testing.T, newCache cacheFactory) {
+       var err error
+       cache := newCache(t, time.Hour)
+
+       // Replace in an empty cache.
+       if err = cache.Replace("notexist", 1, ForEverNeverExpiry); err != ErrNotStored {
+               t.Errorf("Replace in empty cache: expected ErrNotStored, got: %s", err)
+       }
+
+       // Set a value of 1, and replace it with 2
+       if err = cache.Set("int", 1, time.Second); err != nil {
+               t.Errorf("Unexpected error: %s", err)
+       }
+
+       if err = cache.Replace("int", 2, time.Second); err != nil {
+               t.Errorf("Unexpected error: %s", err)
+       }
+       var i int
+       if err = cache.Get("int", &i); err != nil {
+               t.Errorf("Unexpected error getting a replaced item: %s", err)
+       }
+       if i != 2 {
+               t.Errorf("Expected 2, got %d", i)
+       }
+
+       // Wait for it to expire and replace with 3 (unsuccessfully).
+       time.Sleep(2 * time.Second)
+       if err = cache.Replace("int", 3, time.Second); err != ErrNotStored {
+               t.Errorf("Expected ErrNotStored, got: %s", err)
+       }
+       if err = cache.Get("int", &i); err != ErrCacheMiss {
+               t.Errorf("Expected cache miss, got: %s", err)
+       }
+}
+
+func testAdd(t *testing.T, newCache cacheFactory) {
+       var err error
+       cache := newCache(t, time.Hour)
+       // Add to an empty cache.
+       if err = cache.Add("int", 1, time.Second*3); err != nil {
+               t.Errorf("Unexpected error adding to empty cache: %s", err)
+       }
+
+       // Try to add again. (fail)
+       if err = cache.Add("int", 2, time.Second*3); err != nil {
+               if err != ErrNotStored {
+                       t.Errorf("Expected ErrNotStored adding dupe to cache: %s", err)
+               }
+       }
+
+       // Wait for it to expire, and add again.
+       time.Sleep(8 * time.Second)
+       if err = cache.Add("int", 3, time.Second*5); err != nil {
+               t.Errorf("Unexpected error adding to cache: %s", err)
+       }
+
+       // Get and verify the value.
+       var i int
+       if err = cache.Get("int", &i); err != nil {
+               t.Errorf("Unexpected error: %s", err)
+       }
+       if i != 3 {
+               t.Errorf("Expected 3, got: %d", i)
+       }
+}
+
+func testGetMulti(t *testing.T, newCache cacheFactory) {
+       cache := newCache(t, time.Hour)
+
+       m := map[string]interface{}{
+               "str": "foo",
+               "num": 42,
+               "foo": struct{ Bar string }{"baz"},
+       }
+
+       var keys []string
+       for key, value := range m {
+               keys = append(keys, key)
+               if err := cache.Set(key, value, time.Second*30); err != nil {
+                       t.Errorf("Error setting a value: %s", err)
+               }
+       }
+
+       g, err := cache.GetMulti(keys...)
+       if err != nil {
+               t.Errorf("Error in get-multi: %s", err)
+       }
+
+       var str string
+       if err = g.Get("str", &str); err != nil || str != "foo" {
+               t.Errorf("Error getting str: %s / %s", err, str)
+       }
+
+       var num int
+       if err = g.Get("num", &num); err != nil || num != 42 {
+               t.Errorf("Error getting num: %s / %v", err, num)
+       }
+
+       var foo struct{ Bar string }
+       if err = g.Get("foo", &foo); err != nil || foo.Bar != "baz" {
+               t.Errorf("Error getting foo: %s / %v", err, foo)
+       }
+}