github.com/dtm-labs/rockscache@v0.1.1/client_test.go (about) 1 package rockscache 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/redis/go-redis/v9" 10 "github.com/stretchr/testify/assert" 11 ) 12 13 var rdbKey = "client-test-key" 14 15 var rdb = redis.NewClient(&redis.Options{ 16 Addr: "localhost:6379", 17 Username: "root", 18 Password: "", 19 }) 20 var ctx = context.Background() 21 22 // var rdb = redis.NewClusterClient(&redis.ClusterOptions{ 23 // 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"}, 24 // Username: "", 25 // Password: "", 26 // }) 27 28 type iRedisCluster interface { 29 ForEachMaster(context.Context, func(context.Context, *redis.Client) error) error 30 } 31 32 func getCluster() iRedisCluster { 33 var rr interface{} = rdb 34 v, _ := rr.(iRedisCluster) 35 return v 36 } 37 38 func clearCache() { 39 var err error 40 if clu := getCluster(); clu != nil { 41 err = clu.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { 42 return master.FlushAll(ctx).Err() 43 }) 44 } else { 45 err = rdb.FlushDB(ctx).Err() 46 } 47 48 if err != nil { 49 panic(err) 50 } 51 } 52 53 func genDataFunc(value string, sleepMilli int) func() (string, error) { 54 return func() (string, error) { 55 time.Sleep(time.Duration(sleepMilli) * time.Millisecond) 56 return value, nil 57 } 58 } 59 60 func init() { 61 SetVerbose(true) 62 } 63 func TestWeakFetch(t *testing.T) { 64 rc := NewClient(rdb, NewDefaultOptions()) 65 66 clearCache() 67 began := time.Now() 68 expected := "value1" 69 go func() { 70 dc2 := NewClient(rdb, NewDefaultOptions()) 71 v, err := dc2.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200)) 72 assert.Nil(t, err) 73 assert.Equal(t, expected, v) 74 }() 75 time.Sleep(20 * time.Millisecond) 76 77 v, err := rc.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 201)) 78 assert.Nil(t, err) 79 assert.Equal(t, expected, v) 80 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 81 82 err = rc.TagAsDeleted(rdbKey) 83 assert.Nil(t, err) 84 85 nv := "value2" 86 v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc(nv, 200)) 87 assert.Nil(t, err) 88 assert.Equal(t, expected, v) 89 90 time.Sleep(300 * time.Millisecond) 91 v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc("ignored", 200)) 92 assert.Nil(t, err) 93 assert.Equal(t, nv, v) 94 } 95 96 func TestStrongFetch(t *testing.T) { 97 clearCache() 98 rc := NewClient(rdb, NewDefaultOptions()) 99 rc.Options.StrongConsistency = true 100 began := time.Now() 101 expected := "value1" 102 go func() { 103 dc2 := NewClient(rdb, NewDefaultOptions()) 104 v, err := dc2.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200)) 105 assert.Nil(t, err) 106 assert.Equal(t, expected, v) 107 }() 108 time.Sleep(20 * time.Millisecond) 109 110 v, err := rc.Fetch(rdbKey, 60*time.Second, genDataFunc(expected, 200)) 111 assert.Nil(t, err) 112 assert.Equal(t, expected, v) 113 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 114 115 err = rc.TagAsDeleted(rdbKey) 116 assert.Nil(t, err) 117 118 began = time.Now() 119 nv := "value2" 120 v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc(nv, 200)) 121 assert.Nil(t, err) 122 assert.Equal(t, nv, v) 123 assert.True(t, time.Since(began) > time.Duration(150)*time.Millisecond) 124 125 v, err = rc.Fetch(rdbKey, 60*time.Second, genDataFunc("ignored", 200)) 126 assert.Nil(t, err) 127 assert.Equal(t, nv, v) 128 129 } 130 131 func TestStrongErrorFetch(t *testing.T) { 132 rc := NewClient(rdb, NewDefaultOptions()) 133 rc.Options.StrongConsistency = true 134 135 clearCache() 136 began := time.Now() 137 138 fetchError := errors.New("fetch error") 139 getFn := func() (string, error) { 140 return "", fetchError 141 } 142 _, err := rc.Fetch(rdbKey, 60*time.Second, getFn) 143 assert.Error(t, err) 144 fetchError = nil 145 _, err = rc.Fetch(rdbKey, 60*time.Second, getFn) 146 assert.Nil(t, err) 147 assert.True(t, time.Since(began) < time.Duration(150)*time.Millisecond) 148 } 149 150 func TestWeakErrorFetch(t *testing.T) { 151 rc := NewClient(rdb, NewDefaultOptions()) 152 153 clearCache() 154 began := time.Now() 155 156 fetchError := errors.New("fetch error") 157 getFn := func() (string, error) { 158 return "", fetchError 159 } 160 _, err := rc.Fetch(rdbKey, 60*time.Second, getFn) 161 assert.Error(t, err) 162 fetchError = nil 163 _, err = rc.Fetch(rdbKey, 60*time.Second, getFn) 164 assert.Nil(t, err) 165 assert.True(t, time.Since(began) < time.Duration(150)*time.Millisecond) 166 } 167 168 func TestRawGet(t *testing.T) { 169 rc := NewClient(rdb, NewDefaultOptions()) 170 _, err := rc.RawGet(ctx, "not-exists") 171 assert.Error(t, redis.Nil, err) 172 } 173 174 func TestRawSet(t *testing.T) { 175 rc := NewClient(rdb, NewDefaultOptions()) 176 err := rc.RawSet(ctx, "eeeee", "value", 60*time.Second) 177 assert.Nil(t, err) 178 } 179 180 func TestLock(t *testing.T) { 181 rc := NewClient(rdb, NewDefaultOptions()) 182 rc.Options.StrongConsistency = true 183 owner := "test_owner" 184 key := "test_lock" 185 err := rc.LockForUpdate(ctx, key, owner) 186 assert.Nil(t, err) 187 err = rc.LockForUpdate(ctx, key, "other_owner") 188 assert.Error(t, err) 189 err = rc.UnlockForUpdate(ctx, key, owner) 190 assert.Nil(t, err) 191 }