github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/lib/cache/cache_test.go (about) 1 package cache 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 var ( 14 called = 0 15 errSentinel = errors.New("an error") 16 errCached = errors.New("a cached error") 17 ) 18 19 func setup(t *testing.T) (*Cache, CreateFunc) { 20 called = 0 21 create := func(path string) (interface{}, bool, error) { 22 assert.Equal(t, 0, called) 23 called++ 24 switch path { 25 case "/": 26 return "/", true, nil 27 case "/file.txt": 28 return "/file.txt", true, errCached 29 case "/error": 30 return nil, false, errSentinel 31 } 32 panic(fmt.Sprintf("Unknown path %q", path)) 33 } 34 c := New() 35 return c, create 36 } 37 38 func TestGet(t *testing.T) { 39 c, create := setup(t) 40 41 assert.Equal(t, 0, len(c.cache)) 42 43 f, err := c.Get("/", create) 44 require.NoError(t, err) 45 46 assert.Equal(t, 1, len(c.cache)) 47 48 f2, err := c.Get("/", create) 49 require.NoError(t, err) 50 51 assert.Equal(t, f, f2) 52 } 53 54 func TestGetFile(t *testing.T) { 55 c, create := setup(t) 56 57 assert.Equal(t, 0, len(c.cache)) 58 59 f, err := c.Get("/file.txt", create) 60 require.Equal(t, errCached, err) 61 62 assert.Equal(t, 1, len(c.cache)) 63 64 f2, err := c.Get("/file.txt", create) 65 require.Equal(t, errCached, err) 66 67 assert.Equal(t, f, f2) 68 } 69 70 func TestGetError(t *testing.T) { 71 c, create := setup(t) 72 73 assert.Equal(t, 0, len(c.cache)) 74 75 f, err := c.Get("/error", create) 76 require.Equal(t, errSentinel, err) 77 require.Equal(t, nil, f) 78 79 assert.Equal(t, 0, len(c.cache)) 80 } 81 82 func TestPut(t *testing.T) { 83 c, create := setup(t) 84 85 assert.Equal(t, 0, len(c.cache)) 86 87 c.Put("/alien", "slime") 88 89 assert.Equal(t, 1, len(c.cache)) 90 91 fNew, err := c.Get("/alien", create) 92 require.NoError(t, err) 93 require.Equal(t, "slime", fNew) 94 95 assert.Equal(t, 1, len(c.cache)) 96 } 97 98 func TestCacheExpire(t *testing.T) { 99 c, create := setup(t) 100 101 c.expireInterval = time.Millisecond 102 assert.Equal(t, false, c.expireRunning) 103 104 _, err := c.Get("/", create) 105 require.NoError(t, err) 106 107 c.mu.Lock() 108 entry := c.cache["/"] 109 assert.Equal(t, 1, len(c.cache)) 110 c.mu.Unlock() 111 112 c.cacheExpire() 113 114 c.mu.Lock() 115 assert.Equal(t, 1, len(c.cache)) 116 entry.lastUsed = time.Now().Add(-c.expireDuration - 60*time.Second) 117 assert.Equal(t, true, c.expireRunning) 118 c.mu.Unlock() 119 120 time.Sleep(250 * time.Millisecond) 121 122 c.mu.Lock() 123 assert.Equal(t, false, c.expireRunning) 124 assert.Equal(t, 0, len(c.cache)) 125 c.mu.Unlock() 126 } 127 128 func TestCachePin(t *testing.T) { 129 c, create := setup(t) 130 131 _, err := c.Get("/", create) 132 require.NoError(t, err) 133 134 // Pin a non existent item to show nothing happens 135 c.Pin("notfound") 136 137 c.mu.Lock() 138 entry := c.cache["/"] 139 assert.Equal(t, 1, len(c.cache)) 140 c.mu.Unlock() 141 142 c.cacheExpire() 143 144 c.mu.Lock() 145 assert.Equal(t, 1, len(c.cache)) 146 c.mu.Unlock() 147 148 // Pin the entry and check it does not get expired 149 c.Pin("/") 150 151 // Reset last used to make the item expirable 152 c.mu.Lock() 153 entry.lastUsed = time.Now().Add(-c.expireDuration - 60*time.Second) 154 c.mu.Unlock() 155 156 c.cacheExpire() 157 158 c.mu.Lock() 159 assert.Equal(t, 1, len(c.cache)) 160 c.mu.Unlock() 161 162 // Unpin the entry and check it does get expired now 163 c.Unpin("/") 164 165 // Reset last used 166 c.mu.Lock() 167 entry.lastUsed = time.Now().Add(-c.expireDuration - 60*time.Second) 168 c.mu.Unlock() 169 170 c.cacheExpire() 171 172 c.mu.Lock() 173 assert.Equal(t, 0, len(c.cache)) 174 c.mu.Unlock() 175 } 176 177 func TestClear(t *testing.T) { 178 c, create := setup(t) 179 180 assert.Equal(t, 0, len(c.cache)) 181 182 _, err := c.Get("/", create) 183 require.NoError(t, err) 184 185 assert.Equal(t, 1, len(c.cache)) 186 187 c.Clear() 188 189 assert.Equal(t, 0, len(c.cache)) 190 } 191 192 func TestEntries(t *testing.T) { 193 c, create := setup(t) 194 195 assert.Equal(t, 0, c.Entries()) 196 197 _, err := c.Get("/", create) 198 require.NoError(t, err) 199 200 assert.Equal(t, 1, c.Entries()) 201 202 c.Clear() 203 204 assert.Equal(t, 0, c.Entries()) 205 } 206 207 func TestGetMaybe(t *testing.T) { 208 c, create := setup(t) 209 210 value, found := c.GetMaybe("/") 211 assert.Equal(t, false, found) 212 assert.Nil(t, value) 213 214 f, err := c.Get("/", create) 215 require.NoError(t, err) 216 217 value, found = c.GetMaybe("/") 218 assert.Equal(t, true, found) 219 assert.Equal(t, f, value) 220 221 c.Clear() 222 223 value, found = c.GetMaybe("/") 224 assert.Equal(t, false, found) 225 assert.Nil(t, value) 226 } 227 228 func TestCacheRename(t *testing.T) { 229 c := New() 230 create := func(path string) (interface{}, bool, error) { 231 return path, true, nil 232 } 233 234 existing1, err := c.Get("existing1", create) 235 require.NoError(t, err) 236 _, err = c.Get("existing2", create) 237 require.NoError(t, err) 238 239 assert.Equal(t, 2, c.Entries()) 240 241 // rename to non existent 242 value, found := c.Rename("existing1", "EXISTING1") 243 assert.Equal(t, true, found) 244 assert.Equal(t, existing1, value) 245 246 assert.Equal(t, 2, c.Entries()) 247 248 // rename to existent and check existing value is returned 249 value, found = c.Rename("existing2", "EXISTING1") 250 assert.Equal(t, true, found) 251 assert.Equal(t, existing1, value) 252 253 assert.Equal(t, 1, c.Entries()) 254 255 // rename non existent 256 value, found = c.Rename("notfound", "NOTFOUND") 257 assert.Equal(t, false, found) 258 assert.Nil(t, value) 259 260 assert.Equal(t, 1, c.Entries()) 261 }