github.com/wfusion/gofusion@v1.1.14/test/cache/cases/redis_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 TestRedis(t *testing.T) { 24 testingSuite := &Redis{Test: new(testCache.Test)} 25 testingSuite.Init(testingSuite) 26 suite.Run(t, testingSuite) 27 } 28 29 type Redis struct { 30 *testCache.Test 31 } 32 33 func (t *Redis) 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 *Redis) 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 *Redis) TestRedis() { 46 t.Catch(func() { 47 // Given 48 num := 15 49 ctx := context.Background() 50 algo := serialize.AlgorithmGob 51 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](redis, 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"} 64 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 65 t.NotEmpty(rs) 66 67 keys = []string{"1"} 68 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 69 t.NotEmpty(rs) 70 71 keys = []string{"1"} 72 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 73 t.NotEmpty(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.NotEmpty(rs) 79 }) 80 } 81 82 func (t *Redis) TestClear() { 83 t.Catch(func() { 84 // Given 85 ctx := context.Background() 86 algo := serialize.AlgorithmGob 87 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](redis, cache.AppName(t.AppName())) 88 stringObjMap := map[string]*mock.RandomObj{ 89 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 90 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 91 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 92 } 93 defer instance.Clear(ctx) 94 95 // When 96 instance.Set(ctx, stringObjMap) 97 98 // Then 99 keys := []string{"1", "2", "3"} 100 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 101 t.NotEmpty(rs) 102 103 instance.Clear(ctx) 104 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 105 t.NotEmpty(rs) 106 }) 107 } 108 109 func (t *Redis) TestDel() { 110 t.Catch(func() { 111 // Given 112 ctx := context.Background() 113 algo := serialize.AlgorithmGob 114 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](redis, cache.AppName(t.AppName())) 115 stringObjMap := map[string]*mock.RandomObj{ 116 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 117 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 118 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 119 } 120 defer instance.Clear(ctx) 121 122 // When 123 instance.Set(ctx, stringObjMap) 124 125 // Then 126 keys := []string{"1", "2", "3"} 127 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, false)) 128 t.NotEmpty(rs) 129 130 instance.Del(ctx, keys...) 131 rs = instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 132 t.NotEmpty(rs) 133 }) 134 } 135 136 func (t *Redis) TestDelWithFailureKeys() { 137 t.Catch(func() { 138 // Given 139 ctx := context.Background() 140 algo := serialize.AlgorithmGob 141 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj](redis, cache.AppName(t.AppName())) 142 stringObjMap := map[string]*mock.RandomObj{ 143 "1": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 144 "2": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 145 "3": mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 146 } 147 defer instance.Clear(ctx) 148 149 // When 150 keys := []string{"1", "2"} 151 instance.Set(ctx, stringObjMap) 152 failureKeys := instance.Del(ctx, keys...) 153 t.Empty(failureKeys) 154 155 // Then 156 failureKeys = instance.Del(ctx, keys...) 157 t.Empty(failureKeys) 158 }) 159 } 160 161 func (t *Redis) TestSetGetInParallel() { 162 t.Catch(func() { 163 // Given 164 ctx := context.Background() 165 instance := cache.New[string, *mock.CommonObj, []*mock.CommonObj](redisJson, cache.AppName(t.AppName())) 166 defer instance.Clear(ctx) 167 168 wg := new(sync.WaitGroup) 169 for i := 0; i < 500; i++ { 170 wg.Add(1) 171 go func() { 172 defer wg.Done() 173 key := faker.UUIDHyphenated() 174 val := mock.GenObjBySerializeAlgo(serialize.AlgorithmJson).(*mock.CommonObj) 175 instance.Set(ctx, map[string]*mock.CommonObj{key: val}) 176 rs := instance.Get(ctx, []string{key}, commonObjCallback) 177 t.EqualValues(val, rs[0]) 178 }() 179 } 180 wg.Wait() 181 }) 182 } 183 184 func (t *Redis) TestLocalWithCompress() { 185 t.Catch(func() { 186 // Given 187 ctx := context.Background() 188 189 type cases struct { 190 name string 191 cacheName string 192 } 193 194 testCases := []cases{ 195 { 196 name: "zstd", 197 cacheName: redisWithZstdCompress, 198 }, 199 { 200 name: "zlib", 201 cacheName: redisWithZlibCompress, 202 }, 203 { 204 name: "s2", 205 cacheName: redisWithS2Compress, 206 }, 207 { 208 name: "gzip", 209 cacheName: redisWithGzipCompress, 210 }, 211 { 212 name: "deflate", 213 cacheName: redisWithDeflateCompress, 214 }, 215 } 216 217 algo := serialize.AlgorithmGob 218 for _, cs := range testCases { 219 instance := cache.New[string, *mock.RandomObj, []*mock.RandomObj]( 220 cs.cacheName, cache.AppName(t.AppName())) 221 t.Run(cs.name, func() { 222 defer instance.Clear(ctx) 223 t.runInParallel(func() { 224 randomKey := faker.UUIDHyphenated() 225 stringObjMap := map[string]*mock.RandomObj{ 226 randomKey: mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj), 227 } 228 instance.Set(ctx, stringObjMap) 229 230 // When 231 randomKeys := [3]string{} 232 t.NoError(faker.FakeData(&randomKeys)) 233 keys := append([]string{randomKey}, randomKeys[:]...) 234 rs := instance.Get(ctx, keys, t.randomObjCallback(stringObjMap, algo, true)) 235 236 // Then 237 t.Equal(len(rs), len(keys)) 238 t.EqualValues(stringObjMap[randomKey], rs[0]) 239 for i := 0; i < len(rs); i++ { 240 t.NotEmpty(rs[i]) 241 } 242 }) 243 }) 244 } 245 }) 246 } 247 248 func (t *Redis) runInParallel(exec func()) { 249 wg := new(sync.WaitGroup) 250 for i := 0; i < 100; i++ { 251 wg.Add(1) 252 go func() { 253 defer wg.Done() 254 exec() 255 time.Sleep(time.Duration(float64(time.Millisecond) * rand.Float64())) 256 }() 257 } 258 wg.Wait() 259 } 260 261 func (t *Redis) randomObjCallback(origin map[string]*mock.RandomObj, algo serialize.Algorithm, mayMissing bool) ( 262 cb func(context.Context, []string) (map[string]*mock.RandomObj, []utils.OptionExtender)) { 263 return func(ctx context.Context, missed []string) (rs map[string]*mock.RandomObj, opts []utils.OptionExtender) { 264 if !mayMissing { 265 t.FailNow("cache missing!", missed) 266 } 267 268 rs = make(map[string]*mock.RandomObj, len(missed)) 269 for _, key := range missed { 270 if v, ok := origin[key]; ok { 271 rs[key] = v 272 } else { 273 rs[key] = mock.GenObjBySerializeAlgo(algo).(*mock.RandomObj) 274 } 275 } 276 return 277 } 278 } 279 280 func (t *Redis) commonObjCallback(origin map[string]*mock.CommonObj, algo serialize.Algorithm, mayMissing bool) ( 281 cb func(context.Context, []string) (map[string]*mock.CommonObj, []utils.OptionExtender)) { 282 return func(ctx context.Context, missed []string) (rs map[string]*mock.CommonObj, opts []utils.OptionExtender) { 283 if !mayMissing { 284 t.FailNow("cache missing!", missed) 285 } 286 287 rs = make(map[string]*mock.CommonObj, len(missed)) 288 for _, key := range missed { 289 if v, ok := origin[key]; ok { 290 rs[key] = v 291 } else { 292 rs[key] = mock.GenObjBySerializeAlgo(algo).(*mock.CommonObj) 293 } 294 } 295 return 296 } 297 }