github.com/wfusion/gofusion@v1.1.14/test/cache/cases/local_test.go (about) 1 package cases 2 3 import ( 4 "context" 5 "math/rand" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/go-faker/faker/v4" 11 "github.com/spf13/cast" 12 "github.com/stretchr/testify/suite" 13 14 "github.com/wfusion/gofusion/cache" 15 "github.com/wfusion/gofusion/common/utils" 16 "github.com/wfusion/gofusion/common/utils/serialize" 17 "github.com/wfusion/gofusion/log" 18 "github.com/wfusion/gofusion/test/internal/mock" 19 20 testCache "github.com/wfusion/gofusion/test/cache" 21 ) 22 23 func TestLocal(t *testing.T) { 24 testingSuite := &Local{Test: new(testCache.Test)} 25 testingSuite.Init(testingSuite) 26 suite.Run(t, testingSuite) 27 } 28 29 type Local struct { 30 *testCache.Test 31 } 32 33 func (t *Local) BeforeTest(suiteName, testName string) { 34 t.Catch(func() { 35 log.Info(context.Background(), "right before %s %s", suiteName, testName) 36 }) 37 } 38 39 func (t *Local) AfterTest(suiteName, testName string) { 40 t.Catch(func() { 41 log.Info(context.Background(), "right after %s %s", suiteName, testName) 42 }) 43 } 44 45 func (t *Local) TestLocal() { 46 t.Catch(func() { 47 // Given 48 num := 15 49 ctx := context.Background() 50 algo := serialize.AlgorithmUnknown 51 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 52 objList := mock.GenObjListBySerializeAlgo(algo, num).([]*mock.RandomObj) 53 stringObjMap := make(map[string]*mock.RandomObj, num) 54 for i := 0; i < num; i++ { 55 stringObjMap[cast.ToString(i+1)] = objList[i] 56 } 57 defer instance.Clear(ctx) 58 59 // When 60 instance.Set(ctx, stringObjMap) 61 62 // Then 63 keys := []string{"13", "14", "15"} 64 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 65 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 66 67 keys = []string{"1", "2", "3"} 68 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 69 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 70 71 keys = []string{"1"} 72 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 73 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 74 75 time.Sleep(5 * time.Second) 76 keys = []string{"1"} 77 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 78 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 79 }) 80 } 81 82 func (t *Local) TestLocalGetAll() { 83 t.Catch(func() { 84 // Given 85 num := 15 86 ctx := context.Background() 87 algo := serialize.AlgorithmUnknown 88 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 89 objList := mock.GenObjListBySerializeAlgo(algo, num).([]*mock.RandomObj) 90 stringObjMap := make(map[string]*mock.RandomObj, num) 91 for i := 0; i < num; i++ { 92 stringObjMap[cast.ToString(i+1)] = objList[i] 93 } 94 defer instance.Clear(ctx) 95 96 // When 97 instance.Set(ctx, stringObjMap) 98 time.Sleep(5 * time.Second) 99 100 // Then 101 keys := []string{"1"} 102 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 103 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 104 105 rs = instance.GetAll(ctx, nil) 106 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 107 }) 108 } 109 110 func (t *Local) TestLocalWithoutLog() { 111 t.Catch(func() { 112 // Given 113 num := 15 114 ctx := context.Background() 115 algo := serialize.AlgorithmUnknown 116 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](localWithoutLog, 117 cache.AppName(t.AppName())) 118 objList := mock.GenObjListBySerializeAlgo(algo, num).([]*mock.RandomObj) 119 stringObjMap := make(map[string]*mock.RandomObj, num) 120 for i := 0; i < num; i++ { 121 stringObjMap[cast.ToString(i+1)] = objList[i] 122 } 123 defer instance.Clear(ctx) 124 125 // When 126 instance.Set(ctx, stringObjMap) 127 128 // Then 129 keys := []string{"13", "14", "15"} 130 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 131 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 132 133 keys = []string{"1", "2", "3"} 134 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 135 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 136 137 keys = []string{"1"} 138 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 139 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 140 141 time.Sleep(5 * time.Second) 142 keys = []string{"1"} 143 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 144 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 145 }) 146 } 147 148 func (t *Local) TestClear() { 149 t.Catch(func() { 150 // Given 151 ctx := context.Background() 152 algo := serialize.AlgorithmUnknown 153 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 154 stringObjMap := map[string]*mock.RandomObj{ 155 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 156 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 157 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 158 } 159 defer instance.Clear(ctx) 160 161 // When 162 instance.Set(ctx, stringObjMap) 163 164 // Then 165 keys := []string{"1", "2", "3"} 166 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 167 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 168 169 instance.Clear(ctx) 170 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 171 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 172 }) 173 } 174 175 func (t *Local) TestDel() { 176 t.Catch(func() { 177 // Given 178 ctx := context.Background() 179 algo := serialize.AlgorithmUnknown 180 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 181 stringObjMap := map[string]*mock.RandomObj{ 182 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 183 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 184 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 185 } 186 defer instance.Clear(ctx) 187 188 // When 189 instance.Set(ctx, stringObjMap) 190 191 // Then 192 keys := []string{"1", "2", "3"} 193 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 194 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 195 196 instance.Del(ctx, keys...) 197 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 198 t.NotEmpty(rs) 199 }) 200 } 201 202 func (t *Local) TestDelWithFailureKeys() { 203 t.Catch(func() { 204 // Given 205 ctx := context.Background() 206 algo := serialize.AlgorithmUnknown 207 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 208 stringObjMap := map[string]*mock.RandomObj{ 209 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 210 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 211 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 212 } 213 defer instance.Clear(ctx) 214 215 // When 216 keys := []string{"1", "2"} 217 instance.Set(ctx, stringObjMap) 218 failureKeys := instance.Del(ctx, keys...) 219 t.Empty(failureKeys) 220 221 // Then 222 failureKeys = instance.Del(ctx, keys...) 223 t.Empty(failureKeys) 224 }) 225 } 226 227 func (t *Local) TestSetExpired() { 228 t.Catch(func() { 229 // Given 230 ctx := context.Background() 231 algo := serialize.AlgorithmUnknown 232 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 233 stringObjMap := map[string]*mock.RandomObj{"1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj)} 234 defer instance.Clear(ctx) 235 236 // When 237 instance.Set(ctx, stringObjMap, cache.Expired[string](10*time.Second)) 238 239 // Then 240 time.Sleep(5 * time.Second) 241 keys := []string{"1"} 242 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 243 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 244 }) 245 } 246 247 func (t *Local) TestSetKeyExpired() { 248 t.Catch(func() { 249 // Given 250 ctx := context.Background() 251 algo := serialize.AlgorithmUnknown 252 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](local, cache.AppName(t.AppName())) 253 stringObjMap := map[string]*mock.RandomObj{"1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj)} 254 defer instance.Clear(ctx) 255 256 // When 257 instance.Set(ctx, stringObjMap, cache.KeyExpired(map[string]time.Duration{"1": 10 * time.Second})) 258 259 // Then 260 time.Sleep(5 * time.Second) 261 keys := []string{"1"} 262 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 263 t.EqualValues(utils.MapValuesByKeys(stringObjMap, keys), rs) 264 }) 265 } 266 267 func (t *Local) TestSetGetInParallel() { 268 t.Catch(func() { 269 // Given 270 ctx := context.Background() 271 instance := cache.New[string, *mock.CommonObj, []*mock.CommonObj]( 272 localWithSerializeAndCompress, cache.AppName(t.AppName())) 273 defer instance.Clear(ctx) 274 275 wg := new(sync.WaitGroup) 276 for i := 0; i < 500; i++ { 277 wg.Add(1) 278 go func() { 279 defer wg.Done() 280 key := faker.UUIDHyphenated() 281 val := mock.GenObjBySerializeAlgo(serialize.AlgorithmJson).(*mock.CommonObj) 282 instance.Set(ctx, map[string]*mock.CommonObj{key: val}) 283 rs := instance.Get(ctx, []string{key}, commonObjCallback) 284 //t.NotEmpty(rs) 285 t.EqualValues(val, rs[0]) 286 }() 287 } 288 wg.Wait() 289 }) 290 } 291 292 func (t *Local) TestLocalWithCallback() { 293 t.Catch(func() { 294 // Given 295 ctx := context.Background() 296 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj]( 297 localWithCallback, cache.AppName(t.AppName())) 298 defer instance.Clear(ctx) 299 300 t.runInParallel(func() { 301 randomKey := faker.UUIDHyphenated() 302 stringObjMap := map[string]*mock.RandomObj{ 303 randomKey: mock.GenObjBySerializeAlgo(0).(*mock.RandomObj), 304 } 305 instance.Set(ctx, stringObjMap) 306 307 // When 308 randomKeys := [3]string{} 309 t.NoError(faker.FakeData(&randomKeys)) 310 keys := append([]string{randomKey}, randomKeys[:]...) 311 rs := instance.Get(ctx, keys, nil) 312 313 // Then 314 t.Equal(len(rs), len(keys)) 315 t.EqualValues(stringObjMap[randomKey], rs[0]) 316 for i := 0; i < len(rs); i++ { 317 t.NotEmpty(rs[i]) 318 } 319 }) 320 }) 321 } 322 323 func (t *Local) TestLocalWithSerialize() { 324 t.Catch(func() { 325 // Given 326 ctx := context.Background() 327 instance := cache.New[string, *mock.CommonObj, []*mock.CommonObj]( 328 localWithSerialize, cache.AppName(t.AppName())) 329 defer instance.Clear(ctx) 330 331 t.runInParallel(func() { 332 randomKey := faker.UUIDHyphenated() 333 stringObjMap := map[string]*mock.CommonObj{ 334 randomKey: mock.GenObjBySerializeAlgo(serialize.AlgorithmJson).(*mock.CommonObj), 335 } 336 instance.Set(ctx, stringObjMap) 337 338 // When 339 randomKeys := [3]string{} 340 t.NoError(faker.FakeData(&randomKeys)) 341 keys := append([]string{randomKey}, randomKeys[:]...) 342 rs := instance.Get(ctx, keys, t.commonObjCallback(stringObjMap, true)) 343 344 // Then 345 t.Equal(len(rs), len(keys)) 346 t.EqualValues(stringObjMap[randomKey], rs[0]) 347 for i := 0; i < len(rs); i++ { 348 t.NotEmpty(rs[i]) 349 } 350 }) 351 }) 352 } 353 354 func (t *Local) TestLocalWithSerializeAndCompress() { 355 t.Catch(func() { 356 // Given 357 ctx := context.Background() 358 instance := cache.New[string, *mock.CommonObj, []*mock.CommonObj]( 359 localWithSerializeAndCompress, cache.AppName(t.AppName())) 360 defer instance.Clear(ctx) 361 362 t.runInParallel(func() { 363 randomKey := faker.UUIDHyphenated() 364 stringObjMap := map[string]*mock.CommonObj{ 365 randomKey: mock.GenObjBySerializeAlgo(serialize.AlgorithmJson).(*mock.CommonObj), 366 } 367 instance.Set(ctx, stringObjMap) 368 369 // When 370 randomKeys := [3]string{} 371 t.NoError(faker.FakeData(&randomKeys)) 372 keys := append([]string{randomKey}, randomKeys[:]...) 373 rs := instance.Get(ctx, keys, t.commonObjCallback(stringObjMap, true)) 374 375 // Then 376 t.Equal(len(rs), len(keys)) 377 t.EqualValues(stringObjMap[randomKey], rs[0]) 378 for i := 0; i < len(rs); i++ { 379 t.NotEmpty(rs[i]) 380 } 381 }) 382 }) 383 } 384 385 func (t *Local) TestLocalWithCompress() { 386 t.Catch(func() { 387 // Given 388 ctx := context.Background() 389 390 type cases struct { 391 name string 392 cacheName string 393 } 394 395 testCases := []cases{ 396 { 397 name: "zstd", 398 cacheName: localWithZstdCompress, 399 }, 400 { 401 name: "zlib", 402 cacheName: localWithZlibCompress, 403 }, 404 { 405 name: "s2", 406 cacheName: localWithS2Compress, 407 }, 408 { 409 name: "gzip", 410 cacheName: localWithGzipCompress, 411 }, 412 { 413 name: "deflate", 414 cacheName: localWithDeflateCompress, 415 }, 416 } 417 418 algo := serialize.AlgorithmGob 419 for _, cs := range testCases { 420 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj]( 421 cs.cacheName, cache.AppName(t.AppName())) 422 t.Run(cs.name, func() { 423 defer instance.Clear(ctx) 424 t.runInParallel(func() { 425 randomKey := faker.UUIDHyphenated() 426 stringObjMap := map[string]*mock.RandomObj{ 427 randomKey: mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 428 } 429 instance.Set(ctx, stringObjMap) 430 431 // When 432 randomKeys := [3]string{} 433 t.NoError(faker.FakeData(&randomKeys)) 434 keys := append([]string{randomKey}, randomKeys[:]...) 435 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 436 437 // Then 438 t.Equal(len(rs), len(keys)) 439 t.EqualValues(stringObjMap[randomKey], rs[0]) 440 for i := 0; i < len(rs); i++ { 441 t.NotEmpty(rs[i]) 442 } 443 }) 444 }) 445 } 446 }) 447 } 448 449 func (t *Local) runInParallel(exec func()) { 450 wg := new(sync.WaitGroup) 451 for i := 0; i < 100; i++ { 452 wg.Add(1) 453 go func() { 454 defer wg.Done() 455 exec() 456 time.Sleep(time.Duration(float64(time.Millisecond) * rand.Float64())) 457 }() 458 } 459 wg.Wait() 460 } 461 462 func (t *Local) randomObjCallback(origin map[string]*mock.RandomObj, algo serialize.Algorithm, mayMissing bool) ( 463 cb func(context.Context, []string) (map[string]*mock.RandomObj, []utils.OptionExtender)) { 464 return func(ctx context.Context, missed []string) (rs map[string]*mock.RandomObj, opts []utils.OptionExtender) { 465 if !mayMissing { 466 t.FailNow("cache missing!", missed) 467 } 468 469 rs = make(map[string]*mock.RandomObj, len(missed)) 470 for _, key := range missed { 471 if v, ok := origin[key]; ok { 472 rs[key] = v 473 } else { 474 rs[key] = mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj) 475 } 476 } 477 return 478 } 479 } 480 481 func (t *Local) commonObjCallback(origin map[string]*mock.CommonObj, mayMissing bool) ( 482 cb func(context.Context, []string) (map[string]*mock.CommonObj, []utils.OptionExtender)) { 483 return func(ctx context.Context, missed []string) (rs map[string]*mock.CommonObj, opts []utils.OptionExtender) { 484 if !mayMissing { 485 t.FailNow("cache missing!", missed) 486 } 487 488 rs = make(map[string]*mock.CommonObj, len(missed)) 489 for _, key := range missed { 490 if v, ok := origin[key]; ok { 491 rs[key] = v 492 } else { 493 rs[key] = mock.GenObjBySerializeAlgo(serialize.AlgorithmJson).(*mock.CommonObj) 494 } 495 } 496 return 497 } 498 }