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  }