Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / cache / cache_test.go
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.
4
5 package cache
6
7 import (
8         "math"
9         "testing"
10         "time"
11 )
12
13 // Tests against a generic Cache interface.
14 // They should pass for all implementations.
15 type cacheFactory func(*testing.T, time.Duration) Cache
16
17 // Test typical cache interactions
18 func typicalGetSet(t *testing.T, newCache cacheFactory) {
19         var err error
20         cache := newCache(t, time.Hour)
21
22         value := "foo"
23         if err = cache.Set("value", value, DefaultExpiryTime); err != nil {
24                 t.Errorf("Error setting a value: %s", err)
25         }
26
27         value = ""
28         err = cache.Get("value", &value)
29         if err != nil {
30                 t.Errorf("Error getting a value: %s", err)
31         }
32         if value != "foo" {
33                 t.Errorf("Expected to get foo back, got %s", value)
34         }
35 }
36
37 // Test the increment-decrement cases
38 func incrDecr(t *testing.T, newCache cacheFactory) {
39         var err error
40         cache := newCache(t, time.Hour)
41
42         // Normal increment / decrement operation.
43         if err = cache.Set("int", 10, ForEverNeverExpiry); err != nil {
44                 t.Errorf("Error setting int: %s", err)
45         }
46         time.Sleep(time.Second)
47         newValue, err := cache.Increment("int", 50)
48         if err != nil {
49                 t.Errorf("Error incrementing int: %s", err)
50         }
51         if newValue != 60 {
52                 t.Errorf("Expected 60, was %d", newValue)
53         }
54
55         if newValue, err = cache.Decrement("int", 50); err != nil {
56                 t.Errorf("Error decrementing: %s", err)
57         }
58         if newValue != 10 {
59                 t.Errorf("Expected 10, was %d", newValue)
60         }
61
62         // Increment wraparound
63         newValue, err = cache.Increment("int", math.MaxUint64-5)
64         if err != nil {
65                 t.Errorf("Error wrapping around: %s", err)
66         }
67         if newValue != 4 {
68                 t.Errorf("Expected wraparound 4, got %d", newValue)
69         }
70
71         // Decrement capped at 0
72         newValue, err = cache.Decrement("int", 25)
73         if err != nil {
74                 t.Errorf("Error decrementing below 0: %s", err)
75         }
76         if newValue != 0 {
77                 t.Errorf("Expected capped at 0, got %d", newValue)
78         }
79 }
80
81 func expiration(t *testing.T, newCache cacheFactory) {
82         // memcached does not support expiration times less than 1 second.
83         var err error
84         cache := newCache(t, time.Second)
85         // Test Set w/ DefaultExpiryTime
86         value := 10
87         if err = cache.Set("int", value, DefaultExpiryTime); err != nil {
88                 t.Errorf("Set failed: %s", err)
89         }
90         time.Sleep(2 * time.Second)
91         if err = cache.Get("int", &value); err != ErrCacheMiss {
92                 t.Errorf("Expected CacheMiss, but got: %s", err)
93         }
94
95         // Test Set w/ short time
96         if err = cache.Set("int", value, time.Second); err != nil {
97                 t.Errorf("Set failed: %s", err)
98         }
99         time.Sleep(2 * time.Second)
100         if err = cache.Get("int", &value); err != ErrCacheMiss {
101                 t.Errorf("Expected CacheMiss, but got: %s", err)
102         }
103
104         // Test Set w/ longer time.
105         if err = cache.Set("int", value, time.Hour); err != nil {
106                 t.Errorf("Set failed: %s", err)
107         }
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)
111         }
112
113         // Test Set w/ forever.
114         if err = cache.Set("int", value, ForEverNeverExpiry); err != nil {
115                 t.Errorf("Set failed: %s", err)
116         }
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)
120         }
121 }
122
123 func emptyCache(t *testing.T, newCache cacheFactory) {
124         var err error
125         cache := newCache(t, time.Hour)
126
127         err = cache.Get("notexist", 0)
128         if err == nil {
129                 t.Errorf("Error expected for non-existent key")
130         }
131         if err != ErrCacheMiss {
132                 t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
133         }
134
135         err = cache.Delete("notexist")
136         if err != ErrCacheMiss {
137                 t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
138         }
139
140         _, err = cache.Increment("notexist", 1)
141         if err != ErrCacheMiss {
142                 t.Errorf("Expected cache miss incrementing non-existent key: %s", err)
143         }
144
145         _, err = cache.Decrement("notexist", 1)
146         if err != ErrCacheMiss {
147                 t.Errorf("Expected cache miss decrementing non-existent key: %s", err)
148         }
149 }
150
151 func testReplace(t *testing.T, newCache cacheFactory) {
152         var err error
153         cache := newCache(t, time.Hour)
154
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)
158         }
159
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)
163         }
164
165         if err = cache.Replace("int", 2, time.Second); err != nil {
166                 t.Errorf("Unexpected error: %s", err)
167         }
168         var i int
169         if err = cache.Get("int", &i); err != nil {
170                 t.Errorf("Unexpected error getting a replaced item: %s", err)
171         }
172         if i != 2 {
173                 t.Errorf("Expected 2, got %d", i)
174         }
175
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)
180         }
181         if err = cache.Get("int", &i); err != ErrCacheMiss {
182                 t.Errorf("Expected cache miss, got: %s", err)
183         }
184 }
185
186 func testAdd(t *testing.T, newCache cacheFactory) {
187         var err error
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)
192         }
193
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)
198                 }
199         }
200
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)
205         }
206
207         // Get and verify the value.
208         var i int
209         if err = cache.Get("int", &i); err != nil {
210                 t.Errorf("Unexpected error: %s", err)
211         }
212         if i != 3 {
213                 t.Errorf("Expected 3, got: %d", i)
214         }
215 }
216
217 func testGetMulti(t *testing.T, newCache cacheFactory) {
218         cache := newCache(t, time.Hour)
219
220         m := map[string]interface{}{
221                 "str": "foo",
222                 "num": 42,
223                 "foo": struct{ Bar string }{"baz"},
224         }
225
226         var keys []string
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)
231                 }
232         }
233
234         g, err := cache.GetMulti(keys...)
235         if err != nil {
236                 t.Errorf("Error in get-multi: %s", err)
237         }
238
239         var str string
240         if err = g.Get("str", &str); err != nil || str != "foo" {
241                 t.Errorf("Error getting str: %s / %s", err, str)
242         }
243
244         var num int
245         if err = g.Get("num", &num); err != nil || num != 42 {
246                 t.Errorf("Error getting num: %s / %v", err, num)
247         }
248
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)
252         }
253 }