func TestWriteAfterWriterClose(t *testing.T) { r, w := New() s := "hello" errs := make(chan error) go func() { n, err := w.Write([]byte(s)) assert.MustNoError(err) assert.Must(n == len(s)) assert.MustNoError(w.Close()) _, err = w.Write([]byte("world")) errs <- err }() buf := make([]byte, 4096) n, err := io.ReadFull(r, buf) assert.Must(errors.Equal(err, io.EOF)) assert.Must(string(buf[:n]) == s) err = <-errs assert.Must(errors.Equal(err, io.ErrClosedPipe)) assert.MustNoError(r.Close()) }
func testPipe2(t *testing.T, fileName string) { r, w, f := openPipe(t, fileName) defer f.Close() c := 1024 * 128 s := "Hello world!!" go func() { for i := 0; i < c; i++ { m := fmt.Sprintf("[%d]%s ", i, s) n, err := w.Write([]byte(m)) assert.MustNoError(err) assert.Must(n == len(m)) } assert.MustNoError(w.Close()) }() time.Sleep(time.Millisecond * 10) buf := make([]byte, len(s)*c*2) n, err := io.ReadFull(r, buf) assert.Must(errors.Equal(err, io.EOF)) buf = buf[:n] for i := 0; i < c; i++ { m := fmt.Sprintf("[%d]%s ", i, s) assert.Must(len(buf) >= len(m)) assert.Must(string(buf[:len(m)]) == m) buf = buf[len(m):] } assert.Must(len(buf) == 0) assert.MustNoError(r.Close()) }
func hexStringToObject(t *testing.T, s string) interface{} { p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s)) assert.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(err) assert.Must(o != nil) return o }
func TestServerServe(t *testing.T) { h := &testHandler{make(map[string]int)} s, err := NewServer(h) assert.MustNoError(err) resp, err := Decode(bufio.NewReader(bytes.NewReader([]byte("*2\r\n$3\r\nset\r\n$3\r\nfoo\r\n")))) assert.MustNoError(err) _, err = s.Dispatch(nil, resp) assert.MustNoError(err) testmapcount(t, h.c, map[string]int{"foo": 1}) }
func TestDecodeSimpleRequest1(t *testing.T) { resp, err := DecodeFromBytes([]byte("\r\n")) assert.MustNoError(err) x, ok := resp.(*Array) assert.Must(ok) assert.Must(len(x.Value) == 0) }
func TestEncodeHash(t *testing.T) { docheck := func(m map[string]string) { p, err := EncodeDump(toHash(m)) assert.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(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.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(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.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(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(e != nil) o, err := DecodeDump(e.Value) assert.MustNoError(err) return e, o }
func testBacklog(t *testing.T, bl *Backlog, size int) { input := randSlice(32) r1, err := bl.NewReader() assert.MustNoError(err) checkWriter(bl, input) checkReader(r1, input) checkReader(r1, []byte{}) input = randSlice(size) checkWriter(bl, input) checkReader(r1, input) checkWriter(bl, randSlice(size)) assert.Must(r1.IsValid() == true) r2, err := bl.NewReader() assert.MustNoError(err) input = []byte{0xde, 0xad, 0xbe, 0xef} checkWriter(bl, input) assert.Must(r1.IsValid() == false) _, err = r1.Read([]byte{0}) assert.Must(errors.Equal(err, ErrInvalidOffset)) b := make([]byte, len(input)) n, err := io.ReadFull(r2, b) assert.MustNoError(err) assert.Must(n == len(b) && bytes.Equal(b, input)) bl.Close() assert.Must(r1.IsValid() == false) assert.Must(r2.IsValid() == false) _, err = r1.Read([]byte{0}) assert.Must(errors.Equal(err, ErrClosedBacklog)) _, err = r2.Read([]byte{0}) assert.Must(errors.Equal(err, ErrClosedBacklog)) _, err = bl.Write([]byte{0}) assert.Must(errors.Equal(err, ErrClosedBacklog)) }
func testPipe3(t *testing.T, fileName string) { r, w, f := openPipe(t, fileName) defer f.Close() 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.MustNoError(err) c <- n } assert.MustNoError(r.Close()) c <- 0 }() go func() { buf := make([]byte, size) for i := 1; i < size; i++ { n, err := w.Write(buf[:i]) assert.MustNoError(err) assert.Must(n == i) } assert.MustNoError(w.Close()) }() sum := 0 for i := 1; i < size; i++ { sum += i } for { n := <-c if n == 0 { break } sum -= n } assert.Must(sum == 0) }
func TestEncodeString(t *testing.T) { docheck := func(text string) { p, err := EncodeDump(toString(text)) assert.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(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 TestWriteNil(t *testing.T) { r, w := New() go func() { n, err := w.Write(nil) assert.MustNoError(err) assert.Must(n == 0) assert.MustNoError(w.Close()) }() time.Sleep(time.Millisecond * 10) buf := make([]byte, 4096) n, err := io.ReadFull(r, buf) assert.Must(errors.Equal(err, io.EOF)) assert.Must(n == 0) assert.MustNoError(r.Close()) }
func TestEncodeZSet(t *testing.T) { docheck := func(m map[string]float64) { p, err := EncodeDump(toZSet(m)) assert.MustNoError(err) o, err := DecodeDump(p) assert.MustNoError(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 * 10) var err error if u.witherr { err = closer.CloseWithError(u.err) } else { err = closer.Close() } assert.MustNoError(err) c <- 0 }
func testPipe1(t *testing.T, fileName string) { r, w, f := openPipe(t, fileName) defer f.Close() s := "Hello world!!" go func(data []byte) { n, err := w.Write(data) assert.MustNoError(err) assert.Must(n == len(data)) assert.MustNoError(w.Close()) }([]byte(s)) buf := make([]byte, 64) n, err := io.ReadFull(r, buf) assert.Must(errors.Equal(err, io.EOF)) assert.Must(n == len(s)) assert.Must(string(buf[:n]) == s) assert.MustNoError(r.Close()) }
func TestPipeReadClose2(t *testing.T) { r, w := New() c := make(chan int, 1) go delayClose(t, r, c, pipeTest{}) n, err := r.Read(make([]byte, 64)) <-c assert.Must(errors.Equal(err, io.ErrClosedPipe)) assert.Must(n == 0) assert.MustNoError(w.Close()) }
func openPipe(t *testing.T, fileName string) (pr Reader, pw Writer, pf *os.File) { buffSize := 8192 fileSize := 1024 * 1024 * 32 if fileName == "" { pr, pw = NewSize(buffSize) } else { f, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600) assert.MustNoError(err) pr, pw = NewFilePipe(fileSize, f) pf = f } return }
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.MustNoError(err) x, ok := resp.(*Array) assert.Must(ok) assert.Must(len(x.Value) == 2) s1, ok := x.Value[0].(*BulkBytes) assert.Must(ok) assert.Must(bytes.Equal(s1.Value, []byte("LLEN"))) s2, ok := x.Value[1].(*BulkBytes) assert.Must(ok) assert.Must(bytes.Equal(s2.Value, []byte("mylist"))) }
func DecodeHexRdb(t *testing.T, s string, n int) map[string]*BinEntry { p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s)) assert.MustNoError(err) r := bytes.NewReader(p) l := NewLoader(r) assert.MustNoError(l.Header()) entries := make(map[string]*BinEntry) var i int = 0 for { e, err := l.NextBinEntry() assert.MustNoError(err) if e == nil { break } assert.Must(e.DB == 0) entries[string(e.Key)] = e i++ } assert.MustNoError(l.Footer()) assert.Must(r.Len() == 0) assert.Must(len(entries) == i && i == n) return entries }
func TestHandlerFunc(t *testing.T) { h := &testHandler{make(map[string]int)} s, err := NewServer(h) assert.MustNoError(err) key1, key2, key3, key4 := "key1", "key2", "key3", "key4" s.t["get"](nil) testmapcount(t, h.c, map[string]int{}) s.t["get"](nil, []byte(key1), []byte(key2)) testmapcount(t, h.c, map[string]int{key1: 1, key2: 1}) s.t["get"](nil, [][]byte{[]byte(key1), []byte(key3)}...) testmapcount(t, h.c, map[string]int{key1: 2, key2: 1, key3: 1}) s.t["set"](nil) testmapcount(t, h.c, map[string]int{key1: 2, key2: 1, key3: 1}) s.t["set"](nil, []byte(key1), []byte(key4)) testmapcount(t, h.c, map[string]int{key1: 3, key2: 1, key3: 1, key4: 1}) s.t["set"](nil, [][]byte{[]byte(key1), []byte(key2), []byte(key3)}...) testmapcount(t, h.c, map[string]int{key1: 4, key2: 2, key3: 2, key4: 1}) }
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", } for _, s := range test { _, err := DecodeFromBytes([]byte(s)) assert.MustNoError(err) } }
func TestDecodeSimpleRequest2(t *testing.T) { test := []string{ "hello world\r\n", "hello world \r\n", " hello world \r\n", " hello world\r\n", " hello world \r\n", } for _, s := range test { resp, err := DecodeFromBytes([]byte(s)) assert.MustNoError(err) x, ok := resp.(*Array) assert.Must(ok) assert.Must(len(x.Value) == 2) s1, ok := x.Value[0].(*BulkBytes) assert.Must(ok && bytes.Equal(s1.Value, []byte("hello"))) s2, ok := x.Value[1].(*BulkBytes) assert.Must(ok && bytes.Equal(s2.Value, []byte("world"))) } }
func TestPipeWriteClose(t *testing.T) { for _, u := range pipeTests { r, w := New() c := make(chan int, 1) if u.async { go delayClose(t, r, c, u) } else { delayClose(t, r, c, u) } <-c n, err := w.Write([]byte("hello, world")) expect := u.err if expect == nil { expect = io.ErrClosedPipe } assert.Must(errors.Equal(err, expect)) assert.Must(n == 0) assert.MustNoError(w.Close()) } }
func testPipe4(t *testing.T, fileName string) { r, w, f := openPipe(t, fileName) defer f.Close() 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.MustNoError(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 := w.Write(buf) assert.MustNoError(err) assert.MustNoError(w.Close()) assert.Must(n == len(buf)) }() buf := make([]byte, count*block) m, err := aes.NewCipher(key) assert.MustNoError(err) n, err := io.ReadFull(r, buf) assert.MustNoError(err) assert.Must(n == len(buf)) e := cipher.NewCBCDecrypter(m, make([]byte, block)) e.CryptBlocks(buf, buf) for i := 0; i < len(buf); i++ { assert.Must(buf[i] == byte(i)) } _, err = io.ReadFull(r, buf) assert.Must(errors.Equal(err, io.EOF)) assert.MustNoError(r.Close()) }
func TestPipeReadClose(t *testing.T) { for _, u := range pipeTests { r, w := New() 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(errors.Equal(err, expect)) assert.Must(n == 0) assert.MustNoError(r.Close()) } }
func TestWriteRead(t *testing.T) { r, w := New() p := make(chan []byte, 1) go func() { var x []byte for { b := make([]byte, 23) n, err := r.Read(b) if n != 0 { x = append(x, b[:n]...) } if err != nil { p <- x return } } }() b := make([]byte, 1024*1024*128) for i := 0; i < len(b); i++ { b[i] = byte(i) } n, err := w.Write(b) assert.MustNoError(err) assert.Must(n == len(b)) w.Close() x := <-p assert.Must(len(x) == len(b)) assert.Must(bytes.Equal(b, x)) n, err = r.Read(b) assert.Must(err != nil && n == 0) }
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.MustNoError(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.MustNoError(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.MustNoError(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.MustNoError(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.MustNoError(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.MustNoError(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.MustNoError(enc.EncodeFooter()) rdb := b.Bytes() var c atomic2.Int64 l := NewLoader(stats.NewCountReader(bytes.NewReader(rdb), &c)) assert.MustNoError(l.Header()) var i int = 0 for { e, err := l.NextBinEntry() assert.MustNoError(err) if e == nil { break } assert.Must(objs[i].db == e.DB) assert.Must(objs[i].expireat == e.ExpireAt) assert.Must(bytes.Equal(objs[i].key, e.Key)) o, err := DecodeDump(e.Value) assert.MustNoError(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(i == len(objs)) assert.MustNoError(l.Footer()) assert.Must(c.Get() == int64(len(rdb))) }
func testEncodeAndCheck(t *testing.T, resp Resp, expect []byte) { b, err := EncodeToBytes(resp) assert.MustNoError(err) assert.Must(bytes.Equal(b, expect)) }
func checkReader(r io.Reader, b []byte) { x := make([]byte, len(b)) n, err := io.ReadFull(r, x) assert.MustNoError(err) assert.Must(n == len(b) && bytes.Equal(x, b)) }