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 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 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 TestEncodeHash(t *testing.T) { docheck := func(m map[string]string) { p, err := EncodeDump(toHash(m)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) checkHash(t, o, m) } docheck(map[string]string{"": ""}) docheck(map[string]string{"": "", "a": "", "b": "a", "c": "b", "d": "c"}) hash := make(map[string]string) for i := 0; i < 65536; i++ { hash[strconv.Itoa(i)] = strconv.Itoa(i + 1) } docheck(hash) }
func TestEncodeList(t *testing.T) { docheck := func(list ...string) { p, err := EncodeDump(toList(list...)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) checkList(t, o, list) } docheck("") docheck("", "a", "b", "c", "d", "e") list := []string{} for i := 0; i < 65536; i++ { list = append(list, strconv.Itoa(i)) } docheck(list...) }
func TestEncodeSet(t *testing.T) { docheck := func(set ...string) { p, err := EncodeDump(toSet(set...)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) checkSet(t, o, set) } docheck("") docheck("", "a", "b", "c") set := []string{} for i := 0; i < 65536; i++ { set = append(set, strconv.Itoa(i)) } docheck(set...) }
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 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()) }
func TestEncodeString(t *testing.T) { docheck := func(text string) { p, err := EncodeDump(toString(text)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) checkString(t, o, text) } docheck("hello world!!") docheck("2147483648") docheck("4294967296") docheck("") var b bytes.Buffer for i := 0; i < 1024; i++ { b.Write([]byte("01")) } docheck(b.String()) }
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 TestEncodeZSet(t *testing.T) { docheck := func(m map[string]float64) { p, err := EncodeDump(toZSet(m)) assert.ErrorIsNil(t, err) o, err := DecodeDump(p) assert.ErrorIsNil(t, err) checkZSet(t, o, m) } docheck(map[string]float64{"": 0}) zset := make(map[string]float64) for i := -65535; i < 65536; i++ { zset[strconv.Itoa(i)] = float64(i) } docheck(zset) zset["inf"] = math.Inf(1) zset["-inf"] = math.Inf(-1) zset["nan"] = math.NaN() docheck(zset) }
func delayClose(t *testing.T, closer Closer, c chan int, u pipeTest) { time.Sleep(time.Millisecond * 100) var err error if u.witherr { err = closer.CloseWithError(u.err) } else { err = closer.Close() } assert.ErrorIsNil(t, err) c <- 0 }
func openPipe(t *testing.T, fileName string) (Reader, Writer) { buffSize := bytesize.KB * 8 fileSize := bytesize.MB * 32 if fileName == "" { return PipeSize(buffSize) } else { f, err := OpenFile(fileName, false) assert.ErrorIsNil(t, err) return PipeFile(buffSize, fileSize, f) } }
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()) }
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 }
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"))) }
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()) }
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) } }
func TestDecoder(t *testing.T) { test := []string{ "$6\r\nfoobar\r\n", "$0\r\n\r\n", "$-1\r\n", "*0\r\n", "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n", "*3\r\n:1\r\n:2\r\n:3\r\n", "*-1\r\n", "+OK\r\n", "-Error message\r\n", "*2\r\n$1\r\n0\r\n*0\r\n", "*3\r\n$4\r\nEVAL\r\n$31\r\nreturn {1,2,{3,'Hello World!'}}\r\n$1\r\n0\r\n", "\n", } for _, s := range test { _, err := DecodeFromBytes([]byte(s)) assert.ErrorIsNil(t, err) } }
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 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 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()) }
func TestEncodeRdb(t *testing.T) { objs := make([]struct { db uint32 expireat uint64 key []byte obj interface{} typ string }, 128) var b bytes.Buffer enc := NewEncoder(&b) assert.ErrorIsNil(t, enc.EncodeHeader()) for i := 0; i < len(objs); i++ { db := uint32(i + 32) expireat := uint64(i) key := []byte(strconv.Itoa(i)) var obj interface{} var typ string switch i % 5 { case 0: s := strconv.Itoa(i) obj = s typ = "string" assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toString(s))) case 1: list := []string{} for j := 0; j < 32; j++ { list = append(list, fmt.Sprintf("l%d_%d", i, rand.Int())) } obj = list typ = "list" assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toList(list...))) case 2: hash := make(map[string]string) for j := 0; j < 32; j++ { hash[strconv.Itoa(j)] = fmt.Sprintf("h%d_%d", i, rand.Int()) } obj = hash typ = "hash" assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toHash(hash))) case 3: zset := make(map[string]float64) for j := 0; j < 32; j++ { zset[strconv.Itoa(j)] = rand.Float64() } obj = zset typ = "zset" assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toZSet(zset))) case 4: set := []string{} for j := 0; j < 32; j++ { set = append(set, fmt.Sprintf("s%d_%d", i, rand.Int())) } obj = set typ = "set" assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toSet(set...))) } objs[i].db = db objs[i].expireat = expireat objs[i].key = key objs[i].obj = obj objs[i].typ = typ } assert.ErrorIsNil(t, enc.EncodeFooter()) rdb := b.Bytes() var c atomic2.Int64 l := NewLoader(ioutils.NewCountReader(bytes.NewReader(rdb), &c)) assert.ErrorIsNil(t, l.Header()) var i int = 0 for { e, err := l.NextBinEntry() assert.ErrorIsNil(t, err) if e == nil { break } assert.Must(t, objs[i].db == e.DB) assert.Must(t, objs[i].expireat == e.ExpireAt) assert.Must(t, bytes.Equal(objs[i].key, e.Key)) o, err := DecodeDump(e.Value) assert.ErrorIsNil(t, err) switch objs[i].typ { case "string": checkString(t, o, objs[i].obj.(string)) case "list": checkList(t, o, objs[i].obj.([]string)) case "hash": checkHash(t, o, objs[i].obj.(map[string]string)) case "zset": checkZSet(t, o, objs[i].obj.(map[string]float64)) case "set": checkSet(t, o, objs[i].obj.([]string)) } i++ } assert.Must(t, i == len(objs)) assert.ErrorIsNil(t, l.Footer()) assert.Must(t, c.Get() == int64(len(rdb))) }
func testEncodeAndCheck(t *testing.T, resp Resp, expect []byte) { b, err := EncodeToBytes(resp) assert.ErrorIsNil(t, err) assert.Must(t, bytes.Equal(b, expect)) }