github.com/clysto/awgo@v0.15.0/cache_test.go (about) 1 // 2 // Copyright (c) 2017 Dean Jackson <deanishe@deanishe.net> 3 // 4 // MIT Licence. See http://opensource.org/licenses/MIT 5 // 6 // Created on 2017-08-08 7 // 8 9 package aw 10 11 import ( 12 "bytes" 13 "fmt" 14 "os" 15 "path/filepath" 16 "testing" 17 "time" 18 19 "github.com/deanishe/awgo/util" 20 ) 21 22 // WithTempDir creates a temporary directory, calls function fn, then deletes the directory. 23 func WithTempDir(fn func(dir string)) { 24 root := os.TempDir() 25 p := filepath.Join(root, fmt.Sprintf("awgo-%d.%d", os.Getpid(), time.Now().Nanosecond())) 26 util.MustExist(p) 27 defer os.RemoveAll(p) 28 fn(p) 29 } 30 31 // TestStoreAndLoad checks that data are stored and loaded correctly 32 func TestStoreAndLoad(t *testing.T) { 33 WithTempDir(func(dir string) { 34 c := NewCache(dir) 35 s := "this is a test" 36 n := "test.txt" 37 38 // Sanity checks 39 p := c.path(n) 40 if util.PathExists(p) { 41 t.Errorf("cache file already exists: %s", p) 42 } 43 44 // Delete non-existent store 45 if err := c.Store(n, nil); err != nil { 46 t.Errorf("unexpected error clearing cache: %v", err) 47 } 48 49 // Non-existent cache exists 50 if c.Exists(n) { 51 t.Errorf("non-existent cache exists") 52 } 53 54 // Non-existent cache has expired 55 if !c.Expired(n, 0) { 56 t.Errorf("non-existent cache hasn't expired") 57 } 58 59 // Store data 60 data := []byte(s) 61 if err := c.Store(n, data); err != nil { 62 t.Errorf("couldn't cache data to %s: %v", n, err) 63 } 64 if !util.PathExists(p) { 65 t.Errorf("cache file does not exist: %s", p) 66 } 67 68 if c.Exists(n) != util.PathExists(p) { 69 t.Errorf("cache file does not exist: %s", p) 70 } 71 72 // Load data 73 data2, err := c.Load(n) 74 if err != nil { 75 t.Errorf("couldn't load cached data: %v", err) 76 } 77 if bytes.Compare(data, data2) != 0 { 78 t.Errorf("loaded data does not match saved data: expected=%v, got=%v", data, data2) 79 } 80 81 // Data age 82 age, err := c.Age(n) 83 if err != nil { 84 t.Errorf("couldn't get age of cache %s: %v", n, err) 85 } 86 if age == 0 { 87 t.Errorf("age is zero") 88 } 89 90 // Delete data 91 if err := c.Store(n, nil); err != nil { 92 t.Errorf("couldn't delete cache %s: %v", p, err) 93 } 94 95 _, err = c.Age(n) 96 if err == nil { 97 t.Errorf("no error getting age of non-existent cache %s: %v", n, err) 98 } 99 if !os.IsNotExist(err) { 100 t.Errorf("deleted cache exists %s: %v", n, err) 101 } 102 103 // Load non-existent cache 104 if _, err := c.Load(n); err == nil { 105 t.Errorf("no error loading non-existent cache") 106 } 107 }) 108 } 109 110 // TestLoadOrStore tests LoadOrStore API. 111 func TestLoadOrStore(t *testing.T) { 112 s := "this is a test" 113 var reloadCalled bool 114 reload := func() ([]byte, error) { 115 reloadCalled = true 116 return []byte(s), nil 117 } 118 119 WithTempDir(func(dir string) { 120 c := NewCache(dir) 121 n := "test.txt" 122 maxAge := time.Duration(time.Second * 1) 123 124 // Sanity checks 125 p := c.path(n) 126 if util.PathExists(p) { 127 t.Errorf("cache file already exists: %s", p) 128 } 129 130 // Cache empty 131 data, err := c.LoadOrStore(n, maxAge, reload) 132 if err != nil { 133 t.Errorf("couldn't load/store cached data: %v", err) 134 } 135 if bytes.Compare(data, []byte(s)) != 0 { 136 t.Errorf("unexpected cache data. Expected=%v, Got=%v", []byte(s), data) 137 } 138 if !reloadCalled { 139 t.Errorf("reload wasn't called") 140 } 141 142 if c.Expired(n, maxAge) { 143 t.Errorf("cache expired") 144 } 145 146 // Load cached data 147 reloadCalled = false 148 data, err = c.LoadOrStore(n, maxAge, reload) 149 if err != nil { 150 t.Errorf("couldn't load/store cached data: %v", err) 151 } 152 if bytes.Compare(data, []byte(s)) != 0 { 153 t.Errorf("unexpected cache data. Expected=%v, Got=%v", []byte(s), data) 154 } 155 if reloadCalled { 156 t.Errorf("reload was called") 157 } 158 159 // Load with 0 maxAge 160 reloadCalled = false 161 data, err = c.LoadOrStore(n, 0, reload) 162 if err != nil { 163 t.Errorf("couldn't load/store cached data: %v", err) 164 } 165 if bytes.Compare(data, []byte(s)) != 0 { 166 t.Errorf("unexpected cache data. Expected=%v, Got=%v", []byte(s), data) 167 } 168 if reloadCalled { 169 t.Errorf("reload was called") 170 } 171 172 time.Sleep(time.Duration(time.Second * 1)) 173 174 if !c.Expired(n, maxAge) { 175 t.Errorf("cache hasn't expired") 176 } 177 178 // Reload data 179 reloadCalled = false 180 data, err = c.LoadOrStore(n, maxAge, reload) 181 if err != nil { 182 t.Errorf("couldn't load/store cached data: %v", err) 183 } 184 if bytes.Compare(data, []byte(s)) != 0 { 185 t.Errorf("unexpected cache data. Expected=%v, Got=%v", []byte(s), data) 186 } 187 if !reloadCalled { 188 t.Errorf("reload wasn't called") 189 } 190 }) 191 } 192 193 // TestData is for testing JSON serialisation. 194 type TestData struct { 195 A string 196 B string 197 } 198 199 func (td *TestData) Eq(other *TestData) bool { 200 if td.A != other.A { 201 return false 202 } 203 if td.B != other.B { 204 return false 205 } 206 return true 207 } 208 209 // TestStoreJSON round-trips data through the JSON caching API. 210 func TestStoreJSON(t *testing.T) { 211 WithTempDir(func(dir string) { 212 n := "test.json" 213 c := NewCache(dir) 214 p := c.path(n) 215 216 // Delete non-existent store 217 if err := c.StoreJSON(n, nil); err != nil { 218 t.Errorf("unexpected error clearing cache: %v", err) 219 } 220 221 a := &TestData{"one", "two"} 222 if err := c.StoreJSON(n, a); err != nil { 223 t.Errorf("couldn't store JSON: %v", err) 224 } 225 226 if !util.PathExists(p) { 227 t.Errorf("cache doesn't exist") 228 } 229 230 b := &TestData{} 231 if err := c.LoadJSON(n, b); err != nil { 232 t.Errorf("couldn't load cached JSON: %v", err) 233 } 234 235 if !b.Eq(a) { 236 t.Errorf("unexpected data. Expected=%+v, Got=%+v", a, b) 237 } 238 239 // Delete store 240 if err := c.StoreJSON(n, nil); err != nil { 241 t.Errorf("unexpected error clearing cache: %v", err) 242 } 243 244 if util.PathExists(p) { 245 t.Errorf("couldn't delete cache %s", p) 246 } 247 248 // Try to load non-existent cache 249 b = &TestData{} 250 if err := c.LoadJSON(n, b); err == nil { 251 t.Errorf("no error loading non-existent cache") 252 } 253 }) 254 } 255 256 // TestLoadOrStoreJSON tests JSON serialisation. 257 func TestLoadOrStoreJSON(t *testing.T) { 258 var reloadCalled bool 259 var a, b *TestData 260 261 reload := func() (interface{}, error) { 262 reloadCalled = true 263 return &TestData{"one", "two"}, nil 264 } 265 266 WithTempDir(func(dir string) { 267 n := "test.json" 268 c := NewCache(dir) 269 maxAge := time.Duration(time.Second * 1) 270 271 // Sanity checks 272 p := c.path(n) 273 if util.PathExists(p) { 274 t.Errorf("cache file already exists: %s", p) 275 } 276 277 a = &TestData{"one", "two"} 278 b = &TestData{} 279 // Cache empty 280 err := c.LoadOrStoreJSON(n, maxAge, reload, b) 281 if err != nil { 282 t.Errorf("couldn't load/store cached data: %v", err) 283 } 284 if !a.Eq(b) { 285 t.Errorf("unexpected cache data. Expected=%v, Got=%v", a, b) 286 } 287 if !reloadCalled { 288 t.Errorf("reload wasn't called") 289 } 290 291 if c.Expired(n, maxAge) { 292 t.Errorf("cache expired") 293 } 294 295 // Load cached data 296 reloadCalled = false 297 a = &TestData{"one", "two"} 298 b = &TestData{} 299 err = c.LoadOrStoreJSON(n, maxAge, reload, b) 300 if err != nil { 301 t.Errorf("couldn't load/store cached data: %v", err) 302 } 303 if !b.Eq(a) { 304 t.Errorf("unexpected cache data. Expected=%v, Got=%v", a, b) 305 } 306 if reloadCalled { 307 t.Errorf("reload was called") 308 } 309 310 // Load with 0 maxAge 311 reloadCalled = false 312 a = &TestData{"one", "two"} 313 b = &TestData{} 314 err = c.LoadOrStoreJSON(n, 0, reload, b) 315 if err != nil { 316 t.Errorf("couldn't load/store cached data: %v", err) 317 } 318 if !b.Eq(a) { 319 t.Errorf("unexpected cache data. Expected=%v, Got=%v", a, b) 320 } 321 if reloadCalled { 322 t.Errorf("reload was called") 323 } 324 325 time.Sleep(time.Duration(time.Second * 1)) 326 327 if !c.Expired(n, maxAge) { 328 t.Errorf("cache hasn't expired") 329 } 330 331 // Reload data 332 reloadCalled = false 333 a = &TestData{"one", "two"} 334 b = &TestData{} 335 err = c.LoadOrStoreJSON(n, maxAge, reload, b) 336 if err != nil { 337 t.Errorf("couldn't load/store cached data: %v", err) 338 } 339 if !b.Eq(a) { 340 t.Errorf("unexpected cache data. Expected=%v, Got=%v", a, b) 341 } 342 if !reloadCalled { 343 t.Errorf("reload wasn't called") 344 } 345 }) 346 } 347 348 // TestBadReloadError checks reload funcs that return errors 349 func TestBadReloadError(t *testing.T) { 350 reloadB := func() ([]byte, error) { 351 return nil, fmt.Errorf("an error") 352 } 353 354 reloadJSON := func() (interface{}, error) { 355 return nil, fmt.Errorf("an error") 356 } 357 358 WithTempDir(func(dir string) { 359 c := NewCache(dir) 360 n := "test" 361 if _, err := c.LoadOrStore(n, 0, reloadB); err == nil { 362 t.Error("no error returned by reloadB") 363 } 364 v := &TestData{} 365 if err := c.LoadOrStoreJSON(n, 0, reloadJSON, v); err == nil { 366 t.Error("no error returned by reloadJSON") 367 } 368 }) 369 } 370 371 // TestSession tests session-scoped caching. 372 func TestSession(t *testing.T) { 373 WithTempDir(func(dir string) { 374 sid := NewSessionID() 375 s := NewSession(dir, sid) 376 data := []byte("this is a test") 377 n := "test.txt" 378 379 // Sanity checks 380 p := s.cache.path(s.name(n)) 381 if util.PathExists(p) { 382 t.Errorf("cache file already exists: %s", p) 383 } 384 385 // Delete non-existent store 386 if err := s.Store(n, nil); err != nil { 387 t.Errorf("unexpected error clearing cache: %v", err) 388 } 389 390 // Non-existent cache exists 391 if s.Exists(n) { 392 t.Errorf("non-existent cache exists") 393 } 394 395 // Store data 396 if err := s.Store(n, data); err != nil { 397 t.Errorf("couldn't cache data to %s: %v", n, err) 398 } 399 if !util.PathExists(p) { 400 t.Errorf("cache file does not exist: %s", p) 401 } 402 403 if s.Exists(n) != util.PathExists(p) { 404 t.Errorf("cache file does not exist: %s", p) 405 } 406 407 // Load data 408 data2, err := s.Load(n) 409 if err != nil { 410 t.Errorf("couldn't load cached data: %v", err) 411 } 412 if bytes.Compare(data, data2) != 0 { 413 t.Errorf("loaded data does not match saved data: expected=%v, got=%v", data, data2) 414 } 415 416 // Clear session 417 s.Clear(false) // Leave current session data 418 if !util.PathExists(p) { 419 t.Errorf("cache file does not exist: %s", p) 420 } 421 // Clear this session's data, too 422 s.Clear(true) 423 if util.PathExists(p) { 424 t.Errorf("cache file exists: %s", p) 425 } 426 427 // Load non-existent cache 428 if _, err := s.Load(n); err == nil { 429 t.Errorf("no error loading non-existent cache") 430 } 431 432 // Clear old sessions 433 sid1 := NewSessionID() 434 sid2 := NewSessionID() 435 s = NewSession(dir, sid1) 436 s.Store(n, data) 437 438 if !s.Exists(n) { 439 t.Errorf("cached data do not exist: %s", n) 440 } 441 442 s = NewSession(dir, sid2) 443 s.Clear(false) 444 445 if s.Exists(n) { 446 t.Errorf("expired data still exist: %s", n) 447 } 448 }) 449 }