func newConnPair() (*Conn, *Conn) { l, err := net.Listen("tcp", "127.0.0.1:0") assert.MustNoError(err) defer l.Close() const bufsize = 128 * 1024 cc := make(chan *Conn, 1) go func() { defer close(cc) for { c, err := l.Accept() if err != nil { return } cc <- NewConnSize(c, bufsize) } }() conn1, err := DialTimeout(l.Addr().String(), bufsize, time.Millisecond*50) assert.MustNoError(err) conn2, ok := <-cc assert.Must(ok) return conn1, conn2 }
func TestProxy(t *testing.T) { fakeZkConn := zkhelper.NewConn() path := GetSlotBasePath(productName) children, _, _ := fakeZkConn.Children(path) assert.Must(len(children) == 0) g := NewServerGroup(productName, 1) g.Create(fakeZkConn) // test create new group _, err := ServerGroups(fakeZkConn, productName) assert.MustNoError(err) ok, err := g.Exists(fakeZkConn) assert.MustNoError(err) assert.Must(ok) s1 := NewServer(SERVER_TYPE_MASTER, "localhost:1111") g.AddServer(fakeZkConn, s1, "") err = InitSlotSet(fakeZkConn, productName, 1024) assert.MustNoError(err) children, _, _ = fakeZkConn.Children(path) assert.Must(len(children) == 1024) s, err := GetSlot(fakeZkConn, productName, 1) assert.MustNoError(err) assert.Must(s.GroupId == -1) err = SetSlotRange(fakeZkConn, productName, 0, 1023, 1, SLOT_STATUS_ONLINE) assert.MustNoError(err) pi := &ProxyInfo{ Id: "proxy_1", Addr: "localhost:1234", State: PROXY_STATE_OFFLINE, } _, err = CreateProxyInfo(fakeZkConn, productName, pi) assert.MustNoError(err) ps, err := ProxyList(fakeZkConn, productName, nil) assert.MustNoError(err) assert.Must(len(ps) == 1) assert.Must(ps[0].Id == "proxy_1") err = SetProxyStatus(fakeZkConn, productName, pi.Id, PROXY_STATE_ONLINE) assert.MustNoError(err) p, err := GetProxyInfo(fakeZkConn, productName, pi.Id) assert.MustNoError(err) assert.Must(p.State == PROXY_STATE_ONLINE) }
func TestBtoi(t *testing.T) { for i, b := range tmap { v, err := btoi(b) assert.MustNoError(err) assert.Must(v == i) } }
func TestForceRemoveLock(t *testing.T) { fakeZkConn := zkhelper.NewConn() zkLock := utils.GetZkLock(fakeZkConn, productName) assert.Must(zkLock != nil) zkLock.Lock("force remove lock") zkPath := fmt.Sprintf("/zk/codis/db_%s/LOCK", productName) children, _, err := fakeZkConn.Children(zkPath) assert.MustNoError(err) assert.Must(len(children) != 0) ForceRemoveLock(fakeZkConn, productName) children, _, err = fakeZkConn.Children(zkPath) assert.MustNoError(err) assert.Must(len(children) == 0) }
func init() { conn = zkhelper.NewConn() conf = &Config{ proxyId: "proxy_test", productName: "test", zkAddr: "localhost:2181", fact: func(string, int) (zkhelper.Conn, error) { return conn, nil }, proto: "tcp4", } //init action path prefix := models.GetWatchActionPath(conf.productName) err := models.CreateActionRootPath(conn, prefix) assert.MustNoError(err) //init slot err = models.InitSlotSet(conn, conf.productName, 1024) assert.MustNoError(err) //init server group g1 := models.NewServerGroup(conf.productName, 1) g1.Create(conn) g2 := models.NewServerGroup(conf.productName, 2) g2.Create(conn) redis1, _ = miniredis.Run() redis2, _ = miniredis.Run() s1 := models.NewServer(models.SERVER_TYPE_MASTER, redis1.Addr()) s2 := models.NewServer(models.SERVER_TYPE_MASTER, redis2.Addr()) g1.AddServer(conn, s1, "") g2.AddServer(conn, s2, "") //set slot range err = models.SetSlotRange(conn, conf.productName, 0, 511, 1, models.SLOT_STATUS_ONLINE) assert.MustNoError(err) err = models.SetSlotRange(conn, conf.productName, 512, 1023, 2, models.SLOT_STATUS_ONLINE) assert.MustNoError(err) s = New(":19000", ":11000", conf) err = models.SetProxyStatus(conn, conf.productName, conf.proxyId, models.PROXY_STATE_ONLINE) assert.MustNoError(err) }
func TestConnReaderTimeout(t *testing.T) { resp := NewString([]byte("hello world")) conn1, conn2 := newConnPair() defer func() { connPool.Put(conn2) }() var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() var err error conn1.ReaderTimeout = time.Millisecond * 10 _, err = conn1.Reader.Decode() assert.Must(err != nil && IsTimeout(err)) conn1.Reader.Err = nil conn1.ReaderTimeout = 0 _, err = conn1.Reader.Decode() assert.MustNoError(err) _, err = conn1.Reader.Decode() assert.Must(err != nil && errors.Equal(err, io.EOF)) }() wg.Add(1) go func() { defer wg.Done() var err error time.Sleep(time.Millisecond * 100) err = conn2.Writer.Encode(resp, true) assert.MustNoError(err) conn2.Close() }() wg.Wait() conn1.Close() conn2.Close() }
func TestBackend(t *testing.T) { l, err := net.Listen("tcp", "127.0.0.1:0") assert.MustNoError(err) defer l.Close() addr := l.Addr().String() reqc := make(chan *Request, 16384) go func() { bc := NewBackendConn(addr) defer bc.Close() defer close(reqc) var resp = redis.NewBulkBytes(make([]byte, 4096)) for i := 0; i < cap(reqc); i++ { r := &Request{ Resp: resp, Wait: &sync.WaitGroup{}, } r.Wait.Add(1) bc.PushBack(r) reqc <- r } }() go func() { c, err := l.Accept() assert.MustNoError(err) defer c.Close() conn := redis.NewConn(c) time.Sleep(time.Millisecond * 300) for i := 0; i < cap(reqc); i++ { _, err := conn.Reader.Decode() assert.MustNoError(err) resp := redis.NewString([]byte(strconv.Itoa(i))) assert.MustNoError(conn.Writer.Encode(resp, true)) } }() var n int for r := range reqc { r.Wait.Wait() assert.Must(string(r.Response.Resp.Value) == strconv.Itoa(n)) n++ } assert.Must(n == cap(reqc)) }
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) assert.Must(len(resp.Array) == 2) s1 := resp.Array[0] assert.Must(bytes.Equal(s1.Value, []byte("LLEN"))) s2 := resp.Array[1] assert.Must(bytes.Equal(s2.Value, []byte("mylist"))) }
func TestAddSlaveToEmptyGroup(t *testing.T) { resetEnv() g := NewServerGroup(productName, 1) g.Create(conn) s1 := NewServer(SERVER_TYPE_SLAVE, "127.0.0.1:1111") err := g.AddServer(conn, s1) assert.MustNoError(err) assert.Must(g.Servers[0].Type == SERVER_TYPE_MASTER) }
func TestNewAction(t *testing.T) { fakeZkConn := zkhelper.NewConn() err := NewAction(fakeZkConn, productName, ACTION_TYPE_SLOT_CHANGED, nil, "desc", false) assert.MustNoError(err) prefix := GetWatchActionPath(productName) exist, _, err := fakeZkConn.Exists(prefix) assert.MustNoError(err) assert.Must(exist) //test if response node exists d, _, err := fakeZkConn.Get(prefix + "/0000000001") assert.MustNoError(err) //test get action data d, _, err = fakeZkConn.Get(GetActionResponsePath(productName) + "/0000000001") assert.MustNoError(err) var action Action err = json.Unmarshal(d, &action) assert.MustNoError(err) assert.Must(action.Desc == "desc") assert.Must(action.Type == ACTION_TYPE_SLOT_CHANGED) }
func TestSessions(t *testing.T) { cleanupSessions(time.Now().Unix() + 100000) assert.Must(sessions.Len() == 0) l, err := net.Listen("tcp", "127.0.0.1:0") assert.MustNoError(err) defer l.Close() const cnt = 8 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for i := 0; i < cnt; i++ { c, err := l.Accept() assert.MustNoError(err) NewSession(c) } }() wg.Add(1) go func() { defer wg.Done() for i := 0; i < cnt; i++ { c, err := net.Dial("tcp", l.Addr().String()) assert.MustNoError(err) NewSession(c) } }() wg.Wait() assert.Must(sessions.Len() == cnt*2) cleanupSessions(time.Now().Unix() + 10) assert.Must(sessions.Len() == 0) }
func runFakeRedisSrv(addr string) { l, err := net.Listen("tcp", addr) assert.MustNoError(err) for { c, err := l.Accept() if err != nil { continue } go func(c net.Conn) { w := bufio.NewWriter(c) w.WriteString("+OK\r\n") w.Flush() }(c) } }
//this should be the last test func TestMarkOffline(t *testing.T) { suicide := int64(0) go func() { s.Join() atomic.StoreInt64(&suicide, 1) }() err := models.SetProxyStatus(conn, conf.productName, conf.proxyId, models.PROXY_STATE_MARK_OFFLINE) assert.MustNoError(err) time.Sleep(3 * time.Second) if atomic.LoadInt64(&suicide) == 0 { t.Error("shoud be suicided") } }
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) assert.Must(resp.IsArray()) assert.Must(len(resp.Array) == 2) s1 := resp.Array[0] assert.Must(bytes.Equal(s1.Value, []byte("hello"))) s2 := resp.Array[1] assert.Must(bytes.Equal(s2.Value, []byte("world"))) } }
func TestGetOpStr(t *testing.T) { var m = map[string]string{ "get": "GET", "aBc": "ABC", "おはよ": "おはよ", "ni hao!": "NI HAO!", "": "", } for k, v := range m { resp := redis.NewArray([]*redis.Resp{redis.NewBulkBytes([]byte(k))}) s, err := getOpStr(resp) if v != "" { assert.MustNoError(err) assert.Must(s == v) } else { assert.Must(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", } for _, s := range test { _, err := DecodeFromBytes([]byte(s)) assert.MustNoError(err) } }
//this should be the last test func TestMarkOffline(t *testing.T) { InitEnv() suicide := int64(0) proxyMutex.Lock() s.OnSuicide = func() error { atomic.StoreInt64(&suicide, 1) return nil } proxyMutex.Unlock() err := models.SetProxyStatus(conn, conf.productName, conf.proxyId, models.PROXY_STATE_MARK_OFFLINE) assert.MustNoError(err) time.Sleep(3 * time.Second) if atomic.LoadInt64(&suicide) == 0 { t.Error("shoud be suicided") } }
func TestConnWriterTimeout(t *testing.T) { resp := NewString([]byte("hello world")) conn1, conn2 := newConnPair() defer func() { connPool.Put(conn2) }() var wg sync.WaitGroup var count atomic2.Int64 wg.Add(1) go func() { defer wg.Done() defer conn2.Close() conn2.WriterTimeout = time.Millisecond * 50 for { if err := conn2.Writer.Encode(resp, true); err != nil { assert.Must(IsTimeout(err)) return } count.Incr() } }() wg.Wait() for i := count.Get(); i != 0; i-- { _, err := conn1.Reader.Decode() assert.MustNoError(err) } _, err := conn1.Reader.Decode() assert.Must(err != nil && errors.Equal(err, io.EOF)) conn1.Close() conn2.Close() }
func TestSlots(t *testing.T) { fakeZkConn := zkhelper.NewConn() path := GetSlotBasePath(productName) children, _, _ := fakeZkConn.Children(path) assert.Must(len(children) == 0) err := InitSlotSet(fakeZkConn, productName, 1024) assert.MustNoError(err) children, _, _ = fakeZkConn.Children(path) assert.Must(len(children) == 1024) s, err := GetSlot(fakeZkConn, productName, 1) assert.MustNoError(err) assert.Must(s.GroupId == -1) g := NewServerGroup(productName, 1) g.Create(fakeZkConn) // test create new group _, err = ServerGroups(fakeZkConn, productName) assert.MustNoError(err) ok, err := g.Exists(fakeZkConn) assert.MustNoError(err) assert.Must(ok) err = SetSlotRange(fakeZkConn, productName, 0, 1023, 1, SLOT_STATUS_ONLINE) assert.MustNoError(err) s, err = GetSlot(fakeZkConn, productName, 1) assert.MustNoError(err) assert.Must(s.GroupId == 1) err = s.SetMigrateStatus(fakeZkConn, 1, 2) assert.MustNoError(err) assert.Must(s.GroupId == 2) assert.Must(s.State.Status == SLOT_STATUS_MIGRATE) }
func TestServerGroup(t *testing.T) { resetEnv() g := NewServerGroup(productName, 1) g.Create(conn) // test create new group groups, err := ServerGroups(conn, productName) assert.MustNoError(err) assert.Must(len(groups) != 0) ok, err := g.Exists(conn) assert.MustNoError(err) assert.Must(ok) gg, err := GetGroup(conn, productName, 1) assert.MustNoError(err) assert.Must(gg != nil && gg.Id == g.Id) s1 := NewServer(SERVER_TYPE_MASTER, "127.0.0.1:1111") s2 := NewServer(SERVER_TYPE_MASTER, "127.0.0.1:2222") err = g.AddServer(conn, s1) servers, err := g.GetServers(conn) assert.MustNoError(err) assert.Must(len(servers) == 1) g.AddServer(conn, s2) assert.Must(len(g.Servers) == 1) s2.Type = SERVER_TYPE_SLAVE g.AddServer(conn, s2) assert.Must(len(g.Servers) == 2) err = g.Promote(conn, s2.Addr) assert.MustNoError(err) s, err := g.Master(conn) assert.MustNoError(err) assert.Must(s.Addr == s2.Addr) }
func TestGetOpStrCmd(t *testing.T) { var m = map[string]string{ "del": "DEL", "dump": "DUMP", "exists": "EXISTS", "expire": "EXPIRE", "expireat": "EXPIREAT", "persist": "PERSIST", "pexpire": "PEXPIRE", "pexpireat": "PEXPIREAT", "pttl": "PTTL", "restore": "RESTORE", "sort": "SORT", "ttl": "TTL", "type": "TYPE", "append": "APPEND", "bitcount": "BITCOUNT", "decr": "DECR", "decrby": "DECRBY", "get": "GET", "getbit": "GETBIT", "getrange": "GETRANGE", "getset": "GETSET", "incr": "INCR", "incrby": "INCRBY", "incrbyfloat": "INCRBYFLOAT", "mget": "MGET", "mset": "MSET", "psetex": "PSETEX", "set": "SET", "setbit": "SETBIT", "setex": "SETEX", "setnx": "SETNX", "setrange": "SETRANGE", "strlen": "STRLEN", "hdel": "HDEL", "hexists": "HEXISTS", "hget": "HGET", "hgetall": "HGETALL", "hincrby": "HINCRBY", "hincrbyfloat": "HINCRBYFLOAT", "hkeys": "HKEYS", "hlen": "HLEN", "hmget": "HMGET", "hmset": "HMSET", "hset": "HSET", "hsetnx": "HSETNX", "hvals": "HVALS", "hscan": "HSCAN", "lindex": "LINDEX", "linsert": "LINSERT", "llen": "LLEN", "lpop": "LPOP", "lpush": "LPUSH", "lpushx": "LPUSHX", "lrange": "LRANGE", "lrem": "LREM", "lset": "LSET", "ltrim": "LTRIM", "rpop": "RPOP", "rpoplpush": "RPOPLPUSH", "rpush": "RPUSH", "rpushx": "RPUSHX", "sadd": "SADD", "scard": "SCARD", "sdiff": "SDIFF", "sdiffstore": "SDIFFSTORE", "sinter": "SINTER", "sinterstore": "SINTERSTORE", "sismember": "SISMEMBER", "smembers": "SMEMBERS", "smove": "SMOVE", "spop": "SPOP", "srandmember": "SRANDMEMBER", "srem": "SREM", "sunion": "SUNION", "sunionstore": "SUNIONSTORE", "sscan": "SSCAN", "zadd": "ZADD", "zcard": "ZCARD", "zcount": "ZCOUNT", "zincrby": "ZINCRBY", "zinterstore": "ZINTERSTORE", "zlexcount": "ZLEXCOUNT", "zrange": "ZRANGE", "zrangebylex": "ZRANGEBYLEX", "zrangebyscore": "ZRANGEBYSCORE", "zrank": "ZRANK", "zrem": "ZREM", "zremrangebylex": "ZREMRANGEBYLEX", "zremrangebyrank": "ZREMRANGEBYRANK", "zremrangebyscore": "ZREMRANGEBYSCORE", "zrevrange": "ZREVRANGE", "zrevrangebyscore": "ZREVRANGEBYSCORE", "zrevrank": "ZREVRANK", "zscore": "ZSCORE", "zunionstore": "ZUNIONSTORE", "zscan": "ZSCAN", "pfadd": "PFADD", "pfcount": "PFCOUNT", "pfmerge": "PFMERGE", "eval": "EVAL", "evalsha": "EVALSHA", } for k, v := range m { resp := redis.NewArray([]*redis.Resp{redis.NewBulkBytes([]byte(k))}) s, err := getOpStr(resp) assert.MustNoError(err) assert.Must(s == v) } }
func TestDecodeSimpleRequest1(t *testing.T) { resp, err := DecodeFromBytes([]byte("\r\n")) assert.MustNoError(err) assert.Must(resp.IsArray()) assert.Must(len(resp.Array) == 0) }
func testEncodeAndCheck(t *testing.T, resp *Resp, expect []byte) { b, err := EncodeToBytes(resp) assert.MustNoError(err) assert.Must(bytes.Equal(b, expect)) }
func InitEnv() { go once.Do(func() { conn = zkhelper.NewConn() conf = &Config{ proxyId: "proxy_test", productName: "test", zkAddr: "localhost:2181", fact: func(string) (zkhelper.Conn, error) { return conn, nil }, proto: "tcp4", } //init action path prefix := models.GetWatchActionPath(conf.productName) err := models.CreateActionRootPath(conn, prefix) assert.MustNoError(err) //init slot err = models.InitSlotSet(conn, conf.productName, 1024) assert.MustNoError(err) //init server group g1 := models.NewServerGroup(conf.productName, 1) g1.Create(conn) g2 := models.NewServerGroup(conf.productName, 2) g2.Create(conn) redis1, _ = miniredis.Run() redis2, _ = miniredis.Run() s1 := models.NewServer(models.SERVER_TYPE_MASTER, redis1.Addr()) s2 := models.NewServer(models.SERVER_TYPE_MASTER, redis2.Addr()) g1.AddServer(conn, s1, "") g2.AddServer(conn, s2, "") //set slot range err = models.SetSlotRange(conn, conf.productName, 0, 511, 1, models.SLOT_STATUS_ONLINE) assert.MustNoError(err) err = models.SetSlotRange(conn, conf.productName, 512, 1023, 2, models.SLOT_STATUS_ONLINE) assert.MustNoError(err) go func() { //set proxy online time.Sleep(3 * time.Second) err := models.SetProxyStatus(conn, conf.productName, conf.proxyId, models.PROXY_STATE_ONLINE) assert.MustNoError(err) time.Sleep(2 * time.Second) proxyMutex.Lock() defer proxyMutex.Unlock() assert.Must(s.info.State == models.PROXY_STATE_ONLINE) }() proxyMutex.Lock() s, err = NewServer(":19000", ":11000", conf) assert.MustNoError(err) proxyMutex.Unlock() s.Serve() }) waitonce.Do(func() { time.Sleep(10 * time.Second) }) }