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  }