github.com/dtm-labs/rockscache@v0.1.1/batch_test.go (about) 1 package rockscache 2 3 import ( 4 "errors" 5 "math/rand" 6 "strconv" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func genBatchDataFunc(values map[int]string, sleepMilli int) func(idxs []int) (map[int]string, error) { 14 return func(idxs []int) (map[int]string, error) { 15 debugf("batch fetching: %v", idxs) 16 time.Sleep(time.Duration(sleepMilli) * time.Millisecond) 17 return values, nil 18 } 19 } 20 21 func genIdxs(to int) (idxs []int) { 22 for i := 0; i < to; i++ { 23 idxs = append(idxs, i) 24 } 25 return 26 } 27 28 func genKeys(idxs []int) (keys []string) { 29 for _, i := range idxs { 30 suffix := strconv.Itoa(i) 31 k := "key" + suffix 32 keys = append(keys, k) 33 } 34 return 35 } 36 37 func genValues(n int, prefix string) map[int]string { 38 values := make(map[int]string) 39 for i := 0; i < n; i++ { 40 v := prefix + strconv.Itoa(i) 41 values[i] = v 42 } 43 return values 44 } 45 46 func TestWeakFetchBatch(t *testing.T) { 47 clearCache() 48 rc := NewClient(rdb, NewDefaultOptions()) 49 began := time.Now() 50 n := int(rand.Int31n(20) + 10) 51 idxs := genIdxs(n) 52 keys, values1, values2 := genKeys(idxs), genValues(n, "value_"), genValues(n, "eulav_") 53 values3 := genValues(n, "vvvv_") 54 go func() { 55 dc2 := NewClient(rdb, NewDefaultOptions()) 56 v, err := dc2.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values1, 200)) 57 assert.Nil(t, err) 58 assert.Equal(t, values1, v) 59 }() 60 time.Sleep(20 * time.Millisecond) 61 62 v, err := rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values2, 200)) 63 assert.Nil(t, err) 64 assert.Equal(t, values1, v) 65 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 66 67 err = rc.TagAsDeletedBatch(keys) 68 assert.Nil(t, err) 69 70 began = time.Now() 71 v, err = rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values3, 200)) 72 assert.Nil(t, err) 73 assert.Equal(t, values1, v) 74 assert.True(t, time.Since(began) < time.Duration(200)*time.Millisecond) 75 76 time.Sleep(300 * time.Millisecond) 77 v, err = rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values3, 200)) 78 assert.Nil(t, err) 79 assert.Equal(t, values3, v) 80 } 81 82 func TestWeakFetchBatchOverlap(t *testing.T) { 83 clearCache() 84 rc := NewClient(rdb, NewDefaultOptions()) 85 began := time.Now() 86 n := 100 87 idxs := genIdxs(n) 88 keys := genKeys(idxs) 89 keys1, values1 := keys[:60], genValues(60, "value_") 90 keys2, values2 := keys[40:], genValues(60, "eulav_") 91 92 go func() { 93 dc2 := NewClient(rdb, NewDefaultOptions()) 94 v, err := dc2.FetchBatch(keys1, 60*time.Second, genBatchDataFunc(values1, 200)) 95 assert.Nil(t, err) 96 assert.Equal(t, values1, v) 97 }() 98 time.Sleep(20 * time.Millisecond) 99 100 v, err := rc.FetchBatch(keys2, 60*time.Second, genBatchDataFunc(values2, 200)) 101 assert.Nil(t, err) 102 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 103 for i := 40; i < 60; i++ { 104 assert.Equal(t, keys2[i-40], keys1[i]) 105 assert.Equal(t, values1[i], v[i-40]) 106 } 107 for i := 60; i < n; i++ { 108 assert.Equal(t, values2[i-40], v[i-40]) 109 } 110 111 rc.TagAsDeletedBatch(keys[40:60]) 112 began = time.Now() 113 _, err = rc.FetchBatch(keys2, 60*time.Second, genBatchDataFunc(values2, 200)) 114 assert.Nil(t, err) 115 assert.True(t, time.Since(began) < time.Duration(200)*time.Millisecond) 116 for i := 40; i < 60; i++ { 117 assert.Equal(t, keys2[i-40], keys1[i]) 118 assert.Equal(t, values1[i], v[i-40]) 119 } 120 for i := 60; i < n; i++ { 121 assert.Equal(t, values2[i-40], v[i-40]) 122 } 123 124 time.Sleep(300 * time.Millisecond) 125 v, err = rc.FetchBatch(keys2, 20*time.Second, genBatchDataFunc(values2, 200)) 126 assert.Nil(t, err) 127 assert.Equal(t, values2, v) 128 } 129 130 func TestStrongFetchBatch(t *testing.T) { 131 clearCache() 132 rc := NewClient(rdb, NewDefaultOptions()) 133 rc.Options.StrongConsistency = true 134 began := time.Now() 135 n := int(rand.Int31n(20) + 10) 136 idxs := genIdxs(n) 137 keys, values1, values2 := genKeys(idxs), genValues(n, "value_"), genValues(n, "eulav_") 138 values3, values4 := genValues(n, "vvvv_"), genValues(n, "uuuu_") 139 go func() { 140 dc2 := NewClient(rdb, NewDefaultOptions()) 141 v, err := dc2.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values1, 200)) 142 assert.Nil(t, err) 143 assert.Equal(t, values1, v) 144 }() 145 time.Sleep(20 * time.Millisecond) 146 147 v, err := rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values2, 200)) 148 assert.Nil(t, err) 149 assert.Equal(t, values1, v) 150 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 151 152 err = rc.TagAsDeletedBatch(keys) 153 assert.Nil(t, err) 154 155 began = time.Now() 156 v, err = rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values3, 200)) 157 assert.Nil(t, err) 158 assert.Equal(t, values3, v) 159 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 160 161 v, err = rc.FetchBatch(keys, 60*time.Second, genBatchDataFunc(values4, 200)) 162 assert.Nil(t, err) 163 assert.Equal(t, values3, v) 164 } 165 166 func TestStrongFetchBatchOverlap(t *testing.T) { 167 clearCache() 168 rc := NewClient(rdb, NewDefaultOptions()) 169 rc.Options.StrongConsistency = true 170 began := time.Now() 171 n := 100 172 idxs := genIdxs(n) 173 keys := genKeys(idxs) 174 keys1, values1 := keys[:60], genValues(60, "value_") 175 keys2, values2 := keys[40:], genValues(60, "eulav_") 176 177 go func() { 178 dc2 := NewClient(rdb, NewDefaultOptions()) 179 v, err := dc2.FetchBatch(keys1, 20*time.Second, genBatchDataFunc(values1, 200)) 180 assert.Nil(t, err) 181 assert.Equal(t, values1, v) 182 }() 183 time.Sleep(20 * time.Millisecond) 184 185 v, err := rc.FetchBatch(keys2, 20*time.Second, genBatchDataFunc(values2, 200)) 186 assert.Nil(t, err) 187 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 188 for i := 40; i < 60; i++ { 189 assert.Equal(t, keys2[i-40], keys1[i]) 190 assert.Equal(t, values1[i], v[i-40]) 191 } 192 for i := 60; i < n; i++ { 193 assert.Equal(t, values2[i-40], v[i-40]) 194 } 195 } 196 197 func TestStrongFetchBatchOverlapExpire(t *testing.T) { 198 clearCache() 199 opts := NewDefaultOptions() 200 opts.Delay = 10 * time.Millisecond 201 opts.StrongConsistency = true 202 203 rc := NewClient(rdb, opts) 204 began := time.Now() 205 n := 100 206 idxs := genIdxs(n) 207 keys := genKeys(idxs) 208 keys1, values1 := keys[:60], genValues(60, "value_") 209 keys2, values2 := keys[40:], genValues(60, "eulav_") 210 211 v, err := rc.FetchBatch(keys1, 2*time.Second, genBatchDataFunc(values1, 200)) 212 assert.Nil(t, err) 213 assert.Equal(t, values1, v) 214 215 v, err = rc.FetchBatch(keys2, 2*time.Second, genBatchDataFunc(values2, 200)) 216 assert.Nil(t, err) 217 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 218 for i := 40; i < 60; i++ { 219 assert.Equal(t, keys2[i-40], keys1[i]) 220 assert.Equal(t, values1[i], v[i-40]) 221 } 222 for i := 60; i < n; i++ { 223 assert.Equal(t, values2[i-40], v[i-40]) 224 } 225 226 time.Sleep(time.Second) 227 v, err = rc.FetchBatch(keys2, 2*time.Second, genBatchDataFunc(values2, 100)) 228 assert.Nil(t, err) 229 assert.Nil(t, err) 230 assert.Equal(t, values2, v) 231 } 232 233 func TestStrongErrorFetchBatch(t *testing.T) { 234 rc := NewClient(rdb, NewDefaultOptions()) 235 rc.Options.StrongConsistency = true 236 237 clearCache() 238 began := time.Now() 239 240 n := 100 241 idxs := genIdxs(n) 242 keys := genKeys(idxs) 243 244 fetchError := errors.New("fetch error") 245 getFn := func(idxs []int) (map[int]string, error) { 246 return nil, fetchError 247 } 248 _, err := rc.FetchBatch(keys, 60*time.Second, getFn) 249 assert.Error(t, err) 250 fetchError = nil 251 _, err = rc.FetchBatch(keys, 60*time.Second, getFn) 252 assert.Nil(t, err) 253 assert.True(t, time.Since(began) < time.Duration(150)*time.Millisecond) 254 }