github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/cache/asynccache/asynccache_test.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package asynccache 16 17 import ( 18 "errors" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func TestGetOK(t *testing.T) { 26 var key, ret = "key", "ret" 27 op := Options{ 28 RefreshDuration: time.Second, 29 IsSame: func(key string, oldData, newData interface{}) bool { 30 return false 31 }, 32 Fetcher: func(key string) (interface{}, error) { 33 return ret, nil 34 }, 35 } 36 c := NewAsyncCache(op) 37 38 v, err := c.Get(key) 39 assert.NoError(t, err) 40 assert.Equal(t, v.(string), ret) 41 42 time.Sleep(time.Second / 2) 43 ret = "change" 44 v, err = c.Get(key) 45 assert.NoError(t, err) 46 assert.NotEqual(t, v.(string), ret) 47 48 time.Sleep(time.Second) 49 v, err = c.Get(key) 50 assert.NoError(t, err) 51 assert.Equal(t, v.(string), ret) 52 } 53 54 func TestGetErr(t *testing.T) { 55 var key, ret = "key", "ret" 56 var first = true 57 op := Options{ 58 RefreshDuration: time.Second + 100*time.Millisecond, 59 IsSame: func(key string, oldData, newData interface{}) bool { 60 return false 61 }, 62 Fetcher: func(key string) (interface{}, error) { 63 if first { 64 first = false 65 return nil, errors.New("error") 66 } 67 return ret, nil 68 }, 69 } 70 c := NewAsyncCache(op) 71 72 v, err := c.Get(key) 73 assert.Error(t, err) 74 assert.Nil(t, v) 75 76 time.Sleep(time.Second / 2) 77 _, err2 := c.Get(key) 78 assert.Equal(t, err, err2) 79 80 time.Sleep(time.Second + 10*time.Millisecond) 81 v, err = c.Get(key) 82 assert.NoError(t, err) 83 assert.Equal(t, v.(string), ret) 84 } 85 86 func TestGetOrSetOK(t *testing.T) { 87 var key, ret, def = "key", "ret", "def" 88 op := Options{ 89 RefreshDuration: time.Second, 90 IsSame: func(key string, oldData, newData interface{}) bool { 91 return false 92 }, 93 Fetcher: func(key string) (interface{}, error) { 94 return ret, nil 95 }, 96 } 97 c := NewAsyncCache(op) 98 99 v := c.GetOrSet(key, def) 100 assert.Equal(t, v.(string), ret) 101 102 time.Sleep(time.Second / 2) 103 ret = "change" 104 v = c.GetOrSet(key, def) 105 assert.NotEqual(t, v.(string), ret) 106 107 time.Sleep(time.Second) 108 v = c.GetOrSet(key, def) 109 assert.Equal(t, v.(string), ret) 110 } 111 112 func TestGetOrSetErr(t *testing.T) { 113 var key, ret, def = "key", "ret", "def" 114 var first = true 115 op := Options{ 116 RefreshDuration: time.Second + 500*time.Millisecond, 117 IsSame: func(key string, oldData, newData interface{}) bool { 118 return false 119 }, 120 Fetcher: func(key string) (interface{}, error) { 121 if first { 122 first = false 123 return nil, errors.New("error") 124 } 125 return ret, nil 126 }, 127 } 128 c := NewAsyncCache(op) 129 130 v := c.GetOrSet(key, def) 131 assert.Equal(t, v.(string), def) 132 133 time.Sleep(time.Second / 2) 134 v = c.GetOrSet(key, ret) 135 assert.NotEqual(t, v.(string), ret) 136 assert.Equal(t, v.(string), def) 137 138 time.Sleep(time.Second + 500*time.Millisecond) 139 v = c.GetOrSet(key, def) 140 assert.Equal(t, v.(string), ret) 141 } 142 143 func TestSetDefault(t *testing.T) { 144 op := Options{ 145 RefreshDuration: time.Second, 146 IsSame: func(key string, oldData, newData interface{}) bool { 147 return false 148 }, 149 Fetcher: func(key string) (interface{}, error) { 150 return nil, errors.New("error") 151 }, 152 } 153 c := NewAsyncCache(op) 154 155 v := c.GetOrSet("key1", "def1") 156 assert.Equal(t, v.(string), "def1") 157 158 exist := c.SetDefault("key2", "val2") 159 assert.False(t, exist) 160 v = c.GetOrSet("key2", "def2") 161 assert.Equal(t, v.(string), "val2") 162 163 exist = c.SetDefault("key2", "val3") 164 assert.True(t, exist) 165 v = c.GetOrSet("key2", "def2") 166 assert.Equal(t, v.(string), "val2") 167 } 168 169 func TestDeleteIf(t *testing.T) { 170 op := Options{ 171 RefreshDuration: time.Second, 172 IsSame: func(key string, oldData, newData interface{}) bool { 173 return false 174 }, 175 Fetcher: func(key string) (interface{}, error) { 176 return nil, errors.New("error") 177 }, 178 } 179 c := NewAsyncCache(op) 180 181 c.SetDefault("key", "val") 182 v := c.GetOrSet("key", "def") 183 assert.Equal(t, v.(string), "val") 184 185 d, _ := c.(interface{ DeleteIf(func(key string) bool) }) 186 d.DeleteIf(func(string) bool { return true }) 187 188 v = c.GetOrSet("key", "def") 189 assert.Equal(t, v.(string), "def") 190 } 191 192 func TestClose(t *testing.T) { 193 var dur = time.Second / 10 194 var cnt int 195 op := Options{ 196 RefreshDuration: dur - 10*time.Millisecond, 197 IsSame: func(key string, oldData, newData interface{}) bool { 198 return false 199 }, 200 Fetcher: func(key string) (interface{}, error) { 201 cnt++ 202 return cnt, nil 203 }, 204 EnableExpire: true, 205 ExpireDuration: time.Second, 206 } 207 c := NewAsyncCache(op) 208 209 v := c.GetOrSet("key", 10) 210 assert.Equal(t, v.(int), 1) 211 212 time.Sleep(dur) 213 v = c.GetOrSet("key", 10) 214 assert.Equal(t, v.(int), 2) 215 216 time.Sleep(dur) 217 v = c.GetOrSet("key", 10) 218 assert.Equal(t, v.(int), 3) 219 220 c.Close() 221 222 time.Sleep(dur) 223 v = c.GetOrSet("key", 10) 224 assert.Equal(t, v.(int), 3) 225 } 226 227 func TestExpire(t *testing.T) { 228 // trigger is used to mark whether fetcher is called 229 trigger := false 230 op := Options{ 231 EnableExpire: true, 232 ExpireDuration: 3 * time.Minute, 233 RefreshDuration: time.Minute, 234 IsSame: func(key string, oldData, newData interface{}) bool { 235 return true 236 }, 237 Fetcher: func(key string) (interface{}, error) { 238 trigger = true 239 return "", nil 240 }, 241 } 242 c := NewAsyncCache(op).(*asyncCache) 243 244 // GetOrSet cannot trigger fetcher when SetDefault before 245 c.SetDefault("key-default", "") 246 c.SetDefault("key-alive", "") 247 c.GetOrSet("key-alive", "") 248 assert.False(t, trigger) 249 250 c.Get("key-expire") 251 assert.True(t, trigger) 252 253 // first expire set tag 254 c.expire() 255 256 trigger = false 257 c.Get("key-alive") 258 assert.False(t, trigger) 259 // second expire, both key-default & key-expire have been removed 260 c.expire() 261 c.refresh() // prove refresh does not affect expire 262 263 trigger = false 264 c.Get("key-alive") 265 assert.False(t, trigger) 266 trigger = false 267 c.Get("key-default") 268 assert.True(t, trigger) 269 trigger = false 270 c.Get("key-expire") 271 assert.True(t, trigger) 272 } 273 274 func BenchmarkGet(b *testing.B) { 275 var key = "key" 276 op := Options{ 277 RefreshDuration: time.Second, 278 IsSame: func(key string, oldData, newData interface{}) bool { 279 return false 280 }, 281 Fetcher: func(key string) (interface{}, error) { 282 return "", nil 283 }, 284 } 285 c := NewAsyncCache(op) 286 287 b.ReportAllocs() 288 b.ResetTimer() 289 for i := 0; i < b.N; i++ { 290 _, _ = c.Get(key) 291 } 292 } 293 294 func BenchmarkGetParallel(b *testing.B) { 295 var key = "key" 296 op := Options{ 297 RefreshDuration: time.Second, 298 IsSame: func(key string, oldData, newData interface{}) bool { 299 return false 300 }, 301 Fetcher: func(key string) (interface{}, error) { 302 return "", nil 303 }, 304 } 305 c := NewAsyncCache(op) 306 307 b.ReportAllocs() 308 b.ResetTimer() 309 b.RunParallel(func(pb *testing.PB) { 310 for pb.Next() { 311 _, _ = c.Get(key) 312 } 313 }) 314 } 315 316 func BenchmarkGetOrSet(b *testing.B) { 317 var key, def = "key", "def" 318 op := Options{ 319 RefreshDuration: time.Second, 320 IsSame: func(key string, oldData, newData interface{}) bool { 321 return false 322 }, 323 Fetcher: func(key string) (interface{}, error) { 324 return "", nil 325 }, 326 } 327 c := NewAsyncCache(op) 328 329 b.ReportAllocs() 330 b.ResetTimer() 331 for i := 0; i < b.N; i++ { 332 _ = c.GetOrSet(key, def) 333 } 334 } 335 336 func BenchmarkGetOrSetParallel(b *testing.B) { 337 var key, def = "key", "def" 338 op := Options{ 339 RefreshDuration: time.Second, 340 IsSame: func(key string, oldData, newData interface{}) bool { 341 return false 342 }, 343 Fetcher: func(key string) (interface{}, error) { 344 return "", nil 345 }, 346 } 347 c := NewAsyncCache(op) 348 349 b.ReportAllocs() 350 b.ResetTimer() 351 b.RunParallel(func(pb *testing.PB) { 352 for pb.Next() { 353 _ = c.GetOrSet(key, def) 354 } 355 }) 356 } 357 358 func BenchmarkRefresh(b *testing.B) { 359 var key, def = "key", "def" 360 op := Options{ 361 RefreshDuration: time.Second, 362 IsSame: func(key string, oldData, newData interface{}) bool { 363 return false 364 }, 365 Fetcher: func(key string) (interface{}, error) { 366 return "", nil 367 }, 368 } 369 c := NewAsyncCache(op).(*asyncCache) 370 c.SetDefault(key, def) 371 372 b.ReportAllocs() 373 b.ResetTimer() 374 for i := 0; i < b.N; i++ { 375 c.refresh() 376 } 377 } 378 379 func BenchmarkRefreshParallel(b *testing.B) { 380 var key, def = "key", "def" 381 op := Options{ 382 RefreshDuration: time.Second, 383 IsSame: func(key string, oldData, newData interface{}) bool { 384 return false 385 }, 386 Fetcher: func(key string) (interface{}, error) { 387 return "", nil 388 }, 389 } 390 c := NewAsyncCache(op).(*asyncCache) 391 c.SetDefault(key, def) 392 393 b.ReportAllocs() 394 b.ResetTimer() 395 b.RunParallel(func(pb *testing.PB) { 396 for pb.Next() { 397 c.refresh() 398 } 399 }) 400 }