func TestItos(t *testing.T) { for i := 0; i < len(imap)*2; i++ { n, p := -i, i assert.Must(t, strconv.Itoa(n) == itos(int64(n))) assert.Must(t, strconv.Itoa(p) == itos(int64(p))) } }
func testPipe2(t *testing.T, fileName string) { r, w := openPipe(t, fileName) c := 1024 * 128 s := "Hello world!!" go func() { for i := 0; i < c; i++ { m := fmt.Sprintf("[%d]%s ", i, s) _, err := ioutils.WriteFull(w, []byte(m)) assert.ErrorIsNil(t, err) } assert.ErrorIsNil(t, w.Close()) }() time.Sleep(time.Millisecond * 100) buf := make([]byte, len(s)*c*2) n, err := ioutils.ReadFull(r, buf) assert.Must(t, errors.Equal(err, io.EOF)) buf = buf[:n] for i := 0; i < c; i++ { m := fmt.Sprintf("[%d]%s ", i, s) assert.Must(t, len(buf) >= len(m)) assert.Must(t, string(buf[:len(m)]) == m) buf = buf[len(m):] } assert.Must(t, len(buf) == 0) assert.ErrorIsNil(t, r.Close()) }
func checkList(t *testing.T, o interface{}, list []string) { x, ok := o.(List) assert.Must(t, ok) assert.Must(t, len(x) == len(list)) for i, e := range x { assert.Must(t, string(e) == list[i]) } }
func checkHash(t *testing.T, o interface{}, m map[string]string) { x, ok := o.(Hash) assert.Must(t, ok) assert.Must(t, len(x) == len(m)) for _, e := range x { assert.Must(t, m[string(e.Field)] == string(e.Value)) } }
func checkSet(t *testing.T, o interface{}, set []string) { x, ok := o.(Set) assert.Must(t, ok) assert.Must(t, len(x) == len(set)) for i, e := range x { assert.Must(t, string(e) == set[i]) } }
func TestBytesizeError(t *testing.T) { var err error _, err = Parse("--1") assert.Must(t, errors.Equal(err, ErrBadBytesize)) _, err = Parse("hello world") assert.Must(t, errors.Equal(err, ErrBadBytesize)) _, err = Parse("123.132.32") assert.Must(t, errors.Equal(err, ErrBadBytesize)) }
/* #!/bin/bash for ((i=0;i<32;i++)); do ./redis-cli rpush list $i done ./redis-cli dump list */ func TestDecodeList(t *testing.T) { s := ` 0120c000c001c002c003c004c005c006c007c008c009c00ac00bc00cc00dc00e c00fc010c011c012c013c014c015c016c017c018c019c01ac01bc01cc01dc01e c01f0600e87781cbebc997f5 ` val := hexStringToObject(t, s).(List) assert.Must(t, len(val) == 32) for i := 0; i < len(val); i++ { assert.Must(t, string(val[i]) == strconv.Itoa(i)) } }
/* #!/bin/bash for ((i=0;i<32;i++)); do ./redis-cli rpush list $i done ./redis-cli dump list */ func TestDecodeListZipmap(t *testing.T) { s := ` 0a405e5e0000005a000000200000f102f202f302f402f502f602f702f802f902 fa02fb02fc02fd02fe0d03fe0e03fe0f03fe1003fe1103fe1203fe1303fe1403 fe1503fe1603fe1703fe1803fe1903fe1a03fe1b03fe1c03fe1d03fe1e03fe1f ff060052f7f617938b332a ` val := hexStringToObject(t, s).(List) assert.Must(t, len(val) == 32) for i := 0; i < len(val); i++ { assert.Must(t, string(val[i]) == strconv.Itoa(i)) } }
func TestPipeReadClose2(t *testing.T) { r, w := Pipe() c := make(chan int, 1) go delayClose(t, r, c, pipeTest{}) n, err := r.Read(make([]byte, 64)) <-c assert.Must(t, errors.Equal(err, io.ErrClosedPipe)) assert.Must(t, n == 0) assert.ErrorIsNil(t, w.Close()) }
/* #!/bin/bash ./redis-cli flushall for ((i=0;i<32;i++)); do ./redis-cli rpush list ${i} done ./redis-cli save && xxd -p -c 32 dump.rdb */ func TestLoadList(t *testing.T) { s := ` 524544495330303036fe0001046c69737420c000c001c002c003c004c005c006 c007c008c009c00ac00bc00cc00dc00ec00fc010c011c012c013c014c015c016 c017c018c019c01ac01bc01cc01dc01ec01fff756ea1fa90adefe3 ` entries := DecodeHexRdb(t, s, 1) _, obj := getobj(t, entries, "list") val := obj.(List) assert.Must(t, len(val) == 32) for i := 0; i < 32; i++ { assert.Must(t, string(val[i]) == strconv.Itoa(i)) } }
func TestWriteNil(t *testing.T) { r, w := Pipe() go func() { _, err := w.Write(nil) assert.ErrorIsNil(t, err) assert.ErrorIsNil(t, w.Close()) }() buf := make([]byte, 4096) n, err := ioutils.ReadFull(r, buf) assert.Must(t, errors.Equal(err, io.EOF)) assert.Must(t, n == 0) assert.ErrorIsNil(t, r.Close()) }
func getobj(t *testing.T, entries map[string]*BinEntry, key string) (*BinEntry, interface{}) { e := entries[key] assert.Must(t, e != nil) o, err := DecodeDump(e.Value) assert.ErrorIsNil(t, err) return e, o }
func TestDecodeInvalidRequests(t *testing.T) { test := []string{ "", "*hello\r\n", "*-100\r\n", "*3\r\nhi", "*3\r\nhi\r\n", "*4\r\n$1", "*4\r\n$1\r", "*4\r\n$1\n", "*2\r\n$3\r\nget\r\n$what?\r\nx\r\n", "*4\r\n$3\r\nget\r\n$1\r\nx\r\n", "*2\r\n$3\r\nget\r\n$1\r\nx", "*2\r\n$3\r\nget\r\n$1\r\nx\r", "*2\r\n$3\r\nget\r\n$100\r\nx\r\n", "$6\r\nfoobar\r", "$0\rn\r\n", "$-1\n", "*0", "*2n$3\r\nfoo\r\n$3\r\nbar\r\n", "3\r\n:1\r\n:2\r\n:3\r\n", "*-\r\n", "+OK\n", "-Error message\r", } for _, s := range test { _, err := DecodeFromBytes([]byte(s)) assert.Must(t, err != nil) } }
/* #!/bin/bash ./redis-cli flushall ./redis-cli set string_ttls string_ttls ./redis-cli expireat string_ttls 1500000000 ./redis-cli set string_ttlms string_ttlms ./redis-cli pexpireat string_ttlms 1500000000000 ./redis-cli save && xxd -p -c 32 dump.rdb */ func TestLoadStringTTL(t *testing.T) { s := ` 524544495330303036fe00fc0098f73e5d010000000c737472696e675f74746c 6d730c737472696e675f74746c6d73fc0098f73e5d010000000b737472696e67 5f74746c730b737472696e675f74746c73ffd15acd935a3fe949 ` expireat := uint64(1500000000000) entries := DecodeHexRdb(t, s, 2) keys := []string{"string_ttls", "string_ttlms"} for _, key := range keys { e, obj := getobj(t, entries, key) val := obj.(String) assert.Must(t, bytes.Equal([]byte(val), []byte(key))) assert.Must(t, e.ExpireAt == expireat) } }
func hexStringToObject(t *testing.T, s string) interface{} { p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) assert.Must(t, o != nil) return o }
func testPipe1(t *testing.T, fileName string) { r, w := openPipe(t, fileName) s := "Hello world!!" go func(data []byte) { _, err := ioutils.WriteFull(w, data) assert.ErrorIsNil(t, err) assert.ErrorIsNil(t, w.Close()) }([]byte(s)) buf := make([]byte, 64) n, err := ioutils.ReadFull(r, buf) assert.Must(t, errors.Equal(err, io.EOF)) assert.Must(t, n == len(s)) assert.Must(t, string(buf[:n]) == s) assert.ErrorIsNil(t, r.Close()) }
/* #!/bin/bash for ((i=0;i<32;i++)); do ./redis-cli sadd set $i done ./redis-cli dump set */ func TestDecodeSet(t *testing.T) { s := ` 0220c016c00dc01bc012c01ac004c014c002c017c01dc01cc013c019c01ec008 c006c000c001c007c00fc009c01fc00ec003c00ac015c010c00bc018c011c00c c00506007bd0a89270890016 ` val := hexStringToObject(t, s).(Set) assert.Must(t, len(val) == 32) set := make(map[string]bool) for _, mem := range val { set[string(mem)] = true } assert.Must(t, len(val) == len(set)) for i := 0; i < 32; i++ { _, ok := set[strconv.Itoa(i)] assert.Must(t, ok) } }
/* #!/bin/bash ./redis-cli flushall for ((i=0;i<256;i++)); do ./redis-cli rpush list_lzf 0 ./redis-cli rpush list_lzf 1 done ./redis-cli save && xxd -p -c 32 dump.rdb */ func TestLoadListZipmap(t *testing.T) { s := ` 524544495330303036fe000a086c6973745f6c7a66c31f440b040b0400000820 0306000200f102f202e0ff03e1ff07e1ff07e1d90701f2ffff6a1c2d51c02301 16 ` entries := DecodeHexRdb(t, s, 1) _, obj := getobj(t, entries, "list_lzf") val := obj.(List) assert.Must(t, len(val) == 512) for i := 0; i < 256; i++ { var s string = "0" if i%2 != 0 { s = "1" } assert.Must(t, string(val[i]) == s) } }
func testPipe3(t *testing.T, fileName string) { r, w := openPipe(t, fileName) c := make(chan int) size := 4096 go func() { buf := make([]byte, size) for { n, err := r.Read(buf) if errors.Equal(err, io.EOF) { break } assert.ErrorIsNil(t, err) c <- n } assert.ErrorIsNil(t, r.Close()) c <- 0 }() go func() { buf := make([]byte, size) for i := 1; i < size; i++ { n, err := ioutils.WriteFull(w, buf[:i]) assert.ErrorIsNil(t, err) assert.Must(t, n == i) } assert.ErrorIsNil(t, w.Close()) }() sum := 0 for i := 1; i < size; i++ { sum += i } for { n := <-c if n == 0 { break } sum -= n } assert.Must(t, sum == 0) }
func testPipe4(t *testing.T, fileName string) { r, w := openPipe(t, fileName) key := []byte("spinlock aes-128") block := aes.BlockSize count := 1024 * 1024 * 128 / block go func() { buf := make([]byte, count*block) m, err := aes.NewCipher(key) assert.ErrorIsNil(t, err) for i := 0; i < len(buf); i++ { buf[i] = byte(i) } e := cipher.NewCBCEncrypter(m, make([]byte, block)) e.CryptBlocks(buf, buf) n, err := ioutils.WriteFull(w, buf) assert.ErrorIsNil(t, err) assert.ErrorIsNil(t, w.Close()) assert.Must(t, n == len(buf)) }() buf := make([]byte, count*block) m, err := aes.NewCipher(key) assert.ErrorIsNil(t, err) _, err = ioutils.ReadFull(r, buf) assert.ErrorIsNil(t, err) e := cipher.NewCBCDecrypter(m, make([]byte, block)) e.CryptBlocks(buf, buf) for i := 0; i < len(buf); i++ { assert.Must(t, buf[i] == byte(i)) } _, err = ioutils.ReadFull(r, buf) assert.Must(t, errors.Equal(err, io.EOF)) assert.ErrorIsNil(t, r.Close()) }
/* #!/bin/bash for ((i=0;i<32;i++)); do let j="$i*$i" ./redis-cli hset hash $i $j done ./redis-cli dump hash */ func TestDecodeHash(t *testing.T) { s := ` 0420c016c1e401c00dc1a900c01bc1d902c012c14401c01ac1a402c004c010c0 02c004c014c19001c017c11102c01dc14903c01cc11003c013c16901c019c171 02c01ec18403c008c040c006c024c000c000c001c001c007c031c009c051c00f c1e100c01fc1c103c00ec1c400c003c009c00ac064c015c1b901c010c10001c0 0bc079c018c14002c011c12101c00cc19000c005c019060072320e870e10799d ` val := hexStringToObject(t, s).(Hash) assert.Must(t, len(val) == 32) hash := make(map[string]string) for _, ent := range val { hash[string(ent.Field)] = string(ent.Value) } assert.Must(t, len(val) == len(hash)) for i := 0; i < 32; i++ { s := strconv.Itoa(i) assert.Must(t, hash[s] == strconv.Itoa(i*i)) } }
func TestPipeWriteClose(t *testing.T) { for _, u := range pipeTests { r, w := Pipe() c := make(chan int, 1) if u.async { go delayClose(t, r, c, u) } else { delayClose(t, r, c, u) } <-c n, err := ioutils.WriteFull(w, []byte("hello, world")) expect := u.err if expect == nil { expect = io.ErrClosedPipe } assert.Must(t, errors.Equal(err, expect)) assert.Must(t, n == 0) assert.ErrorIsNil(t, w.Close()) } }
func DecodeHexRdb(t *testing.T, s string, n int) map[string]*BinEntry { p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s)) assert.ErrorIsNil(t, err) r := bytes.NewReader(p) l := NewLoader(r) assert.ErrorIsNil(t, l.Header()) entries := make(map[string]*BinEntry) var i int = 0 for { e, err := l.NextBinEntry() assert.ErrorIsNil(t, err) if e == nil { break } assert.Must(t, e.DB == 0) entries[string(e.Key)] = e i++ } assert.ErrorIsNil(t, l.Footer()) assert.Must(t, r.Len() == 0) assert.Must(t, len(entries) == i && i == n) return entries }
/* #!/bin/bash for ((i=0;i<32;i++)); do ./redis-cli zadd zset -$i $i done ./redis-cli dump zset */ func TestDecodeZSet(t *testing.T) { s := ` 0320c016032d3232c00d032d3133c01b032d3237c012032d3138c01a032d3236 c004022d34c014032d3230c002022d32c017032d3233c01d032d3239c01c032d 3238c013032d3139c019032d3235c01e032d3330c008022d38c006022d36c000 0130c001022d31c007022d37c009022d39c00f032d3135c01f032d3331c00e03 2d3134c003022d33c00a032d3130c015032d3231c010032d3136c00b032d3131 c018032d3234c011032d3137c00c032d3132c005022d35060046177397f6688b 16 ` val := hexStringToObject(t, s).(ZSet) assert.Must(t, len(val) == 32) zset := make(map[string]float64) for _, ent := range val { zset[string(ent.Member)] = ent.Score } assert.Must(t, len(val) == len(zset)) for i := 0; i < 32; i++ { s := strconv.Itoa(i) score, ok := zset[s] assert.Must(t, ok) assert.Must(t, math.Abs(score+float64(i)) < 1e-10) } }
func TestPipeReadClose(t *testing.T) { for _, u := range pipeTests { r, w := Pipe() c := make(chan int, 1) if u.async { go delayClose(t, w, c, u) } else { delayClose(t, w, c, u) } buf := make([]byte, 64) n, err := r.Read(buf) <-c expect := u.err if expect == nil { expect = io.EOF } assert.Must(t, errors.Equal(err, expect)) assert.Must(t, n == 0) assert.ErrorIsNil(t, r.Close()) } }
func TestWriteAfterWriterClose(t *testing.T) { r, w := Pipe() s := "hello" errs := make(chan error) go func() { _, err := ioutils.WriteFull(w, []byte(s)) assert.ErrorIsNil(t, err) assert.ErrorIsNil(t, w.Close()) _, err = w.Write([]byte("world")) errs <- err }() buf := make([]byte, 4096) n, err := ioutils.ReadFull(r, buf) assert.Must(t, errors.Equal(err, io.EOF)) assert.Must(t, string(buf[:n]) == s) err = <-errs assert.Must(t, errors.Equal(err, io.ErrClosedPipe)) assert.ErrorIsNil(t, r.Close()) }
/* #!/bin/bash ./redis-cli flushall for ((i=0;i<16;i++)); do ./redis-cli zadd zset1 ${i} ${i} done for ((i=0;i<32;i++)); do ./redis-cli zadd zset2 -${i} ${i} done ./redis-cli save && xxd -p -c 32 dump.rdb */ func TestLoadZSetAndZSetZiplist(t *testing.T) { s := ` 524544495330303036fe0003057a7365743220c016032d3232c00d032d3133c0 1b032d3237c012032d3138c01a032d3236c004022d34c014032d3230c002022d 32c017032d3233c01d032d3239c01c032d3238c013032d3139c019032d3235c0 1e032d3330c008022d38c006022d36c000022d30c001022d31c007022d37c009 022d39c00f032d3135c01f032d3331c00e032d3134c003022d33c00a032d3130 c015032d3231c010032d3136c00b032d3131c018032d3234c011032d3137c00c 032d3132c005022d350c057a736574314051510000004d000000200000f102f1 02f202f202f302f302f402f402f502f502f602f602f702f702f802f802f902f9 02fa02fa02fb02fb02fc02fc02fd02fd02fe0d03fe0d03fe0e03fe0e03fe0f03 fe0fffff2addedbf4f5a8f93 ` entries := DecodeHexRdb(t, s, 2) _, obj1 := getobj(t, entries, "zset1") val1 := obj1.(ZSet) zset1 := make(map[string]float64) for _, ent := range val1 { zset1[string(ent.Member)] = ent.Score } assert.Must(t, len(zset1) == 16) assert.Must(t, len(zset1) == len(val1)) for i := 0; i < 16; i++ { s := strconv.Itoa(i) score, ok := zset1[s] assert.Must(t, ok) assert.Must(t, math.Abs(score-float64(i)) < 1e-10) } _, obj2 := getobj(t, entries, "zset2") val2 := obj2.(ZSet) zset2 := make(map[string]float64) for _, ent := range val2 { zset2[string(ent.Member)] = ent.Score } assert.Must(t, len(zset2) == 32) assert.Must(t, len(zset2) == len(val2)) for i := 0; i < 32; i++ { s := strconv.Itoa(i) score, ok := zset2[s] assert.Must(t, ok) assert.Must(t, math.Abs(score+float64(i)) < 1e-10) } }
func TestDecodeBulkBytes(t *testing.T) { test := "*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n" resp, err := DecodeFromBytes([]byte(test)) assert.ErrorIsNil(t, err) x, ok := resp.(*Array) assert.Must(t, ok) assert.Must(t, len(x.Value) == 2) s1, ok := x.Value[0].(*BulkBytes) assert.Must(t, ok) assert.Must(t, bytes.Equal(s1.Value, []byte("LLEN"))) s2, ok := x.Value[1].(*BulkBytes) assert.Must(t, ok) assert.Must(t, bytes.Equal(s2.Value, []byte("mylist"))) }
/* #!/bin/bash ./redis-cli flushall for i in 1 255 256 65535 65536 2147483647 2147483648 4294967295 4294967296 -2147483648; do ./redis-cli set string_${i} ${i} done ./redis-cli save && xxd -p -c 32 dump.rdb */ func TestLoadIntString(t *testing.T) { s := ` 524544495330303036fe00000a737472696e675f323535c1ff00000873747269 6e675f31c0010011737472696e675f343239343936373239360a343239343936 373239360011737472696e675f343239343936373239350a3432393439363732 39350012737472696e675f2d32313437343833363438c200000080000c737472 696e675f3635353335c2ffff00000011737472696e675f323134373438333634 380a32313437343833363438000c737472696e675f3635353336c20000010000 0a737472696e675f323536c100010011737472696e675f323134373438333634 37c2ffffff7fffe49d9f131fb5c3b5 ` values := []int{1, 255, 256, 65535, 65536, 2147483647, 2147483648, 4294967295, 4294967296, -2147483648} entries := DecodeHexRdb(t, s, len(values)) for _, value := range values { key := fmt.Sprintf("string_%d", value) _, obj := getobj(t, entries, key) val := obj.(String) assert.Must(t, bytes.Equal([]byte(val), []byte(strconv.Itoa(value)))) } }
func TestDecodeRequest(t *testing.T) { test := []string{ "PING\r\n", "ECHO abc\r\n", "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n", "\n", } for _, s := range test { _, err := DecodeRequestFromBytes([]byte(s)) assert.ErrorIsNil(t, err) } invalidTest := []string{ "+OK\r\n", } for _, s := range invalidTest { _, err := DecodeRequestFromBytes([]byte(s)) assert.Must(t, err != nil) } }