initial import

This commit is contained in:
kevin
2020-07-26 17:09:05 +08:00
commit 7e3a369a8f
647 changed files with 54754 additions and 0 deletions

5
core/stores/kv/config.go Normal file
View File

@@ -0,0 +1,5 @@
package kv
import "zero/core/stores/internal"
type KvConf = internal.ClusterConf

653
core/stores/kv/store.go Normal file
View File

@@ -0,0 +1,653 @@
package kv
import (
"errors"
"log"
"zero/core/errorx"
"zero/core/hash"
"zero/core/stores/internal"
"zero/core/stores/redis"
)
var ErrNoRedisNode = errors.New("no redis node")
type (
Store interface {
Del(keys ...string) (int, error)
Eval(script string, key string, args ...interface{}) (interface{}, error)
Exists(key string) (bool, error)
Expire(key string, seconds int) error
Expireat(key string, expireTime int64) error
Get(key string) (string, error)
Hdel(key, field string) (bool, error)
Hexists(key, field string) (bool, error)
Hget(key, field string) (string, error)
Hgetall(key string) (map[string]string, error)
Hincrby(key, field string, increment int) (int, error)
Hkeys(key string) ([]string, error)
Hlen(key string) (int, error)
Hmget(key string, fields ...string) ([]string, error)
Hset(key, field, value string) error
Hsetnx(key, field, value string) (bool, error)
Hmset(key string, fieldsAndValues map[string]string) error
Hvals(key string) ([]string, error)
Incr(key string) (int64, error)
Incrby(key string, increment int64) (int64, error)
Llen(key string) (int, error)
Lpop(key string) (string, error)
Lpush(key string, values ...interface{}) (int, error)
Lrange(key string, start int, stop int) ([]string, error)
Lrem(key string, count int, value string) (int, error)
Persist(key string) (bool, error)
Pfadd(key string, values ...interface{}) (bool, error)
Pfcount(key string) (int64, error)
Rpush(key string, values ...interface{}) (int, error)
Sadd(key string, values ...interface{}) (int, error)
Scard(key string) (int64, error)
Set(key string, value string) error
Setex(key, value string, seconds int) error
Setnx(key, value string) (bool, error)
SetnxEx(key, value string, seconds int) (bool, error)
Sismember(key string, value interface{}) (bool, error)
Smembers(key string) ([]string, error)
Spop(key string) (string, error)
Srandmember(key string, count int) ([]string, error)
Srem(key string, values ...interface{}) (int, error)
Sscan(key string, cursor uint64, match string, count int64) (keys []string, cur uint64, err error)
Ttl(key string) (int, error)
Zadd(key string, score int64, value string) (bool, error)
Zadds(key string, ps ...redis.Pair) (int64, error)
Zcard(key string) (int, error)
Zcount(key string, start, stop int64) (int, error)
Zincrby(key string, increment int64, field string) (int64, error)
Zrange(key string, start, stop int64) ([]string, error)
ZrangeWithScores(key string, start, stop int64) ([]redis.Pair, error)
ZrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error)
ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) ([]redis.Pair, error)
Zrank(key, field string) (int64, error)
Zrem(key string, values ...interface{}) (int, error)
Zremrangebyrank(key string, start, stop int64) (int, error)
Zremrangebyscore(key string, start, stop int64) (int, error)
Zrevrange(key string, start, stop int64) ([]string, error)
ZrevrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error)
ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) ([]redis.Pair, error)
Zscore(key string, value string) (int64, error)
}
clusterStore struct {
dispatcher *hash.ConsistentHash
}
)
func NewStore(c KvConf) Store {
if len(c) == 0 || internal.TotalWeights(c) <= 0 {
log.Fatal("no cache nodes")
}
// even if only one node, we chose to use consistent hash,
// because Store and redis.Redis has different methods.
dispatcher := hash.NewConsistentHash()
for _, node := range c {
cn := node.NewRedis()
dispatcher.AddWithWeight(cn, node.Weight)
}
return clusterStore{
dispatcher: dispatcher,
}
}
func (cs clusterStore) Del(keys ...string) (int, error) {
var val int
var be errorx.BatchError
for _, key := range keys {
node, e := cs.getRedis(key)
if e != nil {
be.Add(e)
continue
}
if v, e := node.Del(key); e != nil {
be.Add(e)
} else {
val += v
}
}
return val, be.Err()
}
func (cs clusterStore) Eval(script string, key string, args ...interface{}) (interface{}, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Eval(script, []string{key}, args...)
}
func (cs clusterStore) Exists(key string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Exists(key)
}
func (cs clusterStore) Expire(key string, seconds int) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Expire(key, seconds)
}
func (cs clusterStore) Expireat(key string, expireTime int64) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Expireat(key, expireTime)
}
func (cs clusterStore) Get(key string) (string, error) {
node, err := cs.getRedis(key)
if err != nil {
return "", err
}
return node.Get(key)
}
func (cs clusterStore) Hdel(key, field string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Hdel(key, field)
}
func (cs clusterStore) Hexists(key, field string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Hexists(key, field)
}
func (cs clusterStore) Hget(key, field string) (string, error) {
node, err := cs.getRedis(key)
if err != nil {
return "", err
}
return node.Hget(key, field)
}
func (cs clusterStore) Hgetall(key string) (map[string]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Hgetall(key)
}
func (cs clusterStore) Hincrby(key, field string, increment int) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Hincrby(key, field, increment)
}
func (cs clusterStore) Hkeys(key string) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Hkeys(key)
}
func (cs clusterStore) Hlen(key string) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Hlen(key)
}
func (cs clusterStore) Hmget(key string, fields ...string) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Hmget(key, fields...)
}
func (cs clusterStore) Hset(key, field, value string) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Hset(key, field, value)
}
func (cs clusterStore) Hsetnx(key, field, value string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Hsetnx(key, field, value)
}
func (cs clusterStore) Hmset(key string, fieldsAndValues map[string]string) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Hmset(key, fieldsAndValues)
}
func (cs clusterStore) Hvals(key string) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Hvals(key)
}
func (cs clusterStore) Incr(key string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Incr(key)
}
func (cs clusterStore) Incrby(key string, increment int64) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Incrby(key, increment)
}
func (cs clusterStore) Llen(key string) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Llen(key)
}
func (cs clusterStore) Lpop(key string) (string, error) {
node, err := cs.getRedis(key)
if err != nil {
return "", err
}
return node.Lpop(key)
}
func (cs clusterStore) Lpush(key string, values ...interface{}) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Lpush(key, values...)
}
func (cs clusterStore) Lrange(key string, start int, stop int) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Lrange(key, start, stop)
}
func (cs clusterStore) Lrem(key string, count int, value string) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Lrem(key, count, value)
}
func (cs clusterStore) Persist(key string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Persist(key)
}
func (cs clusterStore) Pfadd(key string, values ...interface{}) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Pfadd(key, values...)
}
func (cs clusterStore) Pfcount(key string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Pfcount(key)
}
func (cs clusterStore) Rpush(key string, values ...interface{}) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Rpush(key, values...)
}
func (cs clusterStore) Sadd(key string, values ...interface{}) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Sadd(key, values...)
}
func (cs clusterStore) Scard(key string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Scard(key)
}
func (cs clusterStore) Set(key string, value string) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Set(key, value)
}
func (cs clusterStore) Setex(key, value string, seconds int) error {
node, err := cs.getRedis(key)
if err != nil {
return err
}
return node.Setex(key, value, seconds)
}
func (cs clusterStore) Setnx(key, value string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Setnx(key, value)
}
func (cs clusterStore) SetnxEx(key, value string, seconds int) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.SetnxEx(key, value, seconds)
}
func (cs clusterStore) Sismember(key string, value interface{}) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Sismember(key, value)
}
func (cs clusterStore) Smembers(key string) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Smembers(key)
}
func (cs clusterStore) Spop(key string) (string, error) {
node, err := cs.getRedis(key)
if err != nil {
return "", err
}
return node.Spop(key)
}
func (cs clusterStore) Srandmember(key string, count int) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Srandmember(key, count)
}
func (cs clusterStore) Srem(key string, values ...interface{}) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Srem(key, values...)
}
func (cs clusterStore) Sscan(key string, cursor uint64, match string, count int64) (
keys []string, cur uint64, err error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, 0, err
}
return node.Sscan(key, cursor, match, count)
}
func (cs clusterStore) Ttl(key string) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Ttl(key)
}
func (cs clusterStore) Zadd(key string, score int64, value string) (bool, error) {
node, err := cs.getRedis(key)
if err != nil {
return false, err
}
return node.Zadd(key, score, value)
}
func (cs clusterStore) Zadds(key string, ps ...redis.Pair) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zadds(key, ps...)
}
func (cs clusterStore) Zcard(key string) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zcard(key)
}
func (cs clusterStore) Zcount(key string, start, stop int64) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zcount(key, start, stop)
}
func (cs clusterStore) Zincrby(key string, increment int64, field string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zincrby(key, increment, field)
}
func (cs clusterStore) Zrank(key, field string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zrank(key, field)
}
func (cs clusterStore) Zrange(key string, start, stop int64) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Zrange(key, start, stop)
}
func (cs clusterStore) ZrangeWithScores(key string, start, stop int64) ([]redis.Pair, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.ZrangeWithScores(key, start, stop)
}
func (cs clusterStore) ZrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.ZrangebyscoreWithScores(key, start, stop)
}
func (cs clusterStore) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
[]redis.Pair, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.ZrangebyscoreWithScoresAndLimit(key, start, stop, page, size)
}
func (cs clusterStore) Zrem(key string, values ...interface{}) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zrem(key, values...)
}
func (cs clusterStore) Zremrangebyrank(key string, start, stop int64) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zremrangebyrank(key, start, stop)
}
func (cs clusterStore) Zremrangebyscore(key string, start, stop int64) (int, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zremrangebyscore(key, start, stop)
}
func (cs clusterStore) Zrevrange(key string, start, stop int64) ([]string, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.Zrevrange(key, start, stop)
}
func (cs clusterStore) ZrevrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.ZrevrangebyscoreWithScores(key, start, stop)
}
func (cs clusterStore) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
[]redis.Pair, error) {
node, err := cs.getRedis(key)
if err != nil {
return nil, err
}
return node.ZrevrangebyscoreWithScoresAndLimit(key, start, stop, page, size)
}
func (cs clusterStore) Zscore(key string, value string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Zscore(key, value)
}
func (cs clusterStore) getRedis(key string) (*redis.Redis, error) {
if val, ok := cs.dispatcher.Get(key); !ok {
return nil, ErrNoRedisNode
} else {
return val.(*redis.Redis), nil
}
}

View File

@@ -0,0 +1,498 @@
package kv
import (
"testing"
"time"
"zero/core/stores/internal"
"zero/core/stores/redis"
"zero/core/stringx"
"github.com/alicebob/miniredis"
"github.com/stretchr/testify/assert"
)
var s1, _ = miniredis.Run()
var s2, _ = miniredis.Run()
func TestRedis_Exists(t *testing.T) {
runOnCluster(t, func(client Store) {
ok, err := client.Exists("a")
assert.Nil(t, err)
assert.False(t, ok)
assert.Nil(t, client.Set("a", "b"))
ok, err = client.Exists("a")
assert.Nil(t, err)
assert.True(t, ok)
})
}
func TestRedis_Eval(t *testing.T) {
runOnCluster(t, func(client Store) {
_, err := client.Eval(`redis.call("EXISTS", KEYS[1])`, "notexist")
assert.Equal(t, redis.Nil, err)
err = client.Set("key1", "value1")
assert.Nil(t, err)
_, err = client.Eval(`redis.call("EXISTS", KEYS[1])`, "key1")
assert.Equal(t, redis.Nil, err)
val, err := client.Eval(`return redis.call("EXISTS", KEYS[1])`, "key1")
assert.Nil(t, err)
assert.Equal(t, int64(1), val)
})
}
func TestRedis_Hgetall(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
vals, err := client.Hgetall("a")
assert.Nil(t, err)
assert.EqualValues(t, map[string]string{
"aa": "aaa",
"bb": "bbb",
}, vals)
})
}
func TestRedis_Hvals(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
vals, err := client.Hvals("a")
assert.Nil(t, err)
assert.ElementsMatch(t, []string{"aaa", "bbb"}, vals)
})
}
func TestRedis_Hsetnx(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
ok, err := client.Hsetnx("a", "bb", "ccc")
assert.Nil(t, err)
assert.False(t, ok)
ok, err = client.Hsetnx("a", "dd", "ddd")
assert.Nil(t, err)
assert.True(t, ok)
vals, err := client.Hvals("a")
assert.Nil(t, err)
assert.ElementsMatch(t, []string{"aaa", "bbb", "ddd"}, vals)
})
}
func TestRedis_HdelHlen(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
num, err := client.Hlen("a")
assert.Nil(t, err)
assert.Equal(t, 2, num)
val, err := client.Hdel("a", "aa")
assert.Nil(t, err)
assert.True(t, val)
vals, err := client.Hvals("a")
assert.Nil(t, err)
assert.ElementsMatch(t, []string{"bbb"}, vals)
})
}
func TestRedis_HIncrBy(t *testing.T) {
runOnCluster(t, func(client Store) {
val, err := client.Hincrby("key", "field", 2)
assert.Nil(t, err)
assert.Equal(t, 2, val)
val, err = client.Hincrby("key", "field", 3)
assert.Nil(t, err)
assert.Equal(t, 5, val)
})
}
func TestRedis_Hkeys(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
vals, err := client.Hkeys("a")
assert.Nil(t, err)
assert.ElementsMatch(t, []string{"aa", "bb"}, vals)
})
}
func TestRedis_Hmget(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hset("a", "aa", "aaa"))
assert.Nil(t, client.Hset("a", "bb", "bbb"))
vals, err := client.Hmget("a", "aa", "bb")
assert.Nil(t, err)
assert.EqualValues(t, []string{"aaa", "bbb"}, vals)
vals, err = client.Hmget("a", "aa", "no", "bb")
assert.Nil(t, err)
assert.EqualValues(t, []string{"aaa", "", "bbb"}, vals)
})
}
func TestRedis_Hmset(t *testing.T) {
runOnCluster(t, func(client Store) {
assert.Nil(t, client.Hmset("a", map[string]string{
"aa": "aaa",
"bb": "bbb",
}))
vals, err := client.Hmget("a", "aa", "bb")
assert.Nil(t, err)
assert.EqualValues(t, []string{"aaa", "bbb"}, vals)
})
}
func TestRedis_Incr(t *testing.T) {
runOnCluster(t, func(client Store) {
val, err := client.Incr("a")
assert.Nil(t, err)
assert.Equal(t, int64(1), val)
val, err = client.Incr("a")
assert.Nil(t, err)
assert.Equal(t, int64(2), val)
})
}
func TestRedis_IncrBy(t *testing.T) {
runOnCluster(t, func(client Store) {
val, err := client.Incrby("a", 2)
assert.Nil(t, err)
assert.Equal(t, int64(2), val)
val, err = client.Incrby("a", 3)
assert.Nil(t, err)
assert.Equal(t, int64(5), val)
})
}
func TestRedis_List(t *testing.T) {
runOnCluster(t, func(client Store) {
val, err := client.Lpush("key", "value1", "value2")
assert.Nil(t, err)
assert.Equal(t, 2, val)
val, err = client.Rpush("key", "value3", "value4")
assert.Nil(t, err)
assert.Equal(t, 4, val)
val, err = client.Llen("key")
assert.Nil(t, err)
assert.Equal(t, 4, val)
vals, err := client.Lrange("key", 0, 10)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value1", "value3", "value4"}, vals)
v, err := client.Lpop("key")
assert.Nil(t, err)
assert.Equal(t, "value2", v)
val, err = client.Lpush("key", "value1", "value2")
assert.Nil(t, err)
assert.Equal(t, 5, val)
val, err = client.Rpush("key", "value3", "value3")
assert.Nil(t, err)
assert.Equal(t, 7, val)
n, err := client.Lrem("key", 2, "value1")
assert.Nil(t, err)
assert.Equal(t, 2, n)
vals, err = client.Lrange("key", 0, 10)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value3", "value4", "value3", "value3"}, vals)
n, err = client.Lrem("key", -2, "value3")
assert.Nil(t, err)
assert.Equal(t, 2, n)
vals, err = client.Lrange("key", 0, 10)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value3", "value4"}, vals)
})
}
func TestRedis_Persist(t *testing.T) {
runOnCluster(t, func(client Store) {
ok, err := client.Persist("key")
assert.Nil(t, err)
assert.False(t, ok)
err = client.Set("key", "value")
assert.Nil(t, err)
ok, err = client.Persist("key")
assert.Nil(t, err)
assert.False(t, ok)
err = client.Expire("key", 5)
ok, err = client.Persist("key")
assert.Nil(t, err)
assert.True(t, ok)
err = client.Expireat("key", time.Now().Unix()+5)
ok, err = client.Persist("key")
assert.Nil(t, err)
assert.True(t, ok)
})
}
func TestRedis_Sscan(t *testing.T) {
runOnCluster(t, func(client Store) {
key := "list"
var list []string
for i := 0; i < 1550; i++ {
list = append(list, stringx.Randn(i))
}
lens, err := client.Sadd(key, list)
assert.Nil(t, err)
assert.Equal(t, lens, 1550)
var cursor uint64 = 0
sum := 0
for {
keys, next, err := client.Sscan(key, cursor, "", 100)
assert.Nil(t, err)
sum += len(keys)
if next == 0 {
break
}
cursor = next
}
assert.Equal(t, sum, 1550)
_, err = client.Del(key)
assert.Nil(t, err)
})
}
func TestRedis_Set(t *testing.T) {
runOnCluster(t, func(client Store) {
num, err := client.Sadd("key", 1, 2, 3, 4)
assert.Nil(t, err)
assert.Equal(t, 4, num)
val, err := client.Scard("key")
assert.Nil(t, err)
assert.Equal(t, int64(4), val)
ok, err := client.Sismember("key", 2)
assert.Nil(t, err)
assert.True(t, ok)
num, err = client.Srem("key", 3, 4)
assert.Nil(t, err)
assert.Equal(t, 2, num)
vals, err := client.Smembers("key")
assert.Nil(t, err)
assert.ElementsMatch(t, []string{"1", "2"}, vals)
members, err := client.Srandmember("key", 1)
assert.Nil(t, err)
assert.Len(t, members, 1)
assert.Contains(t, []string{"1", "2"}, members[0])
member, err := client.Spop("key")
assert.Nil(t, err)
assert.Contains(t, []string{"1", "2"}, member)
vals, err = client.Smembers("key")
assert.Nil(t, err)
assert.NotContains(t, vals, member)
num, err = client.Sadd("key1", 1, 2, 3, 4)
assert.Nil(t, err)
assert.Equal(t, 4, num)
num, err = client.Sadd("key2", 2, 3, 4, 5)
assert.Nil(t, err)
assert.Equal(t, 4, num)
})
}
func TestRedis_SetGetDel(t *testing.T) {
runOnCluster(t, func(client Store) {
err := client.Set("hello", "world")
assert.Nil(t, err)
val, err := client.Get("hello")
assert.Nil(t, err)
assert.Equal(t, "world", val)
ret, err := client.Del("hello")
assert.Nil(t, err)
assert.Equal(t, 1, ret)
})
}
func TestRedis_SetExNx(t *testing.T) {
runOnCluster(t, func(client Store) {
err := client.Setex("hello", "world", 5)
assert.Nil(t, err)
ok, err := client.Setnx("hello", "newworld")
assert.Nil(t, err)
assert.False(t, ok)
ok, err = client.Setnx("newhello", "newworld")
assert.Nil(t, err)
assert.True(t, ok)
val, err := client.Get("hello")
assert.Nil(t, err)
assert.Equal(t, "world", val)
val, err = client.Get("newhello")
assert.Nil(t, err)
assert.Equal(t, "newworld", val)
ttl, err := client.Ttl("hello")
assert.Nil(t, err)
assert.True(t, ttl > 0)
ok, err = client.SetnxEx("newhello", "newworld", 5)
assert.Nil(t, err)
assert.False(t, ok)
num, err := client.Del("newhello")
assert.Nil(t, err)
assert.Equal(t, 1, num)
ok, err = client.SetnxEx("newhello", "newworld", 5)
assert.Nil(t, err)
assert.True(t, ok)
val, err = client.Get("newhello")
assert.Nil(t, err)
assert.Equal(t, "newworld", val)
})
}
func TestRedis_SetGetDelHashField(t *testing.T) {
runOnCluster(t, func(client Store) {
err := client.Hset("key", "field", "value")
assert.Nil(t, err)
val, err := client.Hget("key", "field")
assert.Nil(t, err)
assert.Equal(t, "value", val)
ok, err := client.Hexists("key", "field")
assert.Nil(t, err)
assert.True(t, ok)
ret, err := client.Hdel("key", "field")
assert.Nil(t, err)
assert.True(t, ret)
ok, err = client.Hexists("key", "field")
assert.Nil(t, err)
assert.False(t, ok)
})
}
func TestRedis_SortedSet(t *testing.T) {
runOnCluster(t, func(client Store) {
ok, err := client.Zadd("key", 1, "value1")
assert.Nil(t, err)
assert.True(t, ok)
ok, err = client.Zadd("key", 2, "value1")
assert.Nil(t, err)
assert.False(t, ok)
val, err := client.Zscore("key", "value1")
assert.Nil(t, err)
assert.Equal(t, int64(2), val)
val, err = client.Zincrby("key", 3, "value1")
assert.Nil(t, err)
assert.Equal(t, int64(5), val)
val, err = client.Zscore("key", "value1")
assert.Nil(t, err)
assert.Equal(t, int64(5), val)
ok, err = client.Zadd("key", 6, "value2")
assert.Nil(t, err)
assert.True(t, ok)
ok, err = client.Zadd("key", 7, "value3")
assert.Nil(t, err)
assert.True(t, ok)
rank, err := client.Zrank("key", "value2")
assert.Nil(t, err)
assert.Equal(t, int64(1), rank)
rank, err = client.Zrank("key", "value4")
assert.Equal(t, redis.Nil, err)
num, err := client.Zrem("key", "value2", "value3")
assert.Nil(t, err)
assert.Equal(t, 2, num)
ok, err = client.Zadd("key", 6, "value2")
assert.Nil(t, err)
assert.True(t, ok)
ok, err = client.Zadd("key", 7, "value3")
assert.Nil(t, err)
assert.True(t, ok)
ok, err = client.Zadd("key", 8, "value4")
assert.Nil(t, err)
assert.True(t, ok)
num, err = client.Zremrangebyscore("key", 6, 7)
assert.Nil(t, err)
assert.Equal(t, 2, num)
ok, err = client.Zadd("key", 6, "value2")
assert.Nil(t, err)
assert.True(t, ok)
ok, err = client.Zadd("key", 7, "value3")
assert.Nil(t, err)
assert.True(t, ok)
num, err = client.Zcount("key", 6, 7)
assert.Nil(t, err)
assert.Equal(t, 2, num)
num, err = client.Zremrangebyrank("key", 1, 2)
assert.Nil(t, err)
assert.Equal(t, 2, num)
card, err := client.Zcard("key")
assert.Nil(t, err)
assert.Equal(t, 2, card)
vals, err := client.Zrange("key", 0, -1)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value1", "value4"}, vals)
vals, err = client.Zrevrange("key", 0, -1)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value4", "value1"}, vals)
pairs, err := client.ZrangeWithScores("key", 0, -1)
assert.Nil(t, err)
assert.EqualValues(t, []redis.Pair{
{
Key: "value1",
Score: 5,
},
{
Key: "value4",
Score: 8,
},
}, pairs)
pairs, err = client.ZrangebyscoreWithScores("key", 5, 8)
assert.Nil(t, err)
assert.EqualValues(t, []redis.Pair{
{
Key: "value1",
Score: 5,
},
{
Key: "value4",
Score: 8,
},
}, pairs)
pairs, err = client.ZrangebyscoreWithScoresAndLimit("key", 5, 8, 1, 1)
assert.Nil(t, err)
assert.EqualValues(t, []redis.Pair{
{
Key: "value4",
Score: 8,
},
}, pairs)
pairs, err = client.ZrevrangebyscoreWithScores("key", 5, 8)
assert.Nil(t, err)
assert.EqualValues(t, []redis.Pair{
{
Key: "value4",
Score: 8,
},
{
Key: "value1",
Score: 5,
},
}, pairs)
pairs, err = client.ZrevrangebyscoreWithScoresAndLimit("key", 5, 8, 1, 1)
assert.Nil(t, err)
assert.EqualValues(t, []redis.Pair{
{
Key: "value1",
Score: 5,
},
}, pairs)
})
}
func runOnCluster(t *testing.T, fn func(cluster Store)) {
s1.FlushAll()
s2.FlushAll()
store := NewStore([]internal.NodeConf{
{
RedisConf: redis.RedisConf{
Host: s1.Addr(),
Type: redis.NodeType,
},
Weight: 100,
},
{
RedisConf: redis.RedisConf{
Host: s2.Addr(),
Type: redis.NodeType,
},
Weight: 100,
},
})
fn(store)
}