tkcashgame_v4/pkg/cache/rockscache/client_test.go

191 lines
4.8 KiB
Go

package rockscache
import (
"context"
"errors"
"testing"
"time"
"github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
var rdbKey = "client-test-key"
var rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Username: "root",
Password: "",
})
// var rdb = redis.NewClusterClient(&redis.ClusterOptions{
// Addrs: []string{"43.128.5.63:46381", "43.128.5.63:46382", "43.128.5.63:46380", "43.128.5.63:46383", "43.128.5.63:46384", "43.128.5.63:46385"},
// Username: "",
// Password: "",
// })
type iRedisCluster interface {
ForEachMaster(context.Context, func(context.Context, *redis.Client) error) error
}
func getCluster() iRedisCluster {
var rr interface{} = rdb
v, _ := rr.(iRedisCluster)
return v
}
func clearCache() {
var err error
if clu := getCluster(); clu != nil {
err = clu.ForEachMaster(rdb.Context(), func(ctx context.Context, master *redis.Client) error {
return master.FlushAll(ctx).Err()
})
} else {
err = rdb.FlushDB(rdb.Context()).Err()
}
if err != nil {
panic(err)
}
}
func genDataFunc(value string, sleepMilli int) func() (string, error) {
return func() (string, error) {
time.Sleep(time.Duration(sleepMilli) * time.Millisecond)
return value, nil
}
}
func init() {
SetVerbose(true)
}
func TestWeakFetch(t *testing.T) {
rc := NewClient[string](rdb, NewDefaultOptions())
clearCache()
began := time.Now()
expected := "value1"
go func() {
dc2 := NewClient[string](rdb, NewDefaultOptions())
v, err := dc2.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200))
assert.Nil(t, err)
assert.Equal(t, expected, v)
}()
time.Sleep(20 * time.Millisecond)
v, err := rc.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 201))
assert.Nil(t, err)
assert.Equal(t, expected, v)
assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond)
err = rc.TagAsDeleted(rdbKey)
assert.Nil(t, err)
nv := "value2"
v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc(nv, 200))
assert.Nil(t, err)
assert.Equal(t, expected, v)
time.Sleep(300 * time.Millisecond)
v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc("ignored", 200))
assert.Nil(t, err)
assert.Equal(t, nv, v)
}
func TestStrongFetch(t *testing.T) {
clearCache()
rc := NewClient[string](rdb, NewDefaultOptions())
rc.Options.StrongConsistency = true
began := time.Now()
expected := "value1"
go func() {
dc2 := NewClient[string](rdb, NewDefaultOptions())
v, err := dc2.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200))
assert.Nil(t, err)
assert.Equal(t, expected, v)
}()
time.Sleep(20 * time.Millisecond)
v, err := rc.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200))
assert.Nil(t, err)
assert.Equal(t, expected, v)
assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond)
err = rc.TagAsDeleted(rdbKey)
assert.Nil(t, err)
began = time.Now()
nv := "value2"
v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc(nv, 200))
assert.Nil(t, err)
assert.Equal(t, nv, v)
assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond)
v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc("ignored", 200))
assert.Nil(t, err)
assert.Equal(t, nv, v)
}
func TestStrongErrorFetch(t *testing.T) {
rc := NewClient[string](rdb, NewDefaultOptions())
rc.Options.StrongConsistency = true
clearCache()
began := time.Now()
fetchError := errors.New("fetch error")
getFn := func() (string, error) {
return "", fetchError
}
_, err := rc.Fetch(rdbKey, 60*time.Second, getFn)
assert.Error(t, err)
fetchError = nil
_, err = rc.Fetch(rdbKey, 60*time.Second, getFn)
assert.Nil(t, err)
assert.True(t, time.Since(began) < time.Duration(150)*time.Millisecond)
}
func TestWeakErrorFetch(t *testing.T) {
rc := NewClient[string](rdb, NewDefaultOptions())
clearCache()
began := time.Now()
fetchError := errors.New("fetch error")
getFn := func() (string, error) {
return "", fetchError
}
_, err := rc.Fetch(rdbKey, 60*time.Second, getFn)
assert.Error(t, err)
fetchError = nil
_, err = rc.Fetch(rdbKey, 60*time.Second, getFn)
assert.Nil(t, err)
assert.True(t, time.Since(began) < time.Duration(150)*time.Millisecond)
}
func TestRawGet(t *testing.T) {
rc := NewClient(rdb, NewDefaultOptions())
_, err := rc.RawGet(rdb.Context(), "not-exists")
assert.Error(t, redis.Nil, err)
}
func TestRawSet(t *testing.T) {
rc := NewClient(rdb, NewDefaultOptions())
err := rc.RawSet(rdb.Context(), "eeeee", "value", 60*time.Second)
assert.Nil(t, err)
}
func TestLock(t *testing.T) {
rc := NewClient(rdb, NewDefaultOptions())
rc.Options.StrongConsistency = true
owner := "test_owner"
key := "test_lock"
err := rc.LockForUpdate(rdb.Context(), key, owner)
assert.Nil(t, err)
err = rc.LockForUpdate(rdb.Context(), key, "other_owner")
assert.Error(t, err)
err = rc.UnlockForUpdate(rdb.Context(), key, owner)
assert.Nil(t, err)
}