This is an automated email from the ASF dual-hosted git repository.
tison pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/incubator-kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 5a269c0f Move TCL test unit/type/list to Go case (#1009)
5a269c0f is described below
commit 5a269c0f71c128a50b5688c341a175a1487e01d8
Author: IoCing <[email protected]>
AuthorDate: Wed Oct 19 00:28:45 2022 +0800
Move TCL test unit/type/list to Go case (#1009)
Co-authored-by: tison <[email protected]>
Co-authored-by: Ruixiang Tan <[email protected]>
---
.github/workflows/kvrocks.yaml | 1 -
tests/gocase/unit/type/list/list_test.go | 626 ++++++++++++++++++++++
tests/gocase/util/tcp_client.go | 15 +
tests/tcl/tests/test_helper.tcl | 1 -
tests/tcl/tests/unit/type/list-common.tcl | 28 -
tests/tcl/tests/unit/type/list.tcl | 838 ------------------------------
6 files changed, 641 insertions(+), 868 deletions(-)
diff --git a/.github/workflows/kvrocks.yaml b/.github/workflows/kvrocks.yaml
index 5088b5e8..75965cfe 100644
--- a/.github/workflows/kvrocks.yaml
+++ b/.github/workflows/kvrocks.yaml
@@ -226,7 +226,6 @@ jobs:
- name: Run Redis Tcl Test
run: |
export ${{ matrix.runtime_env_vars }}
- ./x.py test tcl build --cli-path $HOME/local/bin/redis-cli
--dont-clean
if [[ -n "${{ matrix.with_openssl }}" ]] && [[ "${{ matrix.os }}" ==
ubuntu* ]]; then
git clone https://github.com/jsha/minica
cd minica && go build && cd ..
diff --git a/tests/gocase/unit/type/list/list_test.go
b/tests/gocase/unit/type/list/list_test.go
index 579bfabe..1473daee 100644
--- a/tests/gocase/unit/type/list/list_test.go
+++ b/tests/gocase/unit/type/list/list_test.go
@@ -237,3 +237,629 @@ func TestZipList(t *testing.T) {
}
})
}
+
+func TestList(t *testing.T) {
+ srv := util.StartServer(t, map[string]string{})
+ defer srv.Close()
+ ctx := context.Background()
+ rdb := srv.NewClient()
+ defer func() { require.NoError(t, rdb.Close()) }()
+ rd := srv.NewTCPClient()
+ defer func() { require.NoError(t, rd.Close()) }()
+
+ t.Run("LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - ziplist", func(t
*testing.T) {
+ // first lpush then rpush
+ require.EqualValues(t, 1, rdb.LPush(ctx, "myziplist1",
"aa").Val())
+ require.EqualValues(t, 2, rdb.RPush(ctx, "myziplist1",
"bb").Val())
+ require.EqualValues(t, 3, rdb.RPush(ctx, "myziplist1",
"cc").Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "myziplist1").Val())
+ require.Equal(t, "aa", rdb.LIndex(ctx, "myziplist1", 0).Val())
+ require.Equal(t, "bb", rdb.LIndex(ctx, "myziplist1", 1).Val())
+ require.Equal(t, "cc", rdb.LIndex(ctx, "myziplist1", 2).Val())
+ require.Equal(t, "", rdb.LIndex(ctx, "myziplist1", 3).Val())
+ require.Equal(t, "cc", rdb.RPop(ctx, "myziplist1").Val())
+ require.Equal(t, "aa", rdb.LPop(ctx, "myziplist1").Val())
+
+ // first rpush then lpush
+ require.EqualValues(t, 1, rdb.RPush(ctx, "myziplist2",
"a").Val())
+ require.EqualValues(t, 2, rdb.LPush(ctx, "myziplist2",
"b").Val())
+ require.EqualValues(t, 3, rdb.LPush(ctx, "myziplist2",
"c").Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "myziplist2").Val())
+ require.Equal(t, "c", rdb.LIndex(ctx, "myziplist2", 0).Val())
+ require.Equal(t, "b", rdb.LIndex(ctx, "myziplist2", 1).Val())
+ require.Equal(t, "a", rdb.LIndex(ctx, "myziplist2", 2).Val())
+ require.Equal(t, "", rdb.LIndex(ctx, "myziplist2", 3).Val())
+ require.Equal(t, "a", rdb.RPop(ctx, "myziplist2").Val())
+ require.Equal(t, "c", rdb.LPop(ctx, "myziplist2").Val())
+ })
+
+ t.Run("LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - regular list", func(t
*testing.T) {
+ // first lpush then rpush
+ require.EqualValues(t, 1, rdb.LPush(ctx, "mylist1",
largeValue["linkedList"]).Val())
+ require.EqualValues(t, 2, rdb.RPush(ctx, "mylist1", "b").Val())
+ require.EqualValues(t, 3, rdb.RPush(ctx, "mylist1", "c").Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "mylist1").Val())
+ require.Equal(t, largeValue["linkedList"], rdb.LIndex(ctx,
"mylist1", 0).Val())
+ require.Equal(t, "b", rdb.LIndex(ctx, "mylist1", 1).Val())
+ require.Equal(t, "c", rdb.LIndex(ctx, "mylist1", 2).Val())
+ require.Equal(t, "", rdb.LIndex(ctx, "mylist1", 3).Val())
+ require.Equal(t, "c", rdb.RPop(ctx, "mylist1").Val())
+ require.Equal(t, largeValue["linkedList"], rdb.LPop(ctx,
"mylist1").Val())
+
+ // first rpush then lpush
+ require.EqualValues(t, 1, rdb.RPush(ctx, "mylist2",
largeValue["linkedList"]).Val())
+ require.EqualValues(t, 2, rdb.LPush(ctx, "mylist2", "b").Val())
+ require.EqualValues(t, 3, rdb.LPush(ctx, "mylist2", "c").Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "mylist2").Val())
+ require.Equal(t, "c", rdb.LIndex(ctx, "mylist2", 0).Val())
+ require.Equal(t, "b", rdb.LIndex(ctx, "mylist2", 1).Val())
+ require.Equal(t, largeValue["linkedList"], rdb.LIndex(ctx,
"mylist2", 2).Val())
+ require.Equal(t, "", rdb.LIndex(ctx, "mylist2", 3).Val())
+ require.Equal(t, largeValue["linkedList"], rdb.RPop(ctx,
"mylist2").Val())
+ require.Equal(t, "c", rdb.LPop(ctx, "mylist2").Val())
+ })
+
+ t.Run("R/LPOP against empty list", func(t *testing.T) {
+ require.Equal(t, "", rdb.LPop(ctx, "non-existing-list").Val())
+ })
+
+ t.Run("Variadic RPUSH/LPUSH", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "mylist").Err())
+ require.EqualValues(t, 4, rdb.LPush(ctx, "mylist", "a", "b",
"c", "d").Val())
+ require.EqualValues(t, 8, rdb.RPush(ctx, "mylist", "1", "2",
"3", "4").Val())
+ require.Equal(t, []string{"d", "c", "b", "a", "1", "2", "3",
"4"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run("DEL a list", func(t *testing.T) {
+ require.EqualValues(t, 1, rdb.Del(ctx, "mylist2").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx, "mylist2").Val())
+ require.EqualValues(t, 0, rdb.LLen(ctx, "mylist2").Val())
+ })
+
+ createList := func(key string, entries ...interface{}) {
+ require.NoError(t, rdb.Del(ctx, key).Err())
+ for _, entry := range entries {
+ require.NoError(t, rdb.RPush(ctx, key, entry).Err())
+ }
+ }
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("BLPOP, BRPOP: single existing list - %s",
listType), func(t *testing.T) {
+ createList("blist", []string{"a", "b", large, "c", "d"})
+ require.NoError(t, rd.WriteArgs("blpop", "blist", "1"))
+ rd.MustReadStrings(t, []string{"blist", "a"})
+ require.NoError(t, rd.WriteArgs("brpop", "blist", "1"))
+ rd.MustReadStrings(t, []string{"blist", "d"})
+ require.NoError(t, rd.WriteArgs("blpop", "blist", "1"))
+ rd.MustReadStrings(t, []string{"blist", "b"})
+ require.NoError(t, rd.WriteArgs("brpop", "blist", "1"))
+ rd.MustReadStrings(t, []string{"blist", "c"})
+ })
+
+ t.Run(fmt.Sprintf("BLPOP, BRPOP: multiple existing lists - %s",
listType), func(t *testing.T) {
+ createList("blist1", []string{"a", large, "c"})
+ createList("blist2", []string{"d", large, "f"})
+ require.NoError(t, rd.WriteArgs("blpop", "blist1",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist1", "a"})
+ require.NoError(t, rd.WriteArgs("brpop", "blist1",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist1", "c"})
+ require.EqualValues(t, 1, rdb.LLen(ctx, "blist1").Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "blist2").Val())
+ require.NoError(t, rd.WriteArgs("blpop", "blist2",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist2", "d"})
+ require.NoError(t, rd.WriteArgs("brpop", "blist2",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist2", "f"})
+ require.EqualValues(t, 1, rdb.LLen(ctx, "blist1").Val())
+ require.EqualValues(t, 1, rdb.LLen(ctx, "blist2").Val())
+ })
+
+ t.Run(fmt.Sprintf("BLPOP, BRPOP: second list has an entry -
%s", listType), func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist1").Err())
+ createList("blist2", []string{"d", large, "f"})
+ require.NoError(t, rd.WriteArgs("blpop", "blist1",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist2", "d"})
+ require.NoError(t, rd.WriteArgs("brpop", "blist1",
"blist2", "1"))
+ rd.MustReadStrings(t, []string{"blist2", "f"})
+ require.EqualValues(t, 0, rdb.LLen(ctx, "blist1").Val())
+ require.EqualValues(t, 1, rdb.LLen(ctx, "blist2").Val())
+ })
+ }
+
+ t.Run("BLPOP with same key multiple times should work (redis issue
#801)", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "list1", "list2").Err())
+ require.NoError(t, rd.WriteArgs("blpop", "list1", "list2",
"list2", "list1", "0"))
+ require.NoError(t, rdb.LPush(ctx, "list1", "a").Err())
+ rd.MustReadStrings(t, []string{"list1", "a"})
+ require.NoError(t, rd.WriteArgs("blpop", "list1", "list2",
"list2", "list1", "0"))
+ require.NoError(t, rdb.LPush(ctx, "list2", "b").Err())
+ rd.MustReadStrings(t, []string{"list2", "b"})
+ require.NoError(t, rdb.LPush(ctx, "list1", "a").Err())
+ require.NoError(t, rdb.LPush(ctx, "list2", "b").Err())
+ require.NoError(t, rd.WriteArgs("blpop", "list1", "list2",
"list2", "list1", "0"))
+ rd.MustReadStrings(t, []string{"list1", "a"})
+ require.NoError(t, rd.WriteArgs("blpop", "list1", "list2",
"list2", "list1", "0"))
+ rd.MustReadStrings(t, []string{"list2", "b"})
+ })
+
+ t.Run("BLPOP with variadic LPUSH", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist", "target").Err())
+ time.Sleep(time.Millisecond * 100)
+ require.NoError(t, rd.WriteArgs("blpop", "blist", "0"))
+ time.Sleep(time.Millisecond * 100)
+ require.EqualValues(t, 2, rdb.LPush(ctx, "blist", "foo",
"bar").Val())
+ time.Sleep(time.Millisecond * 100)
+ rd.MustReadStrings(t, []string{"blist", "bar"})
+ require.Equal(t, "foo", rdb.LRange(ctx, "blist", 0,
-1).Val()[0])
+ })
+
+ for _, popType := range []string{"blpop", "brpop"} {
+ t.Run(fmt.Sprintf("%s: with single empty list argument",
popType), func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist1").Err())
+ require.NoError(t, rd.WriteArgs(popType, "blist1", "1"))
+ require.NoError(t, rdb.RPush(ctx, "blist1",
"foo").Err())
+ rd.MustReadStrings(t, []string{"blist1", "foo"})
+ require.EqualValues(t, 0, rdb.Exists(ctx,
"blist1").Val())
+ })
+
+ t.Run(fmt.Sprintf("%s: with negative timeout", popType), func(t
*testing.T) {
+ require.NoError(t, rd.WriteArgs(popType, "blist1",
"-1"))
+ rd.MustMatch(t, ".*negative.*")
+ })
+
+ t.Run(fmt.Sprintf("%s: with zero timeout should block
indefinitely", popType), func(t *testing.T) {
+ // To test this, use a timeout of 0 and wait a second.
+ // The blocking pop should still be waiting for a push.
+ require.NoError(t, rd.WriteArgs(popType, "blist1", "0"))
+ time.Sleep(time.Millisecond * 1000)
+ require.NoError(t, rdb.RPush(ctx, "blist1",
"foo").Err())
+ rd.MustReadStrings(t, []string{"blist1", "foo"})
+ })
+
+ t.Run(fmt.Sprintf("%s: second argument is not a list",
popType), func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist1",
"blist2").Err())
+ require.NoError(t, rdb.Set(ctx, "blist2", "nolist",
0).Err())
+ require.NoError(t, rd.WriteArgs(popType, "blist1",
"blist2", "1"))
+ rd.MustMatch(t, ".*WRONGTYPE.*")
+ })
+
+ t.Run(fmt.Sprintf("%s: timeout", popType), func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist1",
"blist2").Err())
+ require.NoError(t, rd.WriteArgs(popType, "blist1",
"blist2", "1"))
+ rd.MustMatch(t, "")
+ })
+
+ t.Run(fmt.Sprintf("%s: arguments are empty", popType), func(t
*testing.T) {
+ require.NoError(t, rdb.Del(ctx, "blist1",
"blist2").Err())
+ require.NoError(t, rd.WriteArgs(popType, "blist1",
"blist2", "1"))
+ require.NoError(t, rdb.RPush(ctx, "blist1",
"foo").Err())
+ rd.MustReadStrings(t, []string{"blist1", "foo"})
+ require.EqualValues(t, 0, rdb.Exists(ctx,
"blist1").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx,
"blist2").Val())
+ require.NoError(t, rd.WriteArgs(popType, "blist1",
"blist2", "1"))
+ require.NoError(t, rdb.RPush(ctx, "blist2",
"foo").Err())
+ rd.MustReadStrings(t, []string{"blist2", "foo"})
+ require.EqualValues(t, 0, rdb.Exists(ctx,
"blist1").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx,
"blist2").Val())
+ })
+ }
+
+ t.Run("LPUSHX, RPUSHX - generic", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "xlist").Err())
+ require.EqualValues(t, 0, rdb.LPushX(ctx, "xlist", "a").Val())
+ require.EqualValues(t, 0, rdb.LLen(ctx, "xlist").Val())
+ require.EqualValues(t, 0, rdb.RPushX(ctx, "xlist", "a").Val())
+ require.EqualValues(t, 0, rdb.LLen(ctx, "xlist").Val())
+ })
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("LPUSHX, RPUSHX - %s", listType), func(t
*testing.T) {
+ createList("xlist", []string{large, "c"})
+ require.EqualValues(t, 3, rdb.RPushX(ctx, "xlist",
"d").Val())
+ require.EqualValues(t, 4, rdb.LPushX(ctx, "xlist",
"a").Val())
+ require.EqualValues(t, 6, rdb.RPushX(ctx, "xlist",
"42", "x").Val())
+ require.EqualValues(t, 9, rdb.LPushX(ctx, "xlist",
"y3", "y2", "y1").Val())
+ require.Equal(t, []string{"y1", "y2", "y3", "a", large,
"c", "d", "42", "x"}, rdb.LRange(ctx, "xlist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LINSERT - %s", listType), func(t *testing.T)
{
+ createList("xlist", []string{"a", large, "c", "d"})
+ require.EqualValues(t, 5, rdb.LInsert(ctx, "xlist",
"before", "c", "zz").Val())
+ require.Equal(t, []string{"a", large, "zz", "c", "d"},
rdb.LRange(ctx, "xlist", 0, 10).Val())
+ require.EqualValues(t, 6, rdb.LInsert(ctx, "xlist",
"after", "c", "yy").Val())
+ require.Equal(t, []string{"a", large, "zz", "c", "yy",
"d"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+ require.EqualValues(t, 7, rdb.LInsert(ctx, "xlist",
"after", "d", "dd").Val())
+ require.EqualValues(t, -1, rdb.LInsert(ctx, "xlist",
"after", "bad", "ddd").Val())
+ require.Equal(t, []string{"a", large, "zz", "c", "yy",
"d", "dd"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+ require.EqualValues(t, 8, rdb.LInsert(ctx, "xlist",
"before", "a", "aa").Val())
+ require.EqualValues(t, -1, rdb.LInsert(ctx, "xlist",
"before", "bad", "aaa").Val())
+ require.Equal(t, []string{"aa", "a", large, "zz", "c",
"yy", "d", "dd"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+
+ // check inserting integer encoded value
+ require.EqualValues(t, 9, rdb.LInsert(ctx, "xlist",
"before", "aa", "42").Val())
+ require.Equal(t, "42", rdb.LRange(ctx, "xlist", 0,
0).Val()[0])
+ })
+ }
+
+ t.Run("LINSERT raise error on bad syntax", func(t *testing.T) {
+ util.ErrorRegexp(t, rdb.LInsert(ctx, "xlist", "aft3r", "aa",
"42").Err(), ".*syntax.*error.*")
+ })
+
+ listType := "quicklist"
+ for _, num := range []int{250, 500} {
+ checkNumberedListConsistency := func(key string) {
+ l := rdb.LLen(ctx, key).Val()
+ for i := 0; i < int(l); i++ {
+ require.Equal(t, strconv.Itoa(i),
rdb.LIndex(ctx, key, int64(i)).Val())
+ require.Equal(t, strconv.Itoa(int(l)-i-1),
rdb.LIndex(ctx, key, int64(int(l)-i-1)).Val())
+ }
+ }
+
+ checkRandomAccessConsistency := func(key string) {
+ l := rdb.LLen(ctx, key).Val()
+ for i := 0; i < int(l); i++ {
+ k := rand.Intn(int(l))
+ require.Equal(t, strconv.Itoa(k),
rdb.LIndex(ctx, key, int64(k)).Val())
+ require.Equal(t, strconv.Itoa(int(l)-k-1),
rdb.LIndex(ctx, key, int64(int(l)-k-1)).Val())
+ }
+ }
+
+ t.Run(fmt.Sprintf("LINDEX consistency test - %s", listType),
func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "mylist").Err())
+ for i := 0; i < num; i++ {
+ require.NoError(t, rdb.RPush(ctx, "mylist",
strconv.Itoa(i)).Err())
+ }
+ checkNumberedListConsistency("mylist")
+ })
+
+ t.Run(fmt.Sprintf("LINDEX random access - %s", listType),
func(t *testing.T) {
+ checkRandomAccessConsistency("mylist")
+ })
+
+ t.Run(fmt.Sprintf("Check if list is still ok after a DEBUG
RELOAD - %s", listType), func(t *testing.T) {
+ checkNumberedListConsistency("mylist")
+ checkRandomAccessConsistency("mylist")
+ })
+ }
+ t.Run("LLEN against non-list value error", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "mylist").Err())
+ require.NoError(t, rdb.Set(ctx, "mylist", "foobar", 0).Err())
+ require.ErrorContains(t, rdb.LLen(ctx, "mylist").Err(),
"WRONGTYPE")
+ })
+
+ t.Run("LLEN against non existing key", func(t *testing.T) {
+ require.EqualValues(t, 0, rdb.LLen(ctx, "not-a-key").Val())
+ })
+
+ t.Run("LINDEX against non-list value error", func(t *testing.T) {
+ require.ErrorContains(t, rdb.LIndex(ctx, "mylist", 0).Err(),
"WRONGTYPE")
+ })
+
+ t.Run("LINDEX against non existing key", func(t *testing.T) {
+ require.Equal(t, "", rdb.LIndex(ctx, "not-a-key", 10).Val())
+ })
+
+ t.Run("LPUSH against non-list value error", func(t *testing.T) {
+ require.ErrorContains(t, rdb.LPush(ctx, "mylist", 0).Err(),
"WRONGTYPE")
+ })
+
+ t.Run("RPUSH against non-list value error", func(t *testing.T) {
+ require.ErrorContains(t, rdb.RPush(ctx, "mylist", 0).Err(),
"WRONGTYPE")
+ })
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("RPOPLPUSH base case - %s", listType), func(t
*testing.T) {
+ require.NoError(t, rdb.Del(ctx, "mylist1",
"mylist2").Err())
+ createList("mylist1", []string{"a", large, "c", "d"})
+ require.Equal(t, "d", rdb.RPopLPush(ctx, "mylist1",
"mylist2").Val())
+ require.Equal(t, "c", rdb.RPopLPush(ctx, "mylist1",
"mylist2").Val())
+ require.Equal(t, []string{"a", large}, rdb.LRange(ctx,
"mylist1", 0, -1).Val())
+ require.Equal(t, []string{"c", "d"}, rdb.LRange(ctx,
"mylist2", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("RPOPLPUSH with the same list as src and dst
- %s", listType), func(t *testing.T) {
+ createList("mylist", []string{"a", large, "c"})
+ require.Equal(t, []string{"a", large, "c"},
rdb.LRange(ctx, "mylist", 0, -1).Val())
+ require.Equal(t, "c", rdb.RPopLPush(ctx, "mylist",
"mylist").Val())
+ require.Equal(t, []string{"c", "a", large},
rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ for otherListType, otherLarge := range largeValue {
+ t.Run(fmt.Sprintf("RPOPLPUSH with %s source and
existing target %s", listType, otherListType), func(t *testing.T) {
+ createList("srclist", []string{"a", "b", "c",
large})
+ createList("dstlist", []string{otherLarge})
+ require.Equal(t, large, rdb.RPopLPush(ctx,
"srclist", "dstlist").Val())
+ require.Equal(t, "c", rdb.RPopLPush(ctx,
"srclist", "dstlist").Val())
+ require.Equal(t, []string{"a", "b"},
rdb.LRange(ctx, "srclist", 0, -1).Val())
+ require.Equal(t, []string{"c", large,
otherLarge}, rdb.LRange(ctx, "dstlist", 0, -1).Val())
+ })
+ }
+ }
+
+ t.Run("RPOPLPUSH against non existing key", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+ require.Equal(t, "", rdb.RPopLPush(ctx, "srclist",
"dstlist").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx, "srclist").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx, "dstlist").Val())
+ })
+
+ t.Run("RPOPLPUSH against non list src key", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+ require.NoError(t, rdb.Set(ctx, "srclist", "x", 0).Err())
+ require.ErrorContains(t, rdb.RPopLPush(ctx, "srclist",
"dstlist").Err(), "WRONGTYPE")
+ require.Equal(t, "string", rdb.Type(ctx, "srclist").Val())
+ require.EqualValues(t, 0, rdb.Exists(ctx, "newlist").Val())
+ })
+
+ t.Run("RPOPLPUSH against non list dst key", func(t *testing.T) {
+ createList("srclist", []string{"a", "b", "c", "d"})
+ require.NoError(t, rdb.Set(ctx, "dstlist", "x", 0).Err())
+ require.ErrorContains(t, rdb.RPopLPush(ctx, "srclist",
"dstlist").Err(), "WRONGTYPE")
+ require.Equal(t, "string", rdb.Type(ctx, "dstlist").Val())
+ require.Equal(t, []string{"a", "b", "c", "d"}, rdb.LRange(ctx,
"srclist", 0, -1).Val())
+ })
+
+ t.Run("RPOPLPUSH against non existing src key", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+ require.Equal(t, "", rdb.RPopLPush(ctx, "srclist",
"dstlist").Val())
+ })
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("Basic LPOP/RPOP - %s", listType), func(t
*testing.T) {
+ createList("mylist", []string{large, "1", "2"})
+
+ require.Equal(t, large, rdb.LPop(ctx, "mylist").Val())
+ require.Equal(t, "2", rdb.RPop(ctx, "mylist").Val())
+ require.Equal(t, "1", rdb.LPop(ctx, "mylist").Val())
+ require.EqualValues(t, 0, rdb.LLen(ctx, "mylist").Val())
+
+ // pop on empty list
+ require.Equal(t, "", rdb.LPop(ctx, "mylist").Val())
+ require.Equal(t, "", rdb.LPop(ctx, "mylist").Val())
+ })
+ }
+
+ t.Run("LPOP/RPOP against non list value", func(t *testing.T) {
+ require.NoError(t, rdb.Set(ctx, "notalist", "foo", 0).Err())
+ require.ErrorContains(t, rdb.LPop(ctx, "notalist").Err(),
"WRONGTYPE")
+ require.ErrorContains(t, rdb.RPop(ctx, "notalist").Err(),
"WRONGTYPE")
+ })
+
+ t.Run("LPOP/RPOP with wrong number of arguments", func(t *testing.T) {
+ require.ErrorContains(t, rdb.Do(ctx, "lpop", "key", "1",
"1").Err(), "wrong number of arguments")
+ require.ErrorContains(t, rdb.Do(ctx, "lpop", "key", "2",
"2").Err(), "wrong number of arguments")
+ })
+
+ t.Run("RPOP/LPOP with the optional count argument", func(t *testing.T) {
+ require.EqualValues(t, 7, rdb.LPush(ctx, "listcount", "aa",
"bb", "cc", "dd", "ee", "ff", "gg").Val())
+ require.Equal(t, []string{"gg"}, rdb.LPopCount(ctx,
"listcount", 1).Val())
+ require.Equal(t, []string{"ff", "ee"}, rdb.LPopCount(ctx,
"listcount", 2).Val())
+ require.Equal(t, []string{"aa", "bb"}, rdb.RPopCount(ctx,
"listcount", 2).Val())
+ require.Equal(t, []string{"cc"}, rdb.RPopCount(ctx,
"listcount", 1).Val())
+ require.Equal(t, []string{"dd"}, rdb.LPopCount(ctx,
"listcount", 123).Val())
+ util.ErrorRegexp(t, rdb.LPopCount(ctx, "forbatqaz",
-123).Err(), ".*ERR.*range.*")
+ })
+
+ t.Run("LPOP/RPOP with the count 0 returns an empty array", func(t
*testing.T) {
+ require.NoError(t, rdb.LPush(ctx, "listcount", "zero").Err())
+ require.Equal(t, []string{}, rdb.LPopCount(ctx, "listcount",
0).Val())
+ require.Equal(t, []string{}, rdb.RPopCount(ctx, "listcount",
0).Val())
+ })
+
+ t.Run("LPOP/RPOP against non existing key", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "non_existing_key").Err())
+ require.EqualError(t, rdb.LPop(ctx, "non_existing_key").Err(),
redis.Nil.Error())
+ require.EqualError(t, rdb.RPop(ctx, "non_existing_key").Err(),
redis.Nil.Error())
+ })
+
+ t.Run("LPOP/RPOP with <count> against non existing key", func(t
*testing.T) {
+ require.NoError(t, rdb.Del(ctx, "non_existing_key").Err())
+ require.EqualError(t, rdb.LPopCount(ctx, "non_existing_key",
0).Err(), redis.Nil.Error())
+ require.EqualError(t, rdb.LPopCount(ctx, "non_existing_key",
1).Err(), redis.Nil.Error())
+ require.EqualError(t, rdb.RPopCount(ctx, "non_existing_key",
0).Err(), redis.Nil.Error())
+ require.EqualError(t, rdb.RPopCount(ctx, "non_existing_key",
1).Err(), redis.Nil.Error())
+ })
+
+ listType = "quicklist"
+ for _, num := range []int{250, 500} {
+ t.Run(fmt.Sprintf("Mass RPOP/LPOP - %s", listType), func(t
*testing.T) {
+ require.NoError(t, rdb.Del(ctx, "mylist").Err())
+ sum1 := 0
+ for i := 0; i < num; i++ {
+ require.NoError(t, rdb.LPush(ctx, "mylist",
strconv.Itoa(i)).Err())
+ sum1 += i
+ }
+ sum2 := 0
+ for i := 0; i < num/2; i++ {
+ if v1, err := strconv.Atoi(rdb.LPop(ctx,
"mylist").Val()); err == nil {
+ sum2 += v1
+ }
+ if v2, err := strconv.Atoi(rdb.RPop(ctx,
"mylist").Val()); err == nil {
+ sum2 += v2
+ }
+ }
+ require.Equal(t, sum1, sum2)
+ })
+ }
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("LRANGE basics - %s", listType), func(t
*testing.T) {
+ createList("mylist", []string{large, "1", "2", "3",
"4", "5", "6", "7", "8", "9"})
+ require.Equal(t, []string{"1", "2", "3", "4", "5", "6",
"7", "8"}, rdb.LRange(ctx, "mylist", 1, -2).Val())
+ require.Equal(t, []string{"7", "8", "9"},
rdb.LRange(ctx, "mylist", -3, -1).Val())
+ require.Equal(t, []string{"4"}, rdb.LRange(ctx,
"mylist", 4, 4).Val())
+ })
+
+ t.Run(fmt.Sprintf("LRANGE inverted indexes - %s", listType),
func(t *testing.T) {
+ createList("mylist", []string{large, "1", "2", "3",
"4", "5", "6", "7", "8", "9"})
+ require.Equal(t, []string{}, rdb.LRange(ctx, "mylist",
6, 2).Val())
+ })
+
+ t.Run(fmt.Sprintf("LRANGE out of range indexes including the
full list - $type - %s", listType), func(t *testing.T) {
+ createList("mylist", []string{large, "1", "2", "3"})
+ require.Equal(t, []string{large, "1", "2", "3"},
rdb.LRange(ctx, "mylist", -1000, 1000).Val())
+ })
+
+ t.Run(fmt.Sprintf("LRANGE out of range negative end index -
%s", listType), func(t *testing.T) {
+ createList("mylist", []string{large, "1", "2", "3"})
+ require.Equal(t, []string{large}, rdb.LRange(ctx,
"mylist", 0, -4).Val())
+ require.Equal(t, []string{}, rdb.LRange(ctx, "mylist",
0, -5).Val())
+ })
+ }
+
+ t.Run("LRANGE against non existing key", func(t *testing.T) {
+ require.Equal(t, []string{}, rdb.LRange(ctx, "nosuchkey", 0,
1).Val())
+ })
+
+ for listType, large := range largeValue {
+ trimList := func(listType string, min, max int64) []string {
+ require.NoError(t, rdb.Del(ctx, "mylist").Err())
+ createList("mylist", []string{"1", "2", "3", "4",
large})
+ require.NoError(t, rdb.LTrim(ctx, "mylist", min,
max).Err())
+ return rdb.LRange(ctx, "mylist", 0, -1).Val()
+ }
+
+ t.Run(fmt.Sprintf("LTRIM basics - %s", listType), func(t
*testing.T) {
+ require.Equal(t, []string{"1"}, trimList(listType, 0,
0))
+ require.Equal(t, []string{"1", "2"}, trimList(listType,
0, 1))
+ require.Equal(t, []string{"1", "2", "3"},
trimList(listType, 0, 2))
+ require.Equal(t, []string{"2", "3"}, trimList(listType,
1, 2))
+ require.Equal(t, []string{"2", "3", "4", large},
trimList(listType, 1, -1))
+ require.Equal(t, []string{"2", "3", "4"},
trimList(listType, 1, -2))
+ require.Equal(t, []string{"4", large},
trimList(listType, -2, -1))
+ require.Equal(t, []string{large}, trimList(listType,
-1, -1))
+ require.Equal(t, []string{"1", "2", "3", "4", large},
trimList(listType, -5, -1))
+ require.Equal(t, []string{"1", "2", "3", "4", large},
trimList(listType, -10, 10))
+ require.Equal(t, []string{"1", "2", "3", "4", large},
trimList(listType, 0, 5))
+ require.Equal(t, []string{"1", "2", "3", "4", large},
trimList(listType, 0, 10))
+ })
+
+ t.Run(fmt.Sprintf("LTRIM out of range negative end index - %s",
listType), func(t *testing.T) {
+ require.Equal(t, []string{"1"}, trimList(listType, 0,
-5))
+ require.Equal(t, []string{}, trimList(listType, 0, -6))
+ })
+
+ t.Run(fmt.Sprintf("LTRIM lrem elements after ltrim list - %s",
listType), func(t *testing.T) {
+ createList("myotherlist", []string{"0", "1", "2", "3",
"4", "3", "6", "7", "3", "9"})
+ require.Equal(t, "OK", rdb.LTrim(ctx, "myotherlist", 2,
-3).Val())
+ require.Equal(t, []string{"2", "3", "4", "3", "6",
"7"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+ require.EqualValues(t, 2, rdb.LRem(ctx, "myotherlist",
4, "3").Val())
+ require.Equal(t, []string{"2", "4", "6", "7"},
rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LTRIM linsert elements after ltrim list -
%s", listType), func(t *testing.T) {
+ createList("myotherlist1", []string{"0", "1", "2", "3",
"4", "3", "6", "7", "3", "9"})
+ require.Equal(t, "OK", rdb.LTrim(ctx, "myotherlist1",
2, -3).Val())
+ require.Equal(t, []string{"2", "3", "4", "3", "6",
"7"}, rdb.LRange(ctx, "myotherlist1", 0, -1).Val())
+ require.EqualValues(t, -1, rdb.LInsert(ctx,
"myotherlist1", "before", "9", "0").Val())
+ require.EqualValues(t, 7, rdb.LInsert(ctx,
"myotherlist1", "before", "4", "0").Val())
+ require.Equal(t, []string{"2", "3", "0", "4", "3", "6",
"7"}, rdb.LRange(ctx, "myotherlist1", 0, -1).Val())
+ })
+ }
+
+ for listType, large := range largeValue {
+ t.Run(fmt.Sprintf("LSET - %s", listType), func(t *testing.T) {
+ createList("mylist", []string{"99", "98", large, "96",
"95"})
+ require.NoError(t, rdb.LSet(ctx, "mylist", 1,
"foo").Err())
+ require.NoError(t, rdb.LSet(ctx, "mylist", -1,
"bar").Err())
+ require.Equal(t, []string{"99", "foo", large, "96",
"bar"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LSET out of range index - %s", listType),
func(t *testing.T) {
+ util.ErrorRegexp(t, rdb.LSet(ctx, "mylist", 10,
"foo").Err(), "ERR.*range.*")
+ })
+ }
+
+ t.Run("LSET against non existing key", func(t *testing.T) {
+ util.ErrorRegexp(t, rdb.LSet(ctx, "nosuchkey", 10,
"foo").Err(), "ERR.*NotFound.*")
+ })
+
+ t.Run("LSET against non list value", func(t *testing.T) {
+ require.NoError(t, rdb.Set(ctx, "nolist", "foobar", 0).Err())
+ require.ErrorContains(t, rdb.LSet(ctx, "nolist", 0,
"foo").Err(), "WRONGTYPE")
+ })
+
+ for listType, e := range largeValue {
+ t.Run(fmt.Sprintf("LREM remove all the occurrences - %s",
listType), func(t *testing.T) {
+ createList("mylist", []string{e, "foo", "bar",
"foobar", "foobared", "zap", "bar", "test", "foo"})
+ require.EqualValues(t, 2, rdb.LRem(ctx, "mylist", 0,
"bar").Val())
+ require.Equal(t, []string{e, "foo", "foobar",
"foobared", "zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM remove the first occurrence - %s",
listType), func(t *testing.T) {
+ require.EqualValues(t, 1, rdb.LRem(ctx, "mylist", 1,
"foo").Val())
+ require.Equal(t, []string{e, "foobar", "foobared",
"zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM remove non existing element - %s",
listType), func(t *testing.T) {
+ require.EqualValues(t, 0, rdb.LRem(ctx, "mylist", 1,
"nosuchelement").Val())
+ require.Equal(t, []string{e, "foobar", "foobared",
"zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM starting from tail with negative count
- %s", listType), func(t *testing.T) {
+ createList("mylist", []string{e, "foo", "bar",
"foobar", "foobared", "zap", "bar", "test", "foo", "foo"})
+ require.EqualValues(t, 1, rdb.LRem(ctx, "mylist", -1,
"bar").Val())
+ require.Equal(t, []string{e, "foo", "bar", "foobar",
"foobared", "zap", "test", "foo", "foo"}, rdb.LRange(ctx, "mylist", 0,
-1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM starting from tail with negative count
(2) - %s", listType), func(t *testing.T) {
+ require.EqualValues(t, 2, rdb.LRem(ctx, "mylist", -2,
"foo").Val())
+ require.Equal(t, []string{e, "foo", "bar", "foobar",
"foobared", "zap", "test"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM deleting objects that may be int
encoded - %s", listType), func(t *testing.T) {
+ createList("myotherlist", e, 1, 2, 3)
+ require.EqualValues(t, 1, rdb.LRem(ctx, "myotherlist",
1, 2).Val())
+ require.EqualValues(t, 3, rdb.LLen(ctx,
"myotherlist").Val())
+ })
+
+ t.Run(fmt.Sprintf("LREM remove elements in repeating list -
%s", listType), func(t *testing.T) {
+ createList("myotherlist", e, "a", "b", "c", "d", "e",
"f", "a", "f", "a", "f")
+ require.EqualValues(t, 1, rdb.LRem(ctx, "myotherlist",
1, "f").Val())
+ require.Equal(t, []string{e, "a", "b", "c", "d", "e",
"a", "f", "a", "f"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+ require.EqualValues(t, 2, rdb.LRem(ctx, "myotherlist",
0, "f").Val())
+ require.Equal(t, []string{e, "a", "b", "c", "d", "e",
"a", "a"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+ })
+ }
+
+ t.Run("Test LMOVE on different keys", func(t *testing.T) {
+ require.NoError(t, rdb.RPush(ctx, "list1{t}", "1").Err())
+ require.NoError(t, rdb.RPush(ctx, "list1{t}", "2").Err())
+ require.NoError(t, rdb.RPush(ctx, "list1{t}", "3").Err())
+ require.NoError(t, rdb.RPush(ctx, "list1{t}", "4").Err())
+ require.NoError(t, rdb.RPush(ctx, "list1{t}", "5").Err())
+ require.NoError(t, rdb.LMove(ctx, "list1{t}", "list2{t}",
"RIGHT", "LEFT").Err())
+ require.NoError(t, rdb.LMove(ctx, "list1{t}", "list2{t}",
"LEFT", "RIGHT").Err())
+ require.EqualValues(t, 3, rdb.LLen(ctx, "list1{t}").Val())
+ require.EqualValues(t, 2, rdb.LLen(ctx, "list2{t}").Val())
+ require.Equal(t, []string{"2", "3", "4"}, rdb.LRange(ctx,
"list1{t}", 0, -1).Val())
+ require.Equal(t, []string{"5", "1"}, rdb.LRange(ctx,
"list2{t}", 0, -1).Val())
+ })
+
+ for _, from := range []string{"LEFT", "RIGHT"} {
+ for _, to := range []string{"LEFT", "RIGHT"} {
+ t.Run(fmt.Sprintf("LMOVE %s %s on the list node", from,
to), func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx,
"target_key{t}").Err())
+ require.NoError(t, rdb.RPush(ctx,
"target_key{t}", 1).Err())
+ createList("list{t}", []string{"a", "b", "c",
"d"})
+ require.NoError(t, rd.WriteArgs("lmove",
"list{t}", "target_key{t}", from, to))
+ r, err1 := rd.ReadLine()
+ require.Equal(t, "$1", r)
+ require.NoError(t, err1)
+ elem, err2 := rd.ReadLine()
+ require.NoError(t, err2)
+ if from == "RIGHT" {
+ require.Equal(t, elem, "d")
+ require.Equal(t, []string{"a", "b",
"c"}, rdb.LRange(ctx, "list{t}", 0, -1).Val())
+ } else {
+ require.Equal(t, elem, "a")
+ require.Equal(t, []string{"b", "c",
"d"}, rdb.LRange(ctx, "list{t}", 0, -1).Val())
+ }
+ if to == "RIGHT" {
+ require.Equal(t, elem, rdb.RPop(ctx,
"target_key{t}").Val())
+ } else {
+ require.Equal(t, elem, rdb.LPop(ctx,
"target_key{t}").Val())
+ }
+ })
+ }
+ }
+}
diff --git a/tests/gocase/util/tcp_client.go b/tests/gocase/util/tcp_client.go
index 0e8f7663..b364aef5 100644
--- a/tests/gocase/util/tcp_client.go
+++ b/tests/gocase/util/tcp_client.go
@@ -24,6 +24,7 @@ import (
"errors"
"fmt"
"net"
+ "strconv"
"strings"
"testing"
@@ -62,6 +63,20 @@ func (c *TCPClient) MustRead(t testing.TB, s string) {
require.Equal(t, s, r)
}
+func (c *TCPClient) MustReadStrings(t testing.TB, s []string) {
+ r, err := c.ReadLine()
+ require.NoError(t, err)
+ require.EqualValues(t, '*', r[0])
+ n, err := strconv.Atoi(r[1:])
+ require.NoError(t, err)
+ require.Equal(t, n, len(s))
+ for i := 0; i < n; i++ {
+ _, err := c.ReadLine()
+ require.NoError(t, err)
+ c.MustRead(t, s[i])
+ }
+}
+
func (c *TCPClient) MustMatch(t testing.TB, rx string) {
r, err := c.ReadLine()
require.NoError(t, err)
diff --git a/tests/tcl/tests/test_helper.tcl b/tests/tcl/tests/test_helper.tcl
index 2d99606e..72ca6412 100644
--- a/tests/tcl/tests/test_helper.tcl
+++ b/tests/tcl/tests/test_helper.tcl
@@ -33,7 +33,6 @@ source tests/support/test.tcl
source tests/support/util.tcl
set ::all_tests {
- unit/type/list
}
# Index to the next test to run in the ::all_tests list.
diff --git a/tests/tcl/tests/unit/type/list-common.tcl
b/tests/tcl/tests/unit/type/list-common.tcl
deleted file mode 100644
index c012ddd5..00000000
--- a/tests/tcl/tests/unit/type/list-common.tcl
+++ /dev/null
@@ -1,28 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Copyright (c) 2006-2020, Salvatore Sanfilippo
-# See bundled license file licenses/LICENSE.redis for details.
-
-# This file is copied and modified from the Redis project,
-# which started out as:
https://github.com/redis/redis/blob/dbcc0a8/tests/unit/type/list-common.tcl
-
-# We need a value larger than list-max-ziplist-value to make sure
-# the list has the right encoding when it is swapped in again.
-array set largevalue {}
-set largevalue(ziplist) "hello"
-set largevalue(linkedlist) [string repeat "hello" 4]
diff --git a/tests/tcl/tests/unit/type/list.tcl
b/tests/tcl/tests/unit/type/list.tcl
deleted file mode 100644
index a8b78392..00000000
--- a/tests/tcl/tests/unit/type/list.tcl
+++ /dev/null
@@ -1,838 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Copyright (c) 2006-2020, Salvatore Sanfilippo
-# See bundled license file licenses/LICENSE.redis for details.
-
-# This file is copied and modified from the Redis project,
-# which started out as:
https://github.com/redis/redis/blob/dbcc0a8/tests/unit/type/list.tcl
-
-start_server {
- tags {"list"}
-} {
- source "tests/unit/type/list-common.tcl"
-
- test {LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - ziplist} {
- # first lpush then rpush
- assert_equal 1 [r lpush myziplist1 aa]
- assert_equal 2 [r rpush myziplist1 bb]
- assert_equal 3 [r rpush myziplist1 cc]
- assert_equal 3 [r llen myziplist1]
- assert_equal aa [r lindex myziplist1 0]
- assert_equal bb [r lindex myziplist1 1]
- assert_equal cc [r lindex myziplist1 2]
- assert_equal {} [r lindex myziplist2 3]
- assert_equal cc [r rpop myziplist1]
- assert_equal aa [r lpop myziplist1]
- #assert_encoding quicklist myziplist1
-
- # first rpush then lpush
- assert_equal 1 [r rpush myziplist2 a]
- assert_equal 2 [r lpush myziplist2 b]
- assert_equal 3 [r lpush myziplist2 c]
- assert_equal 3 [r llen myziplist2]
- assert_equal c [r lindex myziplist2 0]
- assert_equal b [r lindex myziplist2 1]
- assert_equal a [r lindex myziplist2 2]
- assert_equal {} [r lindex myziplist2 3]
- assert_equal a [r rpop myziplist2]
- assert_equal c [r lpop myziplist2]
- #assert_encoding quicklist myziplist2
- }
-
- test {LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - regular list} {
- # first lpush then rpush
- assert_equal 1 [r lpush mylist1 $largevalue(linkedlist)]
- #assert_encoding quicklist mylist1
- assert_equal 2 [r rpush mylist1 b]
- assert_equal 3 [r rpush mylist1 c]
- assert_equal 3 [r llen mylist1]
- assert_equal $largevalue(linkedlist) [r lindex mylist1 0]
- assert_equal b [r lindex mylist1 1]
- assert_equal c [r lindex mylist1 2]
- assert_equal {} [r lindex mylist1 3]
- assert_equal c [r rpop mylist1]
- assert_equal $largevalue(linkedlist) [r lpop mylist1]
-
- # first rpush then lpush
- assert_equal 1 [r rpush mylist2 $largevalue(linkedlist)]
- #assert_encoding quicklist mylist2
- assert_equal 2 [r lpush mylist2 b]
- assert_equal 3 [r lpush mylist2 c]
- assert_equal 3 [r llen mylist2]
- assert_equal c [r lindex mylist2 0]
- assert_equal b [r lindex mylist2 1]
- assert_equal $largevalue(linkedlist) [r lindex mylist2 2]
- assert_equal {} [r lindex mylist2 3]
- assert_equal $largevalue(linkedlist) [r rpop mylist2]
- assert_equal c [r lpop mylist2]
- }
-
- test {R/LPOP against empty list} {
- r lpop non-existing-list
- } {}
-
- test {Variadic RPUSH/LPUSH} {
- r del mylist
- assert_equal 4 [r lpush mylist a b c d]
- assert_equal 8 [r rpush mylist 0 1 2 3]
- assert_equal {d c b a 0 1 2 3} [r lrange mylist 0 -1]
- }
-
- test {DEL a list} {
- assert_equal 1 [r del mylist2]
- assert_equal 0 [r exists mylist2]
- assert_equal 0 [r llen mylist2]
- }
-
- proc create_list {key entries} {
- r del $key
- foreach entry $entries { r rpush $key $entry }
- #assert_encoding quicklist $key
- }
-
- foreach {type large} [array get largevalue] {
- test "BLPOP, BRPOP: single existing list - $type" {
- set rd [redis_deferring_client]
- create_list blist "a b $large c d"
-
- $rd blpop blist 1
- assert_equal {blist a} [$rd read]
- $rd brpop blist 1
- assert_equal {blist d} [$rd read]
-
- $rd blpop blist 1
- assert_equal {blist b} [$rd read]
- $rd brpop blist 1
- assert_equal {blist c} [$rd read]
- }
-
- test "BLPOP, BRPOP: multiple existing lists - $type" {
- set rd [redis_deferring_client]
- create_list blist1 "a $large c"
- create_list blist2 "d $large f"
-
- $rd blpop blist1 blist2 1
- assert_equal {blist1 a} [$rd read]
- $rd brpop blist1 blist2 1
- assert_equal {blist1 c} [$rd read]
- assert_equal 1 [r llen blist1]
- assert_equal 3 [r llen blist2]
-
- $rd blpop blist2 blist1 1
- assert_equal {blist2 d} [$rd read]
- $rd brpop blist2 blist1 1
- assert_equal {blist2 f} [$rd read]
- assert_equal 1 [r llen blist1]
- assert_equal 1 [r llen blist2]
- }
-
- test "BLPOP, BRPOP: second list has an entry - $type" {
- set rd [redis_deferring_client]
- r del blist1
- create_list blist2 "d $large f"
-
- $rd blpop blist1 blist2 1
- assert_equal {blist2 d} [$rd read]
- $rd brpop blist1 blist2 1
- assert_equal {blist2 f} [$rd read]
- assert_equal 0 [r llen blist1]
- assert_equal 1 [r llen blist2]
- }
-
- # test "BRPOPLPUSH - $type" {
- # r del target
-
- # set rd [redis_deferring_client]
- # create_list blist "a b $large c d"
-
- # $rd brpoplpush blist target 1
- # assert_equal d [$rd read]
-
- # assert_equal d [r rpop target]
- # assert_equal "a b $large c" [r lrange blist 0 -1]
- # }
- }
-
- test "BLPOP with same key multiple times should work (issue #801)" {
- set rd [redis_deferring_client]
- r del list1 list2
-
- # Data arriving after the BLPOP.
- $rd blpop list1 list2 list2 list1 0
- r lpush list1 a
- assert_equal [$rd read] {list1 a}
- $rd blpop list1 list2 list2 list1 0
- r lpush list2 b
- assert_equal [$rd read] {list2 b}
-
- # Data already there.
- r lpush list1 a
- r lpush list2 b
- $rd blpop list1 list2 list2 list1 0
- assert_equal [$rd read] {list1 a}
- $rd blpop list1 list2 list2 list1 0
- assert_equal [$rd read] {list2 b}
- }
-
- test "BLPOP with variadic LPUSH" {
- set rd [redis_deferring_client]
- r del blist target
- if {$::valgrind} {after 100}
- $rd blpop blist 0
- if {$::valgrind} {after 100}
- assert_equal 2 [r lpush blist foo bar]
- if {$::valgrind} {after 100}
- assert_equal {blist bar} [$rd read]
- assert_equal foo [lindex [r lrange blist 0 -1] 0]
- }
-
- # test "BRPOPLPUSH with zero timeout should block indefinitely" {
- # set rd [redis_deferring_client]
- # r del blist target
- # $rd brpoplpush blist target 0
- # after 1000
- # r rpush blist foo
- # assert_equal foo [$rd read]
- # assert_equal {foo} [r lrange target 0 -1]
- # }
-
- # test "BRPOPLPUSH with a client BLPOPing the target list" {
- # set rd [redis_deferring_client]
- # set rd2 [redis_deferring_client]
- # r del blist target
- # $rd2 blpop target 0
- # $rd brpoplpush blist target 0
- # after 1000
- # r rpush blist foo
- # assert_equal foo [$rd read]
- # assert_equal {target foo} [$rd2 read]
- # assert_equal 0 [r exists target]
- # }
-
- # test "BRPOPLPUSH with wrong source type" {
- # set rd [redis_deferring_client]
- # r del blist target
- # r set blist nolist
- # $rd brpoplpush blist target 1
- # assert_error "*WRONGTYPE*" {$rd read}
- # }
-
- # test "BRPOPLPUSH with wrong destination type" {
- # set rd [redis_deferring_client]
- # r del blist target
- # r set target nolist
- # r lpush blist foo
- # $rd brpoplpush blist target 1
- # assert_error "*WRONGTYPE*" {$rd read}
-
- # set rd [redis_deferring_client]
- # r del blist target
- # r set target nolist
- # $rd brpoplpush blist target 0
- # after 1000
- # r rpush blist foo
- # assert_error "*WRONGTYPE*" {$rd read}
- # assert_equal {foo} [r lrange blist 0 -1]
- # }
-
- # test "BRPOPLPUSH maintains order of elements after failure" {
- # set rd [redis_deferring_client]
- # r del blist target
- # r set target nolist
- # $rd brpoplpush blist target 0
- # r rpush blist a b c
- # assert_error "*WRONGTYPE*" {$rd read}
- # r lrange blist 0 -1
- # } {a b c}
-
- # test "BRPOPLPUSH with multiple blocked clients" {
- # set rd1 [redis_deferring_client]
- # set rd2 [redis_deferring_client]
- # r del blist target1 target2
- # r set target1 nolist
- # $rd1 brpoplpush blist target1 0
- # $rd2 brpoplpush blist target2 0
- # r lpush blist foo
-
- # assert_error "*WRONGTYPE*" {$rd1 read}
- # assert_equal {foo} [$rd2 read]
- # assert_equal {foo} [r lrange target2 0 -1]
- # }
-
- # test "Linked BRPOPLPUSH" {
- # set rd1 [redis_deferring_client]
- # set rd2 [redis_deferring_client]
- # r del list1 list2 list3
- # $rd1 brpoplpush list1 list2 0
- # $rd2 brpoplpush list2 list3 0
- # r rpush list1 foo
- # assert_equal {} [r lrange list1 0 -1]
- # assert_equal {} [r lrange list2 0 -1]
- # assert_equal {foo} [r lrange list3 0 -1]
- # }
-
- # test "Circular BRPOPLPUSH" {
- # set rd1 [redis_deferring_client]
- # set rd2 [redis_deferring_client]
- # r del list1 list2
- # $rd1 brpoplpush list1 list2 0
- # $rd2 brpoplpush list2 list1 0
- # r rpush list1 foo
- # assert_equal {foo} [r lrange list1 0 -1]
- # assert_equal {} [r lrange list2 0 -1]
- # }
-
- # test "Self-referential BRPOPLPUSH" {
- # set rd [redis_deferring_client]
- # r del blist
- # $rd brpoplpush blist blist 0
- # r rpush blist foo
- # assert_equal {foo} [r lrange blist 0 -1]
- # }
-
- # test {BRPOPLPUSH timeout} {
- # set rd [redis_deferring_client]
-
- # $rd brpoplpush foo_list bar_list 1
- # after 2000
- # $rd read
- # } {}
-
- foreach {pop} {BLPOP BRPOP} {
- test "$pop: with single empty list argument" {
- set rd [redis_deferring_client]
- r del blist1
- $rd $pop blist1 1
- r rpush blist1 foo
- assert_equal {blist1 foo} [$rd read]
- assert_equal 0 [r exists blist1]
- }
-
- test "$pop: with negative timeout" {
- set rd [redis_deferring_client]
- $rd $pop blist1 -1
- assert_error "*negative*" {$rd read}
- }
-
- # test "$pop: with non-integer timeout" {
- # set rd [redis_deferring_client]
- # $rd $pop blist1 1.1
- # assert_error "ERR*not an integer*" {$rd read}
- # }
-
- test "$pop: with zero timeout should block indefinitely" {
- # To test this, use a timeout of 0 and wait a second.
- # The blocking pop should still be waiting for a push.
- set rd [redis_deferring_client]
- $rd $pop blist1 0
- after 1000
- r rpush blist1 foo
- assert_equal {blist1 foo} [$rd read]
- }
-
- test "$pop: second argument is not a list" {
- set rd [redis_deferring_client]
- r del blist1 blist2
- r set blist2 nolist
- $rd $pop blist1 blist2 1
- assert_error "*WRONGTYPE*" {$rd read}
- }
-
- test "$pop: timeout" {
- set rd [redis_deferring_client]
- r del blist1 blist2
- $rd $pop blist1 blist2 1
- assert_equal {} [$rd read]
- }
-
- test "$pop: arguments are empty" {
- set rd [redis_deferring_client]
- r del blist1 blist2
-
- $rd $pop blist1 blist2 1
- r rpush blist1 foo
- assert_equal {blist1 foo} [$rd read]
- assert_equal 0 [r exists blist1]
- assert_equal 0 [r exists blist2]
-
- $rd $pop blist1 blist2 1
- r rpush blist2 foo
- assert_equal {blist2 foo} [$rd read]
- assert_equal 0 [r exists blist1]
- assert_equal 0 [r exists blist2]
- }
- }
-
- test {LPUSHX, RPUSHX - generic} {
- r del xlist
- assert_equal 0 [r lpushx xlist a]
- assert_equal 0 [r llen xlist]
- assert_equal 0 [r rpushx xlist a]
- assert_equal 0 [r llen xlist]
- }
-
- foreach {type large} [array get largevalue] {
- test "LPUSHX, RPUSHX - $type" {
- create_list xlist "$large c"
- assert_equal 3 [r rpushx xlist d]
- assert_equal 4 [r lpushx xlist a]
- assert_equal 6 [r rpushx xlist 42 x]
- assert_equal 9 [r lpushx xlist y3 y2 y1]
- assert_equal "y1 y2 y3 a $large c d 42 x" [r lrange xlist 0 -1]
- }
-
- test "LINSERT - $type" {
- create_list xlist "a $large c d"
- assert_equal 5 [r linsert xlist before c zz] "before c"
- assert_equal "a $large zz c d" [r lrange xlist 0 10] "lrangeA"
- assert_equal 6 [r linsert xlist after c yy] "after c"
- assert_equal "a $large zz c yy d" [r lrange xlist 0 10] "lrangeB"
- assert_equal 7 [r linsert xlist after d dd] "after d"
- assert_equal -1 [r linsert xlist after bad ddd] "after bad"
- assert_equal "a $large zz c yy d dd" [r lrange xlist 0 10]
"lrangeC"
- assert_equal 8 [r linsert xlist before a aa] "before a"
- assert_equal -1 [r linsert xlist before bad aaa] "before bad"
- assert_equal "aa a $large zz c yy d dd" [r lrange xlist 0 10]
"lrangeD"
-
- # check inserting integer encoded value
- assert_equal 9 [r linsert xlist before aa 42] "before aa"
- assert_equal 42 [r lrange xlist 0 0] "lrangeE"
- }
- }
-
- test {LINSERT raise error on bad syntax} {
- catch {[r linsert xlist aft3r aa 42]} e
- set e
- } {*syntax*error*}
-
- foreach {type num} {quicklist 250 quicklist 500} {
- proc check_numbered_list_consistency {key} {
- set len [r llen $key]
- for {set i 0} {$i < $len} {incr i} {
- assert_equal $i [r lindex $key $i]
- assert_equal [expr $len-1-$i] [r lindex $key [expr (-$i)-1]]
- }
- }
-
- proc check_random_access_consistency {key} {
- set len [r llen $key]
- for {set i 0} {$i < $len} {incr i} {
- set rint [expr int(rand()*$len)]
- assert_equal $rint [r lindex $key $rint]
- assert_equal [expr $len-1-$rint] [r lindex $key [expr
(-$rint)-1]]
- }
- }
-
- test "LINDEX consistency test - $type" {
- r del mylist
- for {set i 0} {$i < $num} {incr i} {
- r rpush mylist $i
- }
- #assert_encoding $type mylist
- check_numbered_list_consistency mylist
- }
-
- test "LINDEX random access - $type" {
- #assert_encoding $type mylist
- check_random_access_consistency mylist
- }
-
- test "Check if list is still ok after a DEBUG RELOAD - $type" {
- #assert_encoding $type mylist
- check_numbered_list_consistency mylist
- check_random_access_consistency mylist
- }
- }
-
- test {LLEN against non-list value error} {
- r del mylist
- r set mylist foobar
- assert_error *WRONGTYPE* {r llen mylist}
- }
-
- test {LLEN against non existing key} {
- assert_equal 0 [r llen not-a-key]
- }
-
- test {LINDEX against non-list value error} {
- assert_error *WRONGTYPE* {r lindex mylist 0}
- }
-
- test {LINDEX against non existing key} {
- assert_equal "" [r lindex not-a-key 10]
- }
-
- test {LPUSH against non-list value error} {
- assert_error *WRONGTYPE* {r lpush mylist 0}
- }
-
- test {RPUSH against non-list value error} {
- assert_error *WRONGTYPE* {r rpush mylist 0}
- }
-
- foreach {type large} [array get largevalue] {
- test "RPOPLPUSH base case - $type" {
- r del mylist1 mylist2
- create_list mylist1 "a $large c d"
- assert_equal d [r rpoplpush mylist1 mylist2]
- assert_equal c [r rpoplpush mylist1 mylist2]
- assert_equal "a $large" [r lrange mylist1 0 -1]
- assert_equal "c d" [r lrange mylist2 0 -1]
- #assert_encoding quicklist mylist2
- }
-
- test "RPOPLPUSH with the same list as src and dst - $type" {
- create_list mylist "a $large c"
- assert_equal "a $large c" [r lrange mylist 0 -1]
- assert_equal c [r rpoplpush mylist mylist]
- assert_equal "c a $large" [r lrange mylist 0 -1]
- }
-
- foreach {othertype otherlarge} [array get largevalue] {
- test "RPOPLPUSH with $type source and existing target $othertype" {
- create_list srclist "a b c $large"
- create_list dstlist "$otherlarge"
- assert_equal $large [r rpoplpush srclist dstlist]
- assert_equal c [r rpoplpush srclist dstlist]
- assert_equal "a b" [r lrange srclist 0 -1]
- assert_equal "c $large $otherlarge" [r lrange dstlist 0 -1]
-
- # When we rpoplpush'ed a large value, dstlist should be
- # converted to the same encoding as srclist.
- if {$type eq "linkedlist"} {
- #assert_encoding quicklist dstlist
- }
- }
- }
- }
-
- test {RPOPLPUSH against non existing key} {
- r del srclist dstlist
- assert_equal {} [r rpoplpush srclist dstlist]
- assert_equal 0 [r exists srclist]
- assert_equal 0 [r exists dstlist]
- }
-
- test {RPOPLPUSH against non list src key} {
- r del srclist dstlist
- r set srclist x
- assert_error *WRONGTYPE* {r rpoplpush srclist dstlist}
- assert_type string srclist
- assert_equal 0 [r exists newlist]
- }
-
- test {RPOPLPUSH against non list dst key} {
- create_list srclist {a b c d}
- r set dstlist x
- assert_error *WRONGTYPE* {r rpoplpush srclist dstlist}
- assert_type string dstlist
- assert_equal {a b c d} [r lrange srclist 0 -1]
- }
-
- test {RPOPLPUSH against non existing src key} {
- r del srclist dstlist
- assert_equal {} [r rpoplpush srclist dstlist]
- } {}
-
- foreach {type large} [array get largevalue] {
- test "Basic LPOP/RPOP - $type" {
- create_list mylist "$large 1 2"
- assert_equal $large [r lpop mylist]
- assert_equal 2 [r rpop mylist]
- assert_equal 1 [r lpop mylist]
- assert_equal 0 [r llen mylist]
-
- # pop on empty list
- assert_equal {} [r lpop mylist]
- assert_equal {} [r rpop mylist]
- }
- }
-
- test {LPOP/RPOP against non list value} {
- r set notalist foo
- assert_error *WRONGTYPE* {r lpop notalist}
- assert_error *WRONGTYPE* {r rpop notalist}
- }
-
- test "LPOP/RPOP with wrong number of arguments" {
- assert_error {*wrong number of arguments*} {r lpop key 1 1}
- assert_error {*wrong number of arguments*} {r rpop key 2 2}
- }
-
- test {RPOP/LPOP with the optional count argument} {
- assert_equal 7 [r lpush listcount aa bb cc dd ee ff gg]
- assert_equal {gg} [r lpop listcount 1]
- assert_equal {ff ee} [r lpop listcount 2]
- assert_equal {aa bb} [r rpop listcount 2]
- assert_equal {cc} [r rpop listcount 1]
- assert_equal {dd} [r rpop listcount 123]
- assert_error "*ERR*range*" {r lpop forbarqaz -123}
- }
-
- test "LPOP/RPOP with the count 0 returns an empty array" {
- # Make sure we can distinguish between an empty array and a null
response
- r readraw 1
-
- r lpush listcount zero
- assert_equal {*0} [r lpop listcount 0]
- assert_equal {*0} [r rpop listcount 0]
-
- r readraw 0
- }
-
- test "LPOP/RPOP against non existing key" {
- r readraw 1
-
- r del non_existing_key
- assert_equal [r lpop non_existing_key] {$-1}
- assert_equal [r rpop non_existing_key] {$-1}
-
- r readraw 0
- }
-
- test "LPOP/RPOP with <count> against non existing key" {
- r readraw 1
-
- r del non_existing_key
-
- assert_equal [r lpop non_existing_key 0] {*-1}
- assert_equal [r lpop non_existing_key 1] {*-1}
-
- assert_equal [r rpop non_existing_key 0] {*-1}
- assert_equal [r rpop non_existing_key 1] {*-1}
-
- r readraw 0
- }
-
- foreach {type num} {quicklist 250 quicklist 500} {
- test "Mass RPOP/LPOP - $type" {
- r del mylist
- set sum1 0
- for {set i 0} {$i < $num} {incr i} {
- r lpush mylist $i
- incr sum1 $i
- }
- #assert_encoding $type mylist
- set sum2 0
- for {set i 0} {$i < [expr $num/2]} {incr i} {
- incr sum2 [r lpop mylist]
- incr sum2 [r rpop mylist]
- }
- assert_equal $sum1 $sum2
- }
- }
-
- foreach {type large} [array get largevalue] {
- test "LRANGE basics - $type" {
- create_list mylist "$large 1 2 3 4 5 6 7 8 9"
- assert_equal {1 2 3 4 5 6 7 8} [r lrange mylist 1 -2]
- assert_equal {7 8 9} [r lrange mylist -3 -1]
- assert_equal {4} [r lrange mylist 4 4]
- }
-
- test "LRANGE inverted indexes - $type" {
- create_list mylist "$large 1 2 3 4 5 6 7 8 9"
- assert_equal {} [r lrange mylist 6 2]
- }
-
- test "LRANGE out of range indexes including the full list - $type" {
- create_list mylist "$large 1 2 3"
- assert_equal "$large 1 2 3" [r lrange mylist -1000 1000]
- }
-
- test "LRANGE out of range negative end index - $type" {
- create_list mylist "$large 1 2 3"
- assert_equal $large [r lrange mylist 0 -4]
- assert_equal {} [r lrange mylist 0 -5]
- }
- }
-
- test {LRANGE against non existing key} {
- assert_equal {} [r lrange nosuchkey 0 1]
- }
-
- foreach {type large} [array get largevalue] {
- proc trim_list {type min max} {
- upvar 1 large large
- r del mylist
- create_list mylist "1 2 3 4 $large"
- r ltrim mylist $min $max
- r lrange mylist 0 -1
- }
-
- test "LTRIM basics - $type" {
- assert_equal "1" [trim_list $type 0 0]
- assert_equal "1 2" [trim_list $type 0 1]
- assert_equal "1 2 3" [trim_list $type 0 2]
- assert_equal "2 3" [trim_list $type 1 2]
- assert_equal "2 3 4 $large" [trim_list $type 1 -1]
- assert_equal "2 3 4" [trim_list $type 1 -2]
- assert_equal "4 $large" [trim_list $type -2 -1]
- assert_equal "$large" [trim_list $type -1 -1]
- assert_equal "1 2 3 4 $large" [trim_list $type -5 -1]
- assert_equal "1 2 3 4 $large" [trim_list $type -10 10]
- assert_equal "1 2 3 4 $large" [trim_list $type 0 5]
- assert_equal "1 2 3 4 $large" [trim_list $type 0 10]
- }
-
- test "LTRIM out of range negative end index - $type" {
- assert_equal {1} [trim_list $type 0 -5]
- assert_equal {} [trim_list $type 0 -6]
- }
-
- test "LTRIM lrem elements after ltrim list - $type" {
- create_list myotherlist "0 1 2 3 4 3 6 7 3 9"
- assert_equal "OK" [r ltrim myotherlist 2 -3]
- assert_equal "2 3 4 3 6 7" [r lrange myotherlist 0 -1]
- assert_equal 2 [r lrem myotherlist 4 3]
- assert_equal "2 4 6 7" [r lrange myotherlist 0 -1]
- }
-
- test "LTRIM linsert elements after ltrim list - $type" {
- create_list myotherlist1 "0 1 2 3 4 3 6 7 3 9"
- assert_equal "OK" [r ltrim myotherlist1 2 -3]
- assert_equal "2 3 4 3 6 7" [r lrange myotherlist1 0 -1]
- assert_equal -1 [r linsert myotherlist1 before 9 0]
- assert_equal 7 [r linsert myotherlist1 before 4 0]
- assert_equal "2 3 0 4 3 6 7" [r lrange myotherlist1 0 -1]
- }
- }
-
- foreach {type large} [array get largevalue] {
- test "LSET - $type" {
- create_list mylist "99 98 $large 96 95"
- r lset mylist 1 foo
- r lset mylist -1 bar
- assert_equal "99 foo $large 96 bar" [r lrange mylist 0 -1]
- }
-
- test "LSET out of range index - $type" {
- assert_error ERR*range* {r lset mylist 10 foo}
- }
- }
-
- test {LSET against non existing key} {
- assert_error ERR*NotFound* {r lset nosuchkey 10 foo}
- }
-
- test {LSET against non list value} {
- r set nolist foobar
- assert_error *WRONGTYPE* {r lset nolist 0 foo}
- }
-
- foreach {type e} [array get largevalue] {
- test "LREM remove all the occurrences - $type" {
- create_list mylist "$e foo bar foobar foobared zap bar test foo"
- assert_equal 2 [r lrem mylist 0 bar]
- assert_equal "$e foo foobar foobared zap test foo" [r lrange
mylist 0 -1]
- }
-
- test "LREM remove the first occurrence - $type" {
- assert_equal 1 [r lrem mylist 1 foo]
- assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0
-1]
- }
-
- test "LREM remove non existing element - $type" {
- assert_equal 0 [r lrem mylist 1 nosuchelement]
- assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0
-1]
- }
-
- test "LREM starting from tail with negative count - $type" {
- create_list mylist "$e foo bar foobar foobared zap bar test foo
foo"
- assert_equal 1 [r lrem mylist -1 bar]
- assert_equal "$e foo bar foobar foobared zap test foo foo" [r
lrange mylist 0 -1]
- }
-
- test "LREM starting from tail with negative count (2) - $type" {
- assert_equal 2 [r lrem mylist -2 foo]
- assert_equal "$e foo bar foobar foobared zap test" [r lrange
mylist 0 -1]
- }
-
- test "LREM deleting objects that may be int encoded - $type" {
- create_list myotherlist "$e 1 2 3"
- assert_equal 1 [r lrem myotherlist 1 2]
- assert_equal 3 [r llen myotherlist]
- }
-
- test "LREM remove elements in repeating list - $type" {
- create_list myotherlist1 "$e a b c d e f a f a f"
- assert_equal 1 [r lrem myotherlist1 1 f]
- assert_equal "$e a b c d e a f a f" [r lrange myotherlist1 0 -1]
- assert_equal 2 [r lrem myotherlist1 0 f]
- assert_equal "$e a b c d e a a" [r lrange myotherlist1 0 -1]
- }
- }
-
- # test "Regression for bug 593 - chaining BRPOPLPUSH with other blocking
cmds" {
- # set rd1 [redis_deferring_client]
- # set rd2 [redis_deferring_client]
-
- # $rd1 brpoplpush a b 0
- # $rd1 brpoplpush a b 0
- # $rd2 brpoplpush b c 0
- # after 1000
- # r lpush a data
- # $rd1 close
- # $rd2 close
- # r ping
- # } {PONG}
-
- test {Test LMOVE on different keys} {
- r RPUSH list1{t} "1"
- r RPUSH list1{t} "2"
- r RPUSH list1{t} "3"
- r RPUSH list1{t} "4"
- r RPUSH list1{t} "5"
-
- r LMOVE list1{t} list2{t} RIGHT LEFT
- r LMOVE list1{t} list2{t} LEFT RIGHT
- assert_equal [r llen list1{t}] 3
- assert_equal [r llen list2{t}] 2
- assert_equal [r lrange list1{t} 0 -1] {2 3 4}
- assert_equal [r lrange list2{t} 0 -1] {5 1}
- }
-
- foreach from {LEFT RIGHT} {
- foreach to {LEFT RIGHT} {
- test "LMOVE $from $to on the list node" {
- r del target_key{t}
- r rpush target_key{t} 1
-
- set rd [redis_deferring_client]
- create_list list{t} "a b c d"
- $rd lmove list{t} target_key{t} $from $to
- set elem [$rd read]
-
- if {$from eq "RIGHT"} {
- assert_equal d $elem
- assert_equal "a b c" [r lrange list{t} 0 -1]
- } else {
- assert_equal a $elem
- assert_equal "b c d" [r lrange list{t} 0 -1]
- }
- if {$to eq "RIGHT"} {
- assert_equal $elem [r rpop target_key{t}]
- } else {
- assert_equal $elem [r lpop target_key{t}]
- }
-
- $rd close
- }
- }
- }
-}