gitee.com/go-spring2/spring-base@v1.1.3/cache/cache_test.go (about) 1 /* 2 * Copyright 2012-2019 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cache_test 18 19 import ( 20 "context" 21 "errors" 22 "sort" 23 "sync" 24 "testing" 25 "time" 26 27 "gitee.com/go-spring2/spring-base/assert" 28 "gitee.com/go-spring2/spring-base/cache" 29 ) 30 31 type response struct { 32 name string 33 } 34 35 type injection struct { 36 expire time.Duration 37 resp interface{} 38 data *response 39 err error 40 } 41 42 var ctxInjectionKey int 43 44 func getInjection(ctx context.Context) *injection { 45 return ctx.Value(&ctxInjectionKey).(*injection) 46 } 47 48 func setInjection(ctx context.Context, i *injection) context.Context { 49 return context.WithValue(ctx, &ctxInjectionKey, i) 50 } 51 52 func loadResponse(ctx context.Context, key string, delay time.Duration) (*response, cache.LoadType, error) { 53 54 i := getInjection(ctx) 55 loader := func(ctx context.Context, key string) (interface{}, error) { 56 if delay > 0 { 57 time.Sleep(delay) 58 } 59 if i.err != nil { 60 return nil, i.err 61 } 62 i.data.name = key 63 return i.data, nil 64 } 65 66 opts := []cache.Option{ 67 cache.ExpireAfterWrite(i.expire), 68 } 69 loadType, result, err := cache.Load(ctx, key, loader, opts...) 70 if err != nil { 71 return nil, cache.LoadNone, err 72 } 73 74 if _, ok := i.resp.(*response); ok { 75 var resp *response 76 err = result.Load(&resp) 77 if err != nil { 78 return nil, cache.LoadNone, err 79 } 80 return resp, loadType, nil 81 } 82 83 var resp int 84 err = result.Load(&resp) 85 return nil, cache.LoadNone, err 86 } 87 88 type LoadTypeSlice []cache.LoadType 89 90 func (p LoadTypeSlice) Len() int { return len(p) } 91 func (p LoadTypeSlice) Less(i, j int) bool { return p[i] > p[j] } 92 func (p LoadTypeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 93 94 func testFunc(key string, i *injection) ([]interface{}, []cache.LoadType) { 95 ctx := setInjection(context.Background(), i) 96 97 var ( 98 datas []interface{} 99 types []cache.LoadType 100 lock sync.Mutex 101 ) 102 103 wg := sync.WaitGroup{} 104 for j := 0; j < 3; j++ { 105 jj := j 106 delay := 10 * time.Millisecond 107 wg.Add(1) 108 go func() { 109 if jj == 1 { 110 time.Sleep(delay) 111 } 112 defer wg.Done() 113 resp, loadType, err := loadResponse(ctx, key, delay) 114 lock.Lock() 115 if err != nil { 116 datas = append(datas, err) 117 118 } else { 119 datas = append(datas, resp) 120 } 121 types = append(types, loadType) 122 lock.Unlock() 123 }() 124 } 125 wg.Wait() 126 127 sort.Sort(LoadTypeSlice(types)) 128 return datas, types 129 } 130 131 func TestCache(t *testing.T) { 132 133 old := cache.Cache 134 defer func() { cache.Cache = old }() 135 136 for size := 1; size < 3; size++ { 137 cache.Cache = cache.NewStorage(size, cache.SimpleHash) 138 139 t.Run("response error", func(t *testing.T) { 140 testKey := "test" 141 defer func() { 142 (cache.Cache).(*cache.Storage).Reset() 143 }() 144 i := &injection{ 145 err: errors.New("this is an error"), 146 } 147 datas, types := testFunc(testKey, i) 148 assert.Equal(t, datas, []interface{}{ 149 errors.New("this is an error"), 150 errors.New("this is an error"), 151 errors.New("this is an error"), 152 }) 153 assert.Equal(t, types, []cache.LoadType{ 154 cache.LoadNone, 155 cache.LoadNone, 156 cache.LoadNone, 157 }) 158 }) 159 160 t.Run("response success", func(t *testing.T) { 161 testKey := "test1234567890test1234567890" 162 defer func() { 163 (cache.Cache).(*cache.Storage).Reset() 164 }() 165 assert.False(t, cache.Has(testKey)) 166 i := &injection{ 167 expire: 50 * time.Millisecond, 168 resp: &response{}, 169 data: &response{}, 170 } 171 datas, types := testFunc(testKey, i) 172 assert.Equal(t, datas, []interface{}{ 173 &response{name: testKey}, 174 &response{name: testKey}, 175 &response{name: testKey}, 176 }) 177 assert.Equal(t, types, []cache.LoadType{ 178 cache.LoadSource, 179 cache.LoadCache, 180 cache.LoadCache, 181 }) 182 time.Sleep(150 * time.Millisecond) 183 assert.False(t, cache.Has(testKey)) 184 }) 185 186 t.Run("response success without expired", func(t *testing.T) { 187 testKey := "test1234567890" 188 defer func() { 189 (cache.Cache).(*cache.Storage).Reset() 190 }() 191 assert.False(t, cache.Has(testKey)) 192 i := &injection{ 193 resp: &response{}, 194 data: &response{}, 195 } 196 datas, types := testFunc(testKey, i) 197 assert.Equal(t, datas, []interface{}{ 198 &response{name: testKey}, 199 &response{name: testKey}, 200 &response{name: testKey}, 201 }) 202 assert.Equal(t, types, []cache.LoadType{ 203 cache.LoadSource, 204 cache.LoadCache, 205 cache.LoadCache, 206 }) 207 time.Sleep(150 * time.Millisecond) 208 assert.True(t, cache.Has(testKey)) 209 }) 210 211 t.Run("load error", func(t *testing.T) { 212 testKey := "test" 213 defer func() { 214 (cache.Cache).(*cache.Storage).Reset() 215 }() 216 i := &injection{ 217 resp: map[string]string{}, 218 data: &response{}, 219 } 220 datas, types := testFunc(testKey, i) 221 assert.Equal(t, datas, []interface{}{ 222 errors.New("load type (int) but expect type (*cache_test.response)"), 223 errors.New("load type (int) but expect type (*cache_test.response)"), 224 errors.New("load type (int) but expect type (*cache_test.response)"), 225 }) 226 assert.Equal(t, types, []cache.LoadType{ 227 cache.LoadNone, 228 cache.LoadNone, 229 cache.LoadNone, 230 }) 231 }) 232 } 233 }