1 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
2 // Revel Framework source code and usage is governed by a MIT style
3 // license that can be found in the LICENSE file.
13 // Tests against a generic Cache interface.
14 // They should pass for all implementations.
15 type cacheFactory func(*testing.T, time.Duration) Cache
17 // Test typical cache interactions
18 func typicalGetSet(t *testing.T, newCache cacheFactory) {
20 cache := newCache(t, time.Hour)
23 if err = cache.Set("value", value, DefaultExpiryTime); err != nil {
24 t.Errorf("Error setting a value: %s", err)
28 err = cache.Get("value", &value)
30 t.Errorf("Error getting a value: %s", err)
33 t.Errorf("Expected to get foo back, got %s", value)
37 // Test the increment-decrement cases
38 func incrDecr(t *testing.T, newCache cacheFactory) {
40 cache := newCache(t, time.Hour)
42 // Normal increment / decrement operation.
43 if err = cache.Set("int", 10, ForEverNeverExpiry); err != nil {
44 t.Errorf("Error setting int: %s", err)
46 time.Sleep(time.Second)
47 newValue, err := cache.Increment("int", 50)
49 t.Errorf("Error incrementing int: %s", err)
52 t.Errorf("Expected 60, was %d", newValue)
55 if newValue, err = cache.Decrement("int", 50); err != nil {
56 t.Errorf("Error decrementing: %s", err)
59 t.Errorf("Expected 10, was %d", newValue)
62 // Increment wraparound
63 newValue, err = cache.Increment("int", math.MaxUint64-5)
65 t.Errorf("Error wrapping around: %s", err)
68 t.Errorf("Expected wraparound 4, got %d", newValue)
71 // Decrement capped at 0
72 newValue, err = cache.Decrement("int", 25)
74 t.Errorf("Error decrementing below 0: %s", err)
77 t.Errorf("Expected capped at 0, got %d", newValue)
81 func expiration(t *testing.T, newCache cacheFactory) {
82 // memcached does not support expiration times less than 1 second.
84 cache := newCache(t, time.Second)
85 // Test Set w/ DefaultExpiryTime
87 if err = cache.Set("int", value, DefaultExpiryTime); err != nil {
88 t.Errorf("Set failed: %s", err)
90 time.Sleep(2 * time.Second)
91 if err = cache.Get("int", &value); err != ErrCacheMiss {
92 t.Errorf("Expected CacheMiss, but got: %s", err)
95 // Test Set w/ short time
96 if err = cache.Set("int", value, time.Second); err != nil {
97 t.Errorf("Set failed: %s", err)
99 time.Sleep(2 * time.Second)
100 if err = cache.Get("int", &value); err != ErrCacheMiss {
101 t.Errorf("Expected CacheMiss, but got: %s", err)
104 // Test Set w/ longer time.
105 if err = cache.Set("int", value, time.Hour); err != nil {
106 t.Errorf("Set failed: %s", err)
108 time.Sleep(2 * time.Second)
109 if err = cache.Get("int", &value); err != nil {
110 t.Errorf("Expected to get the value, but got: %s", err)
113 // Test Set w/ forever.
114 if err = cache.Set("int", value, ForEverNeverExpiry); err != nil {
115 t.Errorf("Set failed: %s", err)
117 time.Sleep(2 * time.Second)
118 if err = cache.Get("int", &value); err != nil {
119 t.Errorf("Expected to get the value, but got: %s", err)
123 func emptyCache(t *testing.T, newCache cacheFactory) {
125 cache := newCache(t, time.Hour)
127 err = cache.Get("notexist", 0)
129 t.Errorf("Error expected for non-existent key")
131 if err != ErrCacheMiss {
132 t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
135 err = cache.Delete("notexist")
136 if err != ErrCacheMiss {
137 t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
140 _, err = cache.Increment("notexist", 1)
141 if err != ErrCacheMiss {
142 t.Errorf("Expected cache miss incrementing non-existent key: %s", err)
145 _, err = cache.Decrement("notexist", 1)
146 if err != ErrCacheMiss {
147 t.Errorf("Expected cache miss decrementing non-existent key: %s", err)
151 func testReplace(t *testing.T, newCache cacheFactory) {
153 cache := newCache(t, time.Hour)
155 // Replace in an empty cache.
156 if err = cache.Replace("notexist", 1, ForEverNeverExpiry); err != ErrNotStored {
157 t.Errorf("Replace in empty cache: expected ErrNotStored, got: %s", err)
160 // Set a value of 1, and replace it with 2
161 if err = cache.Set("int", 1, time.Second); err != nil {
162 t.Errorf("Unexpected error: %s", err)
165 if err = cache.Replace("int", 2, time.Second); err != nil {
166 t.Errorf("Unexpected error: %s", err)
169 if err = cache.Get("int", &i); err != nil {
170 t.Errorf("Unexpected error getting a replaced item: %s", err)
173 t.Errorf("Expected 2, got %d", i)
176 // Wait for it to expire and replace with 3 (unsuccessfully).
177 time.Sleep(2 * time.Second)
178 if err = cache.Replace("int", 3, time.Second); err != ErrNotStored {
179 t.Errorf("Expected ErrNotStored, got: %s", err)
181 if err = cache.Get("int", &i); err != ErrCacheMiss {
182 t.Errorf("Expected cache miss, got: %s", err)
186 func testAdd(t *testing.T, newCache cacheFactory) {
188 cache := newCache(t, time.Hour)
189 // Add to an empty cache.
190 if err = cache.Add("int", 1, time.Second*3); err != nil {
191 t.Errorf("Unexpected error adding to empty cache: %s", err)
194 // Try to add again. (fail)
195 if err = cache.Add("int", 2, time.Second*3); err != nil {
196 if err != ErrNotStored {
197 t.Errorf("Expected ErrNotStored adding dupe to cache: %s", err)
201 // Wait for it to expire, and add again.
202 time.Sleep(8 * time.Second)
203 if err = cache.Add("int", 3, time.Second*5); err != nil {
204 t.Errorf("Unexpected error adding to cache: %s", err)
207 // Get and verify the value.
209 if err = cache.Get("int", &i); err != nil {
210 t.Errorf("Unexpected error: %s", err)
213 t.Errorf("Expected 3, got: %d", i)
217 func testGetMulti(t *testing.T, newCache cacheFactory) {
218 cache := newCache(t, time.Hour)
220 m := map[string]interface{}{
223 "foo": struct{ Bar string }{"baz"},
227 for key, value := range m {
228 keys = append(keys, key)
229 if err := cache.Set(key, value, time.Second*30); err != nil {
230 t.Errorf("Error setting a value: %s", err)
234 g, err := cache.GetMulti(keys...)
236 t.Errorf("Error in get-multi: %s", err)
240 if err = g.Get("str", &str); err != nil || str != "foo" {
241 t.Errorf("Error getting str: %s / %s", err, str)
245 if err = g.Get("num", &num); err != nil || num != 42 {
246 t.Errorf("Error getting num: %s / %v", err, num)
249 var foo struct{ Bar string }
250 if err = g.Get("foo", &foo); err != nil || foo.Bar != "baz" {
251 t.Errorf("Error getting foo: %s / %v", err, foo)