From 153bd05fb7340dd099e6055c684adb6b6f1ba548 Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Thu, 26 Jul 2012 18:16:17 +0300 Subject: [PATCH] Fix multi/exec and add more commands. --- commands.go | 662 +++++++++++++++++++++++++++---- multi.go | 48 --- redis.go | 97 ++++- redis_test.go | 1045 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 1653 insertions(+), 199 deletions(-) delete mode 100644 multi.go diff --git a/commands.go b/commands.go index 2e28b7aa..508290e3 100644 --- a/commands.go +++ b/commands.go @@ -6,12 +6,39 @@ import ( //------------------------------------------------------------------------------ +func (c *Client) Auth(password string) *StatusReq { + req := NewStatusReq("AUTH", password) + c.Run(req) + return req +} + +func (c *Client) Echo(message string) *BulkReq { + req := NewBulkReq("ECHO", message) + c.Run(req) + return req +} + func (c *Client) Ping() *StatusReq { req := NewStatusReq("PING") c.Run(req) return req } +func (c *Client) Quit() *StatusReq { + req := NewStatusReq("QUIT") + c.Run(req) + c.Close() + return req +} + +func (c *Client) Select(index int64) *StatusReq { + req := NewStatusReq("SELECT", strconv.FormatInt(index, 10)) + c.Run(req) + return req +} + +//------------------------------------------------------------------------------ + func (c *Client) Flushall() *StatusReq { req := NewStatusReq("FLUSHALL") c.Run(req) @@ -26,50 +53,590 @@ func (c *Client) Flushdb() *StatusReq { //------------------------------------------------------------------------------ +func (c *Client) Del(keys ...string) *IntReq { + args := append([]string{"DEL"}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) Dump(key string) *BulkReq { + req := NewBulkReq("DUMP", key) + c.Run(req) + return req +} + +func (c *Client) Exists(key string) *BoolReq { + req := NewBoolReq("EXISTS", key) + c.Run(req) + return req +} + +func (c *Client) Expire(key string, seconds int64) *BoolReq { + req := NewBoolReq("EXPIRE", key, strconv.FormatInt(seconds, 10)) + c.Run(req) + return req +} + +func (c *Client) ExpireAt(key string, timestamp int64) *BoolReq { + req := NewBoolReq("EXPIREAT", key, strconv.FormatInt(timestamp, 10)) + c.Run(req) + return req +} + +func (c *Client) Keys(pattern string) *MultiBulkReq { + req := NewMultiBulkReq("KEYS", pattern) + c.Run(req) + return req +} + +func (c *Client) Migrate(host string, port int32, key, db string, timeout int64) *StatusReq { + req := NewStatusReq( + "MIGRATE", + host, + strconv.FormatInt(int64(port), 10), + key, + db, + strconv.FormatInt(timeout, 10), + ) + c.Run(req) + return req +} + +func (c *Client) Move(key string, db int64) *BoolReq { + req := NewBoolReq("MOVE", key, strconv.FormatInt(db, 10)) + c.Run(req) + return req +} + +func (c *Client) ObjectRefCount(keys ...string) *IntReq { + args := append([]string{"OBJECT", "REFCOUNT"}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) ObjectEncoding(keys ...string) *BulkReq { + args := append([]string{"OBJECT", "ENCODING"}, keys...) + req := NewBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) ObjectIdleTime(keys ...string) *IntReq { + args := append([]string{"OBJECT", "IDLETIME"}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) Persist(key string) *BoolReq { + req := NewBoolReq("PERSIST", key) + c.Run(req) + return req +} + +func (c *Client) Pexpire(key string, milliseconds int64) *BoolReq { + req := NewBoolReq("PEXPIRE", key, strconv.FormatInt(milliseconds, 10)) + c.Run(req) + return req +} + +func (c *Client) PexpireAt(key string, milliseconds int64) *BoolReq { + req := NewBoolReq("PEXPIREAT", key, strconv.FormatInt(milliseconds, 10)) + c.Run(req) + return req +} + +func (c *Client) PTTL(key string) *IntReq { + req := NewIntReq("PTTL", key) + c.Run(req) + return req +} + +func (c *Client) RandomKey() *BulkReq { + req := NewBulkReq("RANDOMKEY") + c.Run(req) + return req +} + +func (c *Client) Rename(key, newkey string) *StatusReq { + req := NewStatusReq("RENAME", key, newkey) + c.Run(req) + return req +} + +func (c *Client) RenameNX(key, newkey string) *BoolReq { + req := NewBoolReq("RENAMENX", key, newkey) + c.Run(req) + return req +} + +func (c *Client) Restore(key, ttl int64, value string) *StatusReq { + req := NewStatusReq( + "RESTORE", + strconv.FormatInt(ttl, 10), + value, + ) + c.Run(req) + return req +} + +func (c *Client) Sort(key string, params ...string) *MultiBulkReq { + args := append([]string{"SORT", key}, params...) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) TTL(key string) *IntReq { + req := NewIntReq("TTL", key) + c.Run(req) + return req +} + +func (c *Client) Type(key string) *StatusReq { + req := NewStatusReq("TYPE", key) + c.Run(req) + return req +} + +//------------------------------------------------------------------------------ + +func (c *Client) Append(key, value string) *IntReq { + req := NewIntReq("APPEND", key, value) + c.Run(req) + return req +} + +// BitCount + +// BitOp + +func (c *Client) Decr(key string) *IntReq { + req := NewIntReq("DECR", key) + c.Run(req) + return req +} + +func (c *Client) DecrBy(key string, decrement int64) *IntReq { + req := NewIntReq("DECRBY", key, strconv.FormatInt(decrement, 10)) + c.Run(req) + return req +} + func (c *Client) Get(key string) *BulkReq { req := NewBulkReq("GET", key) c.Run(req) return req } +func (c *Client) GetBit(key string, offset int64) *IntReq { + req := NewIntReq("GETBIT", key, strconv.FormatInt(offset, 10)) + c.Run(req) + return req +} + +func (c *Client) GetRange(key string, start, end int64) *BulkReq { + req := NewBulkReq( + "GETRANGE", + key, + strconv.FormatInt(start, 10), + strconv.FormatInt(end, 10), + ) + c.Run(req) + return req +} + +func (c *Client) GetSet(key, value string) *BulkReq { + req := NewBulkReq("GETSET", key, value) + c.Run(req) + return req +} + +func (c *Client) Incr(key string) *IntReq { + req := NewIntReq("INCR", key) + c.Run(req) + return req +} + +func (c *Client) IncrBy(key string, value int64) *IntReq { + req := NewIntReq("INCRBY", key, strconv.FormatInt(value, 10)) + c.Run(req) + return req +} + +// incrbyfloat + +func (c *Client) MGet(keys ...string) *MultiBulkReq { + args := append([]string{"MGET"}, keys...) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) MSet(pairs ...string) *StatusReq { + args := append([]string{"MSET"}, pairs...) + req := NewStatusReq(args...) + c.Run(req) + return req +} + +func (c *Client) MSetNX(pairs ...string) *BoolReq { + args := append([]string{"MSETNX"}, pairs...) + req := NewBoolReq(args...) + c.Run(req) + return req +} + +func (c *Client) PSetEx(key string, milliseconds int64, value string) *StatusReq { + req := NewStatusReq( + "PSETEX", + key, + strconv.FormatInt(milliseconds, 10), + value, + ) + c.Run(req) + return req +} + func (c *Client) Set(key, value string) *StatusReq { req := NewStatusReq("SET", key, value) c.Run(req) return req } -func (c *Client) Auth(password string) *StatusReq { - req := NewStatusReq("AUTH", password) +func (c *Client) SetBit(key string, offset int64, value int) *IntReq { + req := NewIntReq( + "SETBIT", + key, + strconv.FormatInt(offset, 10), + strconv.FormatInt(int64(value), 10), + ) + c.Run(req) + return req +} + +func (c *Client) SetEx(key string, seconds int64, value string) *StatusReq { + req := NewStatusReq("SETEX", key, strconv.FormatInt(seconds, 10), value) + c.Run(req) + return req +} + +func (c *Client) SetNx(key, value string) *BoolReq { + req := NewBoolReq("SETNX", key, value) + c.Run(req) + return req +} + +func (c *Client) SetRange(key string, offset int64, value string) *IntReq { + req := NewIntReq("SETRANGE", key, strconv.FormatInt(offset, 10), value) + c.Run(req) + return req +} + +func (c *Client) StrLen(key string) *IntReq { + req := NewIntReq("STRLEN", key) c.Run(req) return req } //------------------------------------------------------------------------------ -func (c *Client) Sadd(key string, members ...string) *IntReq { +func (c *Client) HDel(key string, fields ...string) *IntReq { + args := append([]string{"HDEL", key}, fields...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) HExists(key, field string) *BoolReq { + req := NewBoolReq("HEXISTS", key, field) + c.Run(req) + return req +} + +func (c *Client) HGet(key, field string) *BulkReq { + req := NewBulkReq("HGET", key, field) + c.Run(req) + return req +} + +func (c *Client) HGetAll(key string) *MultiBulkReq { + req := NewMultiBulkReq("HGETALL", key) + c.Run(req) + return req +} + +func (c *Client) HIncrBy(key, field string, incr int64) *IntReq { + req := NewIntReq("HINCRBY", key, field, strconv.FormatInt(incr, 10)) + c.Run(req) + return req +} + +// hincrbyfloat + +func (c *Client) HKeys(key string) *MultiBulkReq { + req := NewMultiBulkReq("HKEYS", key) + c.Run(req) + return req +} + +func (c *Client) HLen(key string) *IntReq { + req := NewIntReq("HLEN", key) + c.Run(req) + return req +} + +func (c *Client) HMGet(key string, fields ...string) *MultiBulkReq { + args := append([]string{"HMGET", key}, fields...) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) HMSet(key, field, value string, pairs ...string) *StatusReq { + args := append([]string{"HMSET", key, field, value}, pairs...) + req := NewStatusReq(args...) + c.Run(req) + return req +} + +func (c *Client) HSet(key, field, value string) *BoolReq { + req := NewBoolReq("HSET", key, field, value) + c.Run(req) + return req +} + +func (c *Client) HSetNX(key, field, value string) *BoolReq { + req := NewBoolReq("HSETNX", key, field, value) + c.Run(req) + return req +} + +func (c *Client) HVals(key string) *MultiBulkReq { + req := NewMultiBulkReq("HVALS", key) + c.Run(req) + return req +} + +//------------------------------------------------------------------------------ + +func (c *Client) BLPop(timeout int64, keys ...string) *MultiBulkReq { + args := append([]string{"BLPOP"}, keys...) + args = append(args, strconv.FormatInt(timeout, 10)) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) BRPop(timeout int64, keys ...string) *MultiBulkReq { + args := append([]string{"BRPOP"}, keys...) + args = append(args, strconv.FormatInt(timeout, 10)) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) BRPopLPush(source, destination string, timeout int64) *BulkReq { + req := NewBulkReq( + "BRPOPLPUSH", + source, + destination, + strconv.FormatInt(timeout, 10), + ) + c.Run(req) + return req +} + +func (c *Client) LIndex(key string, index int64) *BulkReq { + req := NewBulkReq("LINDEX", key, strconv.FormatInt(index, 10)) + c.Run(req) + return req +} + +func (c *Client) LInsert(key, op, pivot, value string) *IntReq { + req := NewIntReq("LINSERT", key, op, pivot, value) + c.Run(req) + return req +} + +func (c *Client) LLen(key string) *IntReq { + req := NewIntReq("LLEN", key) + c.Run(req) + return req +} + +func (c *Client) LPop(key string) *BulkReq { + req := NewBulkReq("LPOP", key) + c.Run(req) + return req +} + +func (c *Client) LPush(key string, values ...string) *IntReq { + args := append([]string{"LPUSH", key}, values...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) LPushX(key, value string) *IntReq { + req := NewIntReq("LPUSHX", key, value) + c.Run(req) + return req +} + +func (c *Client) LRange(key string, start, stop int64) *MultiBulkReq { + req := NewMultiBulkReq( + "LRANGE", + key, + strconv.FormatInt(start, 10), + strconv.FormatInt(stop, 10), + ) + c.Run(req) + return req +} + +func (c *Client) LRem(key string, count int64, value string) *IntReq { + req := NewIntReq("LREM", key, strconv.FormatInt(count, 10), value) + c.Run(req) + return req +} + +func (c *Client) LSet(key string, index int64, value string) *StatusReq { + req := NewStatusReq("LSET", key, strconv.FormatInt(index, 10), value) + c.Run(req) + return req +} + +func (c *Client) LTrim(key string, start, stop int64) *StatusReq { + req := NewStatusReq( + "LTRIM", + key, + strconv.FormatInt(start, 10), + strconv.FormatInt(stop, 10), + ) + c.Run(req) + return req +} + +func (c *Client) RPop(key string) *BulkReq { + req := NewBulkReq("RPOP", key) + c.Run(req) + return req +} + +func (c *Client) RPopLPush(source, destination string) *BulkReq { + req := NewBulkReq("RPOPLPUSH", source, destination) + c.Run(req) + return req +} + +func (c *Client) RPush(key string, values ...string) *IntReq { + args := append([]string{"RPUSH", key}, values...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) RPushX(key string, value string) *IntReq { + req := NewIntReq("RPUSHX", key, value) + c.Run(req) + return req +} + +//------------------------------------------------------------------------------ + +func (c *Client) SAdd(key string, members ...string) *IntReq { args := append([]string{"SADD", key}, members...) req := NewIntReq(args...) c.Run(req) return req } -func (c *Client) Srem(key string, members ...string) *IntReq { +func (c *Client) SCard(key string) *IntReq { + req := NewIntReq("SCARD", key) + c.Run(req) + return req +} + +func (c *Client) SDiff(keys ...string) *MultiBulkReq { + args := append([]string{"SDIFF"}, keys...) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) SDiffStore(destination string, keys ...string) *IntReq { + args := append([]string{"SDIFFSTORE", destination}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) SInter(keys ...string) *MultiBulkReq { + args := append([]string{"SINTER"}, keys...) + req := NewMultiBulkReq(args...) + c.Run(req) + return req +} + +func (c *Client) SInterStore(destination string, keys ...string) *IntReq { + args := append([]string{"SINTERSTORE", destination}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req +} + +func (c *Client) SIsMember(key, member string) *BoolReq { + req := NewBoolReq("SISMEMBER", key, member) + c.Run(req) + return req +} + +func (c *Client) SMembers(key string) *MultiBulkReq { + req := NewMultiBulkReq("SMEMBERS", key) + c.Run(req) + return req +} + +func (c *Client) SMove(source, destination, member string) *BoolReq { + req := NewBoolReq("SMOVE", source, destination, member) + c.Run(req) + return req +} + +func (c *Client) SPop(key string) *BulkReq { + req := NewBulkReq("SPOP", key) + c.Run(req) + return req +} + +func (c *Client) SRandMember(key string) *BulkReq { + req := NewBulkReq("SRANDMEMBER", key) + c.Run(req) + return req +} + +func (c *Client) SRem(key string, members ...string) *IntReq { args := append([]string{"SREM", key}, members...) req := NewIntReq(args...) c.Run(req) return req } -func (c *Client) Smembers(key string) *MultiBulkReq { - req := NewMultiBulkReq("SMEMBERS", key) +func (c *Client) SUnion(keys ...string) *MultiBulkReq { + args := append([]string{"SUNION"}, keys...) + req := NewMultiBulkReq(args...) c.Run(req) return req } -//------------------------------------------------------------------------------ - -func (c *Client) Multi() *MultiClient { - return NewMultiClient(c.connect, c.disconnect) +func (c *Client) SUnionStore(destination string, keys ...string) *IntReq { + args := append([]string{"SUNIONSTORE", destination}, keys...) + req := NewIntReq(args...) + c.Run(req) + return req } //------------------------------------------------------------------------------ @@ -86,77 +653,6 @@ func (c *Client) Publish(channel, message string) *IntReq { //------------------------------------------------------------------------------ -func (c *Client) Hset(key, field, value string) *BoolReq { - req := NewBoolReq("HSET", key, field, value) - c.Run(req) - return req -} - -func (c *Client) Hsetnx(key, field, value string) *BoolReq { - req := NewBoolReq("HSETNX", key, field, value) - c.Run(req) - return req -} - -func (c *Client) Hmset(key, field, value string, pairs ...string) *StatusReq { - args := append([]string{"HMSET", key, field, value}, pairs...) - req := NewStatusReq(args...) - c.Run(req) - return req -} - -func (c *Client) Hget(key, field string) *BulkReq { - req := NewBulkReq("HGET", key, field) - c.Run(req) - return req -} - -func (c *Client) Hmget(key string, fields ...string) *MultiBulkReq { - args := append([]string{"HMGET", key}, fields...) - req := NewMultiBulkReq(args...) - c.Run(req) - return req -} - -func (c *Client) Hexists(key, field string) *BoolReq { - req := NewBoolReq("HEXISTS", key, field) - c.Run(req) - return req -} - -func (c *Client) Hdel(key string, fields ...string) *IntReq { - args := append([]string{"HDEL", key}, fields...) - req := NewIntReq(args...) - c.Run(req) - return req -} - -func (c *Client) Hlen(key string) *IntReq { - req := NewIntReq("HLEN", key) - c.Run(req) - return req -} - -func (c *Client) Hgetall(key string) *MultiBulkReq { - req := NewMultiBulkReq("HGETALL", key) - c.Run(req) - return req -} - -func (c *Client) Hkeys(key string) *MultiBulkReq { - req := NewMultiBulkReq("HKEYS", key) - c.Run(req) - return req -} - -func (c *Client) Hvals(key string) *MultiBulkReq { - req := NewMultiBulkReq("HVALS", key) - c.Run(req) - return req -} - -func (c *Client) Hincrby(key, field string, incr int64) *IntReq { - req := NewIntReq("HINCRBY", key, field, strconv.FormatInt(incr, 10)) - c.Run(req) - return req +func (c *Client) Multi() *Client { + return NewMultiClient(c.connect, c.disconnect) } diff --git a/multi.go b/multi.go deleted file mode 100644 index 20b2dccf..00000000 --- a/multi.go +++ /dev/null @@ -1,48 +0,0 @@ -package redis - -type MultiClient struct { - *Client - reqs []Req -} - -func NewMultiClient(connect connectFunc, disconnect disconnectFunc) *MultiClient { - return &MultiClient{ - Client: NewClient(connect, disconnect), - reqs: make([]Req, 0), - } - -} - -func (c *MultiClient) queueReq(req Req) { - c.reqs = append(c.reqs, req) -} - -func (c *MultiClient) run(req Req) { - c.queueReq(req) -} - -func (c *MultiClient) Exec() ([]Req, error) { - c.mtx.Lock() - defer c.mtx.Unlock() - - reqs := c.reqs - c.reqs = make([]Req, 0) - - multiReq := make([]byte, 0, 8192) - multiReq = append(multiReq, PackReq([]string{"MULTI"})...) - for _, req := range reqs { - multiReq = append(multiReq, req.Req()...) - } - multiReq = append(multiReq, PackReq([]string{"EXEC"})...) - - buf, err := c.WriteRead(multiReq) - if err != nil { - return nil, err - } - - for _, req := range reqs { - req.ParseReply(buf) - } - - return reqs, nil -} diff --git a/redis.go b/redis.go index 4b606a19..d0582383 100644 --- a/redis.go +++ b/redis.go @@ -1,6 +1,7 @@ package redis import ( + "fmt" "io" "sync" @@ -16,6 +17,8 @@ type Client struct { disconnect disconnectFunc currConn io.ReadWriter rd *bufreader.Reader + + reqs []Req } func NewClient(connect connectFunc, disconnect disconnectFunc) *Client { @@ -26,6 +29,16 @@ func NewClient(connect connectFunc, disconnect disconnectFunc) *Client { } } +func NewMultiClient(connect connectFunc, disconnect disconnectFunc) *Client { + return &Client{ + rd: bufreader.NewSizedReader(8192), + connect: connect, + disconnect: disconnect, + + reqs: make([]Req, 0), + } +} + func (c *Client) Close() error { if c.disconnect != nil { c.disconnect(c.currConn) @@ -71,6 +84,8 @@ func (c *Client) ReadReply() (*bufreader.Reader, error) { } func (c *Client) WriteRead(buf []byte) (*bufreader.Reader, error) { + c.mtx.Lock() + defer c.mtx.Unlock() if err := c.WriteReq(buf); err != nil { return nil, err } @@ -78,16 +93,84 @@ func (c *Client) WriteRead(buf []byte) (*bufreader.Reader, error) { } func (c *Client) Run(req Req) { - c.mtx.Lock() - c.run(req) - c.mtx.Unlock() -} + if c.reqs != nil { + c.mtx.Lock() + c.reqs = append(c.reqs, req) + c.mtx.Unlock() + return + } -func (c *Client) run(req Req) { - buf, err := c.WriteRead(req.Req()) + rd, err := c.WriteRead(req.Req()) if err != nil { req.SetErr(err) return } - req.ParseReply(buf) + req.ParseReply(rd) +} + +//------------------------------------------------------------------------------ + +func (c *Client) Discard() { + if c.reqs == nil { + panic("MultiClient required") + } + + c.mtx.Lock() + c.reqs = c.reqs[:0] + c.mtx.Unlock() +} + +func (c *Client) Exec() ([]Req, error) { + if c.reqs == nil { + panic("MultiClient required") + } + + c.mtx.Lock() + reqs := c.reqs + c.reqs = make([]Req, 0) + c.mtx.Unlock() + + multiReq := make([]byte, 0, 1024) + multiReq = append(multiReq, PackReq([]string{"MULTI"})...) + for _, req := range reqs { + multiReq = append(multiReq, req.Req()...) + } + multiReq = append(multiReq, PackReq([]string{"EXEC"})...) + + rd, err := c.WriteRead(multiReq) + if err != nil { + return nil, err + } + + statusReq := NewStatusReq() + + // multi + statusReq.ParseReply(rd) + _, err = statusReq.Reply() + if err != nil { + return nil, err + } + + for _ = range reqs { + // queue + statusReq.ParseReply(rd) + _, err = statusReq.Reply() + if err != nil { + return nil, err + } + } + + line, err := rd.ReadLine('\n') + if err != nil { + return nil, err + } + if line[0] != '*' { + return nil, fmt.Errorf("Expected '*', but got line %q of %q.", line, rd.Bytes()) + } + + for _, req := range reqs { + req.ParseReply(rd) + } + + return reqs, nil } diff --git a/redis_test.go b/redis_test.go index 0ee5c3f6..95b448b0 100644 --- a/redis_test.go +++ b/redis_test.go @@ -36,108 +36,1008 @@ func (t *RedisTest) TearDownTest(c *C) { t.redisC.Flushdb() } -func (t *RedisTest) TestPing(c *C) { - _, err := t.redisC.Ping().Reply() - c.Check(err, IsNil) +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestAuth(c *C) { + c.Skip("not implemented") } -func (t *RedisTest) TestSetGet(c *C) { - key := "foo" - value := "bar" - - _, err := t.redisC.Set(key, value).Reply() +func (t *RedisTest) TestEcho(c *C) { + echo, err := t.redisC.Echo("hello").Reply() c.Check(err, IsNil) + c.Check(echo, Equals, "hello") +} + +func (t *RedisTest) TestPing(c *C) { + pong, err := t.redisC.Ping().Reply() + c.Check(err, IsNil) + c.Check(pong, Equals, "PONG") +} + +func (t *RedisTest) TestQuit(c *C) { + ok, err := t.redisC.Quit().Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + pong, err := t.redisC.Ping().Reply() + c.Check(err, IsNil) + c.Check(pong, Equals, "PONG") +} + +func (t *RedisTest) TestSelect(c *C) { + ok, err := t.redisC.Select(1).Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") +} + +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestDel(c *C) { + n, err := t.redisC.Del("foo").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) +} + +func (t *RedisTest) TestDump(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestExists(c *C) { + exists, err := t.redisC.Exists("foo").Reply() + c.Check(err, IsNil) + c.Check(exists, Equals, false) +} + +func (t *RedisTest) TestExpire(c *C) { + isSet, err := t.redisC.Expire("foo", 0).Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) +} + +func (t *RedisTest) TestExpireAt(c *C) { + isSet, err := t.redisC.ExpireAt("foo", 0).Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) +} + +func (t *RedisTest) TestKeys(c *C) { + t.redisC.Set("foo1", "") + t.redisC.Set("foo2", "") + + keys, err := t.redisC.Keys("*").Reply() + c.Check(err, IsNil) + c.Check(keys, HasLen, 2) + c.Check(keys[0], Equals, "foo1") + c.Check(keys[1], Equals, "foo2") +} + +func (t *RedisTest) TestMigrate(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestMove(c *C) { + isMoved, err := t.redisC.Move("foo", 1).Reply() + c.Check(err, IsNil) + c.Check(isMoved, Equals, false) + + t.redisC.Set("foo", "bar") + + isMoved, err = t.redisC.Move("foo", 1).Reply() + c.Check(err, IsNil) + c.Check(isMoved, Equals, true) v, err := t.redisC.Get("foo").Reply() - c.Check(err, IsNil) - c.Check(v, Equals, value) - - _, err = t.redisC.Get("_").Reply() c.Check(err, Equals, redis.Nil) + c.Check(v, Equals, "") + + t.redisC.Select(1) + + v, err = t.redisC.Get("foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") } -func (t *RedisTest) TestHmsetHmget(c *C) { - _, err := t.redisC.Hmset("myhash", "foo1", "bar1", "foo2", "bar2").Reply() - c.Check(err, IsNil) +func (t *RedisTest) TestObject(c *C) { + t.redisC.Set("foo", "bar").Reply() - pairs, err := t.redisC.Hmget("myhash", "foo1", "foo3", "foo2").Reply() - c.Check(err, IsNil) - c.Check(pairs, HasLen, 3) - c.Check(pairs[0], Equals, "bar1") - c.Check(pairs[1], Equals, nil) - c.Check(pairs[2], Equals, "bar2") -} - -func (t *RedisTest) TestSet(c *C) { - n, err := t.redisC.Sadd("myset", "foo").Reply() + n, err := t.redisC.ObjectRefCount("foo").Reply() c.Check(err, IsNil) c.Check(n, Equals, int64(1)) - members, err := t.redisC.Smembers("myset").Reply() + enc, err := t.redisC.ObjectEncoding("foo").Reply() c.Check(err, IsNil) - c.Check(members, HasLen, 1) - c.Check(members[0], Equals, "foo") + c.Check(enc, Equals, "raw") - n, err = t.redisC.Srem("myset", "foo").Reply() + n, err = t.redisC.ObjectIdleTime("foo").Reply() c.Check(err, IsNil) - c.Check(n, Equals, int64(1)) + c.Check(n, Equals, int64(0)) } -func (t *RedisTest) TestHsetnx(c *C) { - wasSet, err := t.redisC.Hsetnx("myhash", "foo1", "bar1").Reply() - c.Check(err, IsNil) - c.Check(wasSet, Equals, true) +func (t *RedisTest) TestPersist(c *C) { + t.redisC.Set("foo", "bar").Reply() - wasSet, err = t.redisC.Hsetnx("myhash", "foo1", "bar1").Reply() + isPersisted, err := t.redisC.Persist("foo").Reply() c.Check(err, IsNil) - c.Check(wasSet, Equals, false) + c.Check(isPersisted, Equals, false) + + t.redisC.Expire("foo", 10) + + isPersisted, err = t.redisC.Persist("foo").Reply() + c.Check(err, IsNil) + c.Check(isPersisted, Equals, true) } -func (t *RedisTest) TestHash(c *C) { - _, err := t.redisC.Hset("myhash", "foo", "bar").Reply() +func (t *RedisTest) TestPexpire(c *C) { + c.Skip("not implemented") + isSet, err := t.redisC.Pexpire("foo", 0).Reply() c.Check(err, IsNil) + c.Check(isSet, Equals, false) +} - v, err := t.redisC.Hget("myhash", "foo").Reply() +func (t *RedisTest) TestPexpireAt(c *C) { + c.Skip("not implemented") + isSet, err := t.redisC.PexpireAt("foo", time.Now().UnixNano()*100+60).Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) +} + +func (t *RedisTest) TestPTTL(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestRandomKey(c *C) { + key, err := t.redisC.RandomKey().Reply() + c.Check(err, Equals, redis.Nil) + c.Check(key, Equals, "") + + t.redisC.Set("foo", "bar").Reply() + + key, err = t.redisC.RandomKey().Reply() + c.Check(err, IsNil) + c.Check(key, Equals, "foo") +} + +func (t *RedisTest) TestRename(c *C) { + t.redisC.Set("foo", "bar").Reply() + + status, err := t.redisC.Rename("foo", "foo1").Reply() + c.Check(err, IsNil) + c.Check(status, Equals, "OK") + + v, err := t.redisC.Get("foo1").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestRenameNX(c *C) { + t.redisC.Set("foo", "bar").Reply() + + renamed, err := t.redisC.RenameNX("foo", "foo1").Reply() + c.Check(err, IsNil) + c.Check(renamed, Equals, true) + + v, err := t.redisC.Get("foo1").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestRestore(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestSort(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestTTL(c *C) { + ttl, err := t.redisC.TTL("foo").Reply() + c.Check(err, IsNil) + c.Check(ttl, Equals, int64(-1)) + + t.redisC.Set("foo", "bar").Reply() + t.redisC.Expire("foo", 60) + + ttl, err = t.redisC.TTL("foo").Reply() + c.Check(err, IsNil) + c.Check(ttl, Equals, int64(60)) +} + +func (t *RedisTest) Type(c *C) { + t.redisC.Set("foo", "bar").Reply() + + type_, err := t.redisC.Type("foo").Reply() + c.Check(err, IsNil) + c.Check(type_, Equals, "string") +} + +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestAppend(c *C) { + l, err := t.redisC.Append("foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(l, Equals, int64(3)) +} + +func (t *RedisTest) TestDecr(c *C) { + n, err := t.redisC.Decr("foo").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(-1)) +} + +func (t *RedisTest) TestDecrBy(c *C) { + n, err := t.redisC.DecrBy("foo", 10).Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(-10)) +} + +func (t *RedisTest) TestGet(c *C) { + v, err := t.redisC.Get("foo").Reply() + c.Check(err, Equals, redis.Nil) + c.Check(v, Equals, "") +} + +func (t *RedisTest) TestSetGetBig(c *C) { + v, err := t.redisC.GetBit("foo", 5).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, int64(0)) + + v, err = t.redisC.SetBit("foo", 5, 1).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, int64(0)) + + v, err = t.redisC.GetBit("foo", 5).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, int64(1)) +} + +func (t *RedisTest) TestGetRange(c *C) { + t.redisC.Set("foo", "hello") + + v, err := t.redisC.GetRange("foo", 0, 1).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "he") +} + +func (t *RedisTest) TestGetSet(c *C) { + t.redisC.Set("foo", "bar") + + v, err := t.redisC.GetSet("foo", "bar2").Reply() c.Check(err, IsNil) c.Check(v, Equals, "bar") - exists, err := t.redisC.Hexists("myhash", "foo").Reply() + v, err = t.redisC.Get("foo").Reply() c.Check(err, IsNil) - c.Check(exists, Equals, true) + c.Check(v, Equals, "bar2") +} - hlen, err := t.redisC.Hlen("myhash").Reply() +func (t *RedisTest) TestIncr(c *C) { + n, err := t.redisC.Incr("foo").Reply() c.Check(err, IsNil) - c.Check(hlen, Equals, int64(1)) + c.Check(n, Equals, int64(1)) +} - res, err := t.redisC.Hgetall("myhash").Reply() +func (t *RedisTest) TestIncrBy(c *C) { + n, err := t.redisC.IncrBy("foo", 10).Reply() c.Check(err, IsNil) - c.Check(res, HasLen, 2) - c.Check(res[0], Equals, "foo") - c.Check(res[1], Equals, "bar") + c.Check(n, Equals, int64(10)) +} - keys, err := t.redisC.Hkeys("myhash").Reply() +func (t *RedisTest) TestMsetMget(c *C) { + ok, err := t.redisC.MSet("foo1", "bar1", "foo2", "bar2").Reply() c.Check(err, IsNil) - c.Check(keys, HasLen, 1) - c.Check(keys[0], Equals, "foo") + c.Check(ok, Equals, "OK") - vals, err := t.redisC.Hvals("myhash").Reply() + values, err := t.redisC.MGet("foo1", "foo2").Reply() c.Check(err, IsNil) - c.Check(vals, HasLen, 1) - c.Check(vals[0], Equals, "bar") + c.Check(values, DeepEquals, []interface{}{"bar1", "bar2"}) +} - n, err := t.redisC.Hdel("myhash", "foo").Reply() +func (t *RedisTest) MSetNX(c *C) { + isSet, err := t.redisC.MSetNX("foo1", "bar1", "foo2", "bar2").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, true) + + isSet, err = t.redisC.MSetNX("foo1", "bar1", "foo2", "bar2").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) +} + +func (t *RedisTest) PSetEx(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestSetGet(c *C) { + ok, err := t.redisC.Set("foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + v, err := t.redisC.Get("foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestSetEx(c *C) { + ok, err := t.redisC.SetEx("foo", 10, "bar").Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + ttl, err := t.redisC.TTL("foo").Reply() + c.Check(err, IsNil) + c.Check(ttl, Equals, int64(10)) +} + +func (t *RedisTest) TestSetNx(c *C) { + isSet, err := t.redisC.SetNx("foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, true) + + isSet, err = t.redisC.SetNx("foo", "bar2").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) + + v, err := t.redisC.Get("foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestSetRange(c *C) { + t.redisC.Set("foo", "Hello World").Reply() + + n, err := t.redisC.SetRange("foo", 6, "Redis").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(11)) + + v, err := t.redisC.Get("foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "Hello Redis") +} + +func (t *RedisTest) TestStrLen(c *C) { + t.redisC.Set("foo", "bar").Reply() + + n, err := t.redisC.StrLen("foo").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(3)) + + n, err = t.redisC.StrLen("_").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) +} + +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestHDel(c *C) { + t.redisC.HSet("myhash", "foo", "bar").Reply() + + n, err := t.redisC.HDel("myhash", "foo").Reply() c.Check(err, IsNil) c.Check(n, Equals, int64(1)) - wasSet, err := t.redisC.Hset("myhash", "counter", "0").Reply() + n, err = t.redisC.HDel("myhash", "foo").Reply() c.Check(err, IsNil) - c.Check(wasSet, Equals, true) - - counter, err := t.redisC.Hincrby("myhash", "counter", 1).Reply() - c.Check(err, IsNil) - c.Check(counter, Equals, int64(1)) + c.Check(n, Equals, int64(0)) } +func (t *RedisTest) TestHExists(c *C) { + t.redisC.HSet("myhash", "foo", "bar").Reply() + + n, err := t.redisC.HExists("myhash", "foo").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, true) + + n, err = t.redisC.HExists("myhash", "foo1").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, false) +} + +func (t *RedisTest) TestHGet(c *C) { + t.redisC.HSet("myhash", "foo", "bar").Reply() + + v, err := t.redisC.HGet("myhash", "foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") + + v, err = t.redisC.HGet("myhash", "foo1").Reply() + c.Check(err, Equals, redis.Nil) + c.Check(v, Equals, "") +} + +func (t *RedisTest) TestHGetAll(c *C) { + t.redisC.HSet("myhash", "foo1", "bar1").Reply() + t.redisC.HSet("myhash", "foo2", "bar2").Reply() + + values, err := t.redisC.HGetAll("myhash").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 4) + c.Check(values, DeepEquals, []interface{}{"foo1", "bar1", "foo2", "bar2"}) +} + +func (t *RedisTest) TestHIncrBy(c *C) { + t.redisC.HSet("myhash", "foo", "5").Reply() + + n, err := t.redisC.HIncrBy("myhash", "foo", 1).Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(6)) + + n, err = t.redisC.HIncrBy("myhash", "foo", -1).Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(5)) + + n, err = t.redisC.HIncrBy("myhash", "foo", -10).Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(-5)) +} + +func (t *RedisTest) TestHIncrByFloat(c *C) { + c.Skip("not implemented") +} + +func (t *RedisTest) TestHKeys(c *C) { + t.redisC.HSet("myhash", "foo1", "bar1").Reply() + t.redisC.HSet("myhash", "foo2", "bar2").Reply() + + values, err := t.redisC.HKeys("myhash").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"foo1", "foo2"}) +} + +func (t *RedisTest) TestHLen(c *C) { + t.redisC.HSet("myhash", "foo1", "bar1").Reply() + t.redisC.HSet("myhash", "foo2", "bar2").Reply() + + n, err := t.redisC.HLen("myhash").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) +} + +func (t *RedisTest) TestHMGet(c *C) { + t.redisC.HSet("myhash", "foo1", "bar1").Reply() + t.redisC.HSet("myhash", "foo2", "bar2").Reply() + + values, err := t.redisC.HMGet("myhash", "foo1", "foo2", "_").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) + c.Check(values, DeepEquals, []interface{}{"bar1", "bar2", nil}) +} + +func (t *RedisTest) TestHMSet(c *C) { + ok, err := t.redisC.HMSet("myhash", "foo1", "bar1", "foo2", "bar2").Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + v1, err := t.redisC.HGet("myhash", "foo1").Reply() + c.Check(err, IsNil) + c.Check(v1, Equals, "bar1") + + v2, err := t.redisC.HGet("myhash", "foo2").Reply() + c.Check(err, IsNil) + c.Check(v2, Equals, "bar2") +} + +func (t *RedisTest) TestHSet(c *C) { + isNew, err := t.redisC.HSet("myhash", "foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(isNew, Equals, true) + + v, err := t.redisC.HGet("myhash", "foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestHSetNX(c *C) { + isSet, err := t.redisC.HSetNX("myhash", "foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, true) + + isSet, err = t.redisC.HSetNX("myhash", "foo", "bar").Reply() + c.Check(err, IsNil) + c.Check(isSet, Equals, false) + + v, err := t.redisC.HGet("myhash", "foo").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar") +} + +func (t *RedisTest) TestHVals(c *C) { + t.redisC.HSet("myhash", "foo1", "bar1").Reply() + t.redisC.HSet("myhash", "foo2", "bar2").Reply() + + values, err := t.redisC.HVals("myhash").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"bar1", "bar2"}) +} + +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestBLPop(c *C) { + t.redisC.RPush("list1", "a", "b", "c").Reply() + + values, err := t.redisC.BLPop(0, "list1", "list2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"list1", "a"}) +} + +func (t *RedisTest) TestBrPop(c *C) { + t.redisC.RPush("list1", "a", "b", "c").Reply() + + values, err := t.redisC.BRPop(0, "list1", "list2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"list1", "c"}) +} + +func (t *RedisTest) TestBRPopLPush(c *C) { + t.redisC.RPush("list1", "a", "b", "c").Reply() + + v, err := t.redisC.BRPopLPush("list1", "list2", 0).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "c") +} + +func (t *RedisTest) TestLIndex(c *C) { + t.redisC.LPush("list", "World") + t.redisC.LPush("list", "Hello") + + v, err := t.redisC.LIndex("list", 0).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "Hello") + + v, err = t.redisC.LIndex("list", -1).Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "World") + + v, err = t.redisC.LIndex("list", 3).Reply() + c.Check(err, Equals, redis.Nil) + c.Check(v, Equals, "") +} + +func (t *RedisTest) TestLInsert(c *C) { + t.redisC.RPush("list", "Hello").Reply() + t.redisC.RPush("list", "World").Reply() + + n, err := t.redisC.LInsert("list", "BEFORE", "World", "There").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(3)) + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) + c.Check(values, DeepEquals, []interface{}{"Hello", "There", "World"}) +} + +func (t *RedisTest) TestLLen(c *C) { + t.redisC.LPush("list", "World").Reply() + t.redisC.LPush("list", "Hello").Reply() + + n, err := t.redisC.LLen("list").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) +} + +func (t *RedisTest) TestLPop(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + v, err := t.redisC.LPop("list").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "one") + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"two", "three"}) +} + +func (t *RedisTest) TestLPush(c *C) { + t.redisC.LPush("list", "World").Reply() + t.redisC.LPush("list", "Hello").Reply() + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"Hello", "World"}) +} + +func (t *RedisTest) TestLPushX(c *C) { + t.redisC.LPush("list", "World").Reply() + + n, err := t.redisC.LPushX("list", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) + + n, err = t.redisC.LPushX("list2", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, DeepEquals, []interface{}{"Hello", "World"}) + + values, err = t.redisC.LRange("list2", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 0) +} + +func (t *RedisTest) TestLRange(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + values, err := t.redisC.LRange("list", 0, 0).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 1) + c.Check(values, DeepEquals, []interface{}{"one"}) + + values, err = t.redisC.LRange("list", -3, 2).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) + c.Check(values, DeepEquals, []interface{}{"one", "two", "three"}) + + values, err = t.redisC.LRange("list", -100, 100).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) + c.Check(values, DeepEquals, []interface{}{"one", "two", "three"}) + + values, err = t.redisC.LRange("list", 5, 10).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 0) +} + +func (t *RedisTest) TestLRem(c *C) { + t.redisC.RPush("list", "hello").Reply() + t.redisC.RPush("list", "hello").Reply() + t.redisC.RPush("list", "foo").Reply() + t.redisC.RPush("list", "hello").Reply() + + n, err := t.redisC.LRem("list", -2, "hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"hello", "foo"}) +} + +func (t *RedisTest) TestLSet(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + ok, err := t.redisC.LSet("list", 0, "four").Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + ok, err = t.redisC.LSet("list", -2, "five").Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) + c.Check(values, DeepEquals, []interface{}{"four", "five", "three"}) +} + +func (t *RedisTest) TestLTrim(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + ok, err := t.redisC.LTrim("list", 1, -1).Reply() + c.Check(err, IsNil) + c.Check(ok, Equals, "OK") + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"two", "three"}) +} + +func (t *RedisTest) TestRPop(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + v, err := t.redisC.RPop("list").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "three") + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"one", "two"}) +} + +func (t *RedisTest) TestRPopLPush(c *C) { + t.redisC.RPush("list", "one").Reply() + t.redisC.RPush("list", "two").Reply() + t.redisC.RPush("list", "three").Reply() + + v, err := t.redisC.RPopLPush("list", "list2").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "three") + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"one", "two"}) + + values, err = t.redisC.LRange("list2", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 1) + c.Check(values, DeepEquals, []interface{}{"three"}) +} + +func (t *RedisTest) TestRPush(c *C) { + n, err := t.redisC.RPush("list", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.RPush("list", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"Hello", "World"}) +} + +func (t *RedisTest) TestRPushX(c *C) { + n, err := t.redisC.RPush("list", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.RPushX("list", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) + + n, err = t.redisC.RPushX("list2", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) + + values, err := t.redisC.LRange("list", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"Hello", "World"}) + + values, err = t.redisC.LRange("list2", 0, -1).Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 0) +} + +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestSAdd(c *C) { + n, err := t.redisC.SAdd("set", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.SAdd("set", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.SAdd("set", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) + + members, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(members, HasLen, 2) + c.Check(members[0], Equals, "World") + c.Check(members[1], Equals, "Hello") +} + +func (t *RedisTest) TestSCard(c *C) { + n, err := t.redisC.SAdd("set", "Hello").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.SAdd("set", "World").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + card, err := t.redisC.SCard("set").Reply() + c.Check(err, IsNil) + c.Check(card, Equals, int64(2)) +} + +func (t *RedisTest) TestSDiff(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + values, err := t.redisC.SDiff("set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"a", "b"}) +} + +func (t *RedisTest) TestSDiffStore(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + n, err := t.redisC.SDiffStore("set", "set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(2)) + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"a", "b"}) +} + +func (t *RedisTest) TestSInter(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + values, err := t.redisC.SInter("set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 1) + c.Check(values, DeepEquals, []interface{}{"c"}) +} + +func (t *RedisTest) TestSInterStore(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + n, err := t.redisC.SInterStore("set", "set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 1) + c.Check(values, DeepEquals, []interface{}{"c"}) +} + +func (t *RedisTest) TestIsMember(c *C) { + t.redisC.SAdd("set", "one").Reply() + + isMember, err := t.redisC.SIsMember("set", "one").Reply() + c.Check(err, IsNil) + c.Check(isMember, Equals, true) + + isMember, err = t.redisC.SIsMember("set", "two").Reply() + c.Check(err, IsNil) + c.Check(isMember, Equals, false) +} + +func (t *RedisTest) TestSMembers(c *C) { + t.redisC.SAdd("set", "Hello").Reply() + t.redisC.SAdd("set", "World").Reply() + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"World", "Hello"}) +} + +func (t *RedisTest) TestSMove(c *C) { + t.redisC.SAdd("set1", "one").Reply() + t.redisC.SAdd("set1", "two").Reply() + + t.redisC.SAdd("set2", "three").Reply() + + isMoved, err := t.redisC.SMove("set1", "set2", "two").Reply() + c.Check(err, IsNil) + c.Check(isMoved, Equals, true) + + values, err := t.redisC.SMembers("set1").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 1) + c.Check(values, DeepEquals, []interface{}{"one"}) + + values, err = t.redisC.SMembers("set2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"three", "two"}) +} + +func (t *RedisTest) TestSPop(c *C) { + t.redisC.SAdd("set", "one").Reply() + t.redisC.SAdd("set", "two").Reply() + t.redisC.SAdd("set", "three").Reply() + + v, err := t.redisC.SPop("set").Reply() + c.Check(err, IsNil) + c.Check(v, Not(Equals), "") + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) +} + +func (t *RedisTest) TestSRandMember(c *C) { + t.redisC.SAdd("set", "one").Reply() + t.redisC.SAdd("set", "two").Reply() + t.redisC.SAdd("set", "three").Reply() + + v, err := t.redisC.SRandMember("set").Reply() + c.Check(err, IsNil) + c.Check(v, Not(Equals), "") + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 3) +} + +func (t *RedisTest) TestSRem(c *C) { + t.redisC.SAdd("set", "one").Reply() + t.redisC.SAdd("set", "two").Reply() + t.redisC.SAdd("set", "three").Reply() + + n, err := t.redisC.SRem("set", "one").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(1)) + + n, err = t.redisC.SRem("set", "four").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(0)) + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 2) + c.Check(values, DeepEquals, []interface{}{"three", "two"}) +} + +func (t *RedisTest) TestSUnion(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + values, err := t.redisC.SUnion("set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 5) +} + +func (t *RedisTest) TestSUnionStore(c *C) { + t.redisC.SAdd("set1", "a").Reply() + t.redisC.SAdd("set1", "b").Reply() + t.redisC.SAdd("set1", "c").Reply() + + t.redisC.SAdd("set2", "c").Reply() + t.redisC.SAdd("set2", "d").Reply() + t.redisC.SAdd("set2", "e").Reply() + + n, err := t.redisC.SUnionStore("set", "set1", "set2").Reply() + c.Check(err, IsNil) + c.Check(n, Equals, int64(5)) + + values, err := t.redisC.SMembers("set").Reply() + c.Check(err, IsNil) + c.Check(values, HasLen, 5) +} + +//------------------------------------------------------------------------------ + func (t *RedisTest) TestPubSub(c *C) { pubsub := t.redisC.PubSubClient() @@ -224,14 +1124,37 @@ func (t *RedisTest) TestPubSub(c *C) { } } +//------------------------------------------------------------------------------ + +func (t *RedisTest) TestDiscard(c *C) { + multiC := t.redisC.Multi() + + multiC.Set("foo1", "bar1") + multiC.Discard() + multiC.Set("foo2", "bar2") + + reqs, err := multiC.Exec() + c.Check(err, IsNil) + c.Check(reqs, HasLen, 1) + + v, err := t.redisC.Get("foo1").Reply() + c.Check(err, Equals, redis.Nil) + c.Check(v, Equals, "") + + v, err = t.redisC.Get("foo2").Reply() + c.Check(err, IsNil) + c.Check(v, Equals, "bar2") +} + func (t *RedisTest) TestMultiExec(c *C) { multiC := t.redisC.Multi() setR := multiC.Set("foo", "bar") getR := multiC.Get("foo") - _, err := multiC.Exec() + reqs, err := multiC.Exec() c.Check(err, IsNil) + c.Check(reqs, HasLen, 2) _, err = setR.Reply() c.Check(err, IsNil)