func TestBlankCommmand(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() for _, cmd := range testCommands { if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil { t.Fatalf("Send(%v) returned error %v", cmd.args, err) } } reply, err := redis.Values(c.Do("")) if err != nil { t.Fatalf("Do() returned error %v", err) } if len(reply) != len(testCommands) { t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands)) } for i, cmd := range testCommands { actual := reply[i] if !reflect.DeepEqual(actual, cmd.expected) { t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected) } } }
func TestConnMuxClose(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } m := redisx.NewConnMux(c) defer m.Close() c1 := m.Get() c2 := m.Get() if err := c1.Send("ECHO", "hello"); err != nil { t.Fatal(err) } if err := c1.Close(); err != nil { t.Fatal(err) } if err := c2.Send("ECHO", "world"); err != nil { t.Fatal(err) } if err := c2.Flush(); err != nil { t.Fatal(err) } s, err := redis.String(c2.Receive()) if err != nil { t.Fatal(err) } if s != "world" { t.Fatalf("echo returned %q, want %q", s, "world") } c2.Close() }
func TestPipelineCommands(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() for _, cmd := range testCommands { if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil { t.Fatalf("Send(%v) returned error %v", cmd.args, err) } } if err := c.Flush(); err != nil { t.Errorf("Flush() returned error %v", err) } for _, cmd := range testCommands { actual, err := c.Receive() if err != nil { t.Fatalf("Receive(%v) returned error %v", cmd.args, err) } if !reflect.DeepEqual(actual, cmd.expected) { t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected) } } }
func BenchmarkPipelineConcurrency(b *testing.B) { b.StopTimer() c, err := redistest.Dial() if err != nil { b.Fatalf("error connection to database, %v", err) } defer c.Close() var wg sync.WaitGroup wg.Add(numConcurrent) var pipeline textproto.Pipeline b.StartTimer() for i := 0; i < numConcurrent; i++ { go func() { defer wg.Done() for i := 0; i < b.N; i++ { id := pipeline.Next() pipeline.StartRequest(id) c.Send("PING") c.Flush() pipeline.EndRequest(id) pipeline.StartResponse(id) _, err := c.Receive() if err != nil { b.Fatal(err) } pipeline.EndResponse(id) } }() } wg.Wait() }
func BenchmarkConnMuxConcurrent(b *testing.B) { b.StopTimer() c, err := redistest.Dial() if err != nil { b.Fatalf("error connection to database, %v", err) } defer c.Close() m := redisx.NewConnMux(c) var wg sync.WaitGroup wg.Add(numConcurrent) b.StartTimer() for i := 0; i < numConcurrent; i++ { go func() { defer wg.Done() for i := 0; i < b.N; i++ { c := m.Get() if _, err := c.Do("PING"); err != nil { b.Fatal(err) } c.Close() } }() } wg.Wait() }
func TestScript(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() // To test fall back in Do, we make script unique by adding comment with current time. script := fmt.Sprintf("--%d\nreturn {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", time.Now().UnixNano()) s := redis.NewScript(2, script) reply := []interface{}{[]byte("key1"), []byte("key2"), []byte("arg1"), []byte("arg2")} v, err := s.Do(c, "key1", "key2", "arg1", "arg2") if err != nil { t.Errorf("s.Do(c, ...) returned %v", err) } if !reflect.DeepEqual(v, reply) { t.Errorf("s.Do(c, ..); = %v, want %v", v, reply) } err = s.Load(c) if err != nil { t.Errorf("s.Load(c) returned %v", err) } err = s.SendHash(c, "key1", "key2", "arg1", "arg2") if err != nil { t.Errorf("s.SendHash(c, ...) returned %v", err) } err = c.Flush() if err != nil { t.Errorf("c.Flush() returned %v", err) } v, err = c.Receive() if !reflect.DeepEqual(v, reply) { t.Errorf("s.SendHash(c, ..); c.Receive() = %v, want %v", v, reply) } err = s.Send(c, "key1", "key2", "arg1", "arg2") if err != nil { t.Errorf("s.Send(c, ...) returned %v", err) } err = c.Flush() if err != nil { t.Errorf("c.Flush() returned %v", err) } v, err = c.Receive() if !reflect.DeepEqual(v, reply) { t.Errorf("s.Send(c, ..); c.Receive() = %v, want %v", v, reply) } }
func (d *poolDialer) dial() (redis.Conn, error) { d.dialed += 1 if d.dialErr != nil { return nil, d.dialErr } c, err := redistest.Dial() if err != nil { return nil, err } d.open += 1 return &poolTestConn{d: d, Conn: c}, nil }
func BenchmarkDoPing(b *testing.B) { b.StopTimer() c, err := redistest.Dial() if err != nil { b.Fatal(err) } defer c.Close() b.StartTimer() for i := 0; i < b.N; i++ { if _, err := c.Do("PING"); err != nil { b.Fatal(err) } } }
func BenchmarkConn(b *testing.B) { b.StopTimer() c, err := redistest.Dial() if err != nil { b.Fatalf("error connection to database, %v", err) } defer c.Close() b.StartTimer() for i := 0; i < b.N; i++ { if _, err := c.Do("PING"); err != nil { b.Fatal(err) } } }
func TestDoCommands(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() for _, cmd := range testCommands { actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...) if err != nil { t.Errorf("Do(%v) returned error %v", cmd.args, err) continue } if !reflect.DeepEqual(actual, cmd.expected) { t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected) } } }
func BenchmarkConnMux(b *testing.B) { b.StopTimer() c, err := redistest.Dial() if err != nil { b.Fatalf("error connection to database, %v", err) } m := redisx.NewConnMux(c) defer m.Close() b.StartTimer() for i := 0; i < b.N; i++ { c := m.Get() if _, err := c.Do("PING"); err != nil { b.Fatal(err) } c.Close() } }
func TestError(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() c.Do("SET", "key", "val") _, err = c.Do("HSET", "key", "fld", "val") if err == nil { t.Errorf("Expected err for HSET on string key.") } if c.Err() != nil { t.Errorf("Conn has Err()=%v, expect nil", c.Err()) } _, err = c.Do("SET", "key", "val") if err != nil { t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err) } }
func TestRecvBeforeSend(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() done := make(chan struct{}) go func() { c.Receive() close(done) }() time.Sleep(time.Millisecond) c.Send("PING") c.Flush() <-done _, err = c.Do("") if err != nil { t.Fatalf("error=%v", err) } }
func TestPushed(t *testing.T) { pc, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer pc.Close() nc, err := net.Dial("tcp", ":6379") if err != nil { t.Fatal(err) } defer nc.Close() nc.SetReadDeadline(time.Now().Add(4 * time.Second)) c := redis.PubSubConn{Conn: redis.NewConn(nc, 0, 0)} c.Subscribe("c1") expectPushed(t, c, "Subscribe(c1)", redis.Subscription{Kind: "subscribe", Channel: "c1", Count: 1}) c.Subscribe("c2") expectPushed(t, c, "Subscribe(c2)", redis.Subscription{Kind: "subscribe", Channel: "c2", Count: 2}) c.PSubscribe("p1") expectPushed(t, c, "PSubscribe(p1)", redis.Subscription{Kind: "psubscribe", Channel: "p1", Count: 3}) c.PSubscribe("p2") expectPushed(t, c, "PSubscribe(p2)", redis.Subscription{Kind: "psubscribe", Channel: "p2", Count: 4}) c.PUnsubscribe() expectPushed(t, c, "Punsubscribe(p1)", redis.Subscription{Kind: "punsubscribe", Channel: "p1", Count: 3}) expectPushed(t, c, "Punsubscribe()", redis.Subscription{Kind: "punsubscribe", Channel: "p2", Count: 2}) pc.Do("PUBLISH", "c1", "hello") expectPushed(t, c, "PUBLISH c1 hello", redis.Message{Channel: "c1", Data: []byte("hello")}) c.Ping("hello") expectPushed(t, c, `Ping("hello")`, redis.Pong{"hello"}) c.Conn.Send("PING") c.Conn.Flush() expectPushed(t, c, `Send("PING")`, redis.Pong{}) }
// TextExecError tests handling of errors in a transaction. See // http://redis.io/topics/transactions for information on how Redis handles // errors in a transaction. func TestExecError(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() // Execute commands that fail before EXEC is called. c.Do("ZADD", "k0", 0, 0) c.Send("MULTI") c.Send("NOTACOMMAND", "k0", 0, 0) c.Send("ZINCRBY", "k0", 0, 0) v, err := c.Do("EXEC") if err == nil { t.Fatalf("EXEC returned values %v, expected error", v) } // Execute commands that fail after EXEC is called. The first command // returns an error. c.Do("ZADD", "k1", 0, 0) c.Send("MULTI") c.Send("HSET", "k1", 0, 0) c.Send("ZINCRBY", "k1", 0, 0) v, err = c.Do("EXEC") if err != nil { t.Fatalf("EXEC returned error %v", err) } vs, err := redis.Values(v, nil) if err != nil { t.Fatalf("Values(v) returned error %v", err) } if len(vs) != 2 { t.Fatalf("len(vs) == %d, want 2", len(vs)) } if _, ok := vs[0].(error); !ok { t.Fatalf("first result is type %T, expected error", vs[0]) } if _, ok := vs[1].([]byte); !ok { t.Fatalf("second result is type %T, expected []byte", vs[2]) } // Execute commands that fail after EXEC is called. The second command // returns an error. c.Do("ZADD", "k2", 0, 0) c.Send("MULTI") c.Send("ZINCRBY", "k2", 0, 0) c.Send("HSET", "k2", 0, 0) v, err = c.Do("EXEC") if err != nil { t.Fatalf("EXEC returned error %v", err) } vs, err = redis.Values(v, nil) if err != nil { t.Fatalf("Values(v) returned error %v", err) } if len(vs) != 2 { t.Fatalf("len(vs) == %d, want 2", len(vs)) } if _, ok := vs[0].([]byte); !ok { t.Fatalf("first result is type %T, expected []byte", vs[0]) } if _, ok := vs[1].(error); !ok { t.Fatalf("second result is type %T, expected error", vs[2]) } }
// dial wraps DialTestDB() with a more suitable function name for examples. func dial() (redis.Conn, error) { return redistest.Dial() }