|
|
|
package redis
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/go-kratos/kratos/pkg/container/pool"
|
|
|
|
xtime "github.com/go-kratos/kratos/pkg/time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestRedis(t *testing.T) {
|
|
|
|
testSet(t, testPool)
|
|
|
|
testSend(t, testPool)
|
|
|
|
testGet(t, testPool)
|
|
|
|
testErr(t, testPool)
|
|
|
|
if err := testPool.Close(); err != nil {
|
|
|
|
t.Errorf("redis: close error(%v)", err)
|
|
|
|
}
|
|
|
|
conn, err := NewConn(testConfig)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("redis: new conn error(%v)", err)
|
|
|
|
}
|
|
|
|
if err := conn.Close(); err != nil {
|
|
|
|
t.Errorf("redis: close error(%v)", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testSet(t *testing.T, p *Pool) {
|
|
|
|
var (
|
|
|
|
key = "test"
|
|
|
|
value = "test"
|
|
|
|
conn = p.Get(context.TODO())
|
|
|
|
)
|
|
|
|
defer conn.Close()
|
|
|
|
if reply, err := conn.Do("set", key, value); err != nil {
|
|
|
|
t.Errorf("redis: conn.Do(SET, %s, %s) error(%v)", key, value, err)
|
|
|
|
} else {
|
|
|
|
t.Logf("redis: set status: %s", reply)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testSend(t *testing.T, p *Pool) {
|
|
|
|
var (
|
|
|
|
key = "test"
|
|
|
|
value = "test"
|
|
|
|
expire = 1000
|
|
|
|
conn = p.Get(context.TODO())
|
|
|
|
)
|
|
|
|
defer conn.Close()
|
|
|
|
if err := conn.Send("SET", key, value); err != nil {
|
|
|
|
t.Errorf("redis: conn.Send(SET, %s, %s) error(%v)", key, value, err)
|
|
|
|
}
|
|
|
|
if err := conn.Send("EXPIRE", key, expire); err != nil {
|
|
|
|
t.Errorf("redis: conn.Send(EXPIRE key(%s) expire(%d)) error(%v)", key, expire, err)
|
|
|
|
}
|
|
|
|
if err := conn.Flush(); err != nil {
|
|
|
|
t.Errorf("redis: conn.Flush error(%v)", err)
|
|
|
|
}
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
if _, err := conn.Receive(); err != nil {
|
|
|
|
t.Errorf("redis: conn.Receive error(%v)", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Logf("redis: set value: %s", value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testGet(t *testing.T, p *Pool) {
|
|
|
|
var (
|
|
|
|
key = "test"
|
|
|
|
conn = p.Get(context.TODO())
|
|
|
|
)
|
|
|
|
defer conn.Close()
|
|
|
|
if reply, err := conn.Do("GET", key); err != nil {
|
|
|
|
t.Errorf("redis: conn.Do(GET, %s) error(%v)", key, err)
|
|
|
|
} else {
|
|
|
|
t.Logf("redis: get value: %s", reply)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testErr(t *testing.T, p *Pool) {
|
|
|
|
conn := p.Get(context.TODO())
|
|
|
|
if err := conn.Close(); err != nil {
|
|
|
|
t.Errorf("redis: close error(%v)", err)
|
|
|
|
}
|
|
|
|
if err := conn.Err(); err == nil {
|
|
|
|
t.Errorf("redis: err not nil")
|
|
|
|
} else {
|
|
|
|
t.Logf("redis: err: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkRedis(b *testing.B) {
|
|
|
|
conf := &Config{
|
|
|
|
Name: "test",
|
|
|
|
Proto: "tcp",
|
|
|
|
Addr: testRedisAddr,
|
|
|
|
DialTimeout: xtime.Duration(time.Second),
|
|
|
|
ReadTimeout: xtime.Duration(time.Second),
|
|
|
|
WriteTimeout: xtime.Duration(time.Second),
|
|
|
|
}
|
|
|
|
conf.Config = &pool.Config{
|
|
|
|
Active: 10,
|
|
|
|
Idle: 5,
|
|
|
|
IdleTimeout: xtime.Duration(90 * time.Second),
|
|
|
|
}
|
|
|
|
benchmarkPool := NewPool(conf)
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
conn := benchmarkPool.Get(context.TODO())
|
|
|
|
if err := conn.Close(); err != nil {
|
|
|
|
b.Errorf("redis: close error(%v)", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if err := benchmarkPool.Close(); err != nil {
|
|
|
|
b.Errorf("redis: close error(%v)", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var testRedisCommands = []struct {
|
|
|
|
args []interface{}
|
|
|
|
expected interface{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
[]interface{}{"PING"},
|
|
|
|
"PONG",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"SET", "foo", "bar"},
|
|
|
|
"OK",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"GET", "foo"},
|
|
|
|
[]byte("bar"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"GET", "nokey"},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"MGET", "nokey", "foo"},
|
|
|
|
[]interface{}{nil, []byte("bar")},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"INCR", "mycounter"},
|
|
|
|
int64(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"LPUSH", "mylist", "foo"},
|
|
|
|
int64(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"LPUSH", "mylist", "bar"},
|
|
|
|
int64(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]interface{}{"LRANGE", "mylist", 0, -1},
|
|
|
|
[]interface{}{[]byte("bar"), []byte("foo")},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewRedis(t *testing.T) {
|
|
|
|
type args struct {
|
|
|
|
c *Config
|
|
|
|
options []DialOption
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
|
|
|
wantErr bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"new_redis",
|
|
|
|
args{
|
|
|
|
testConfig,
|
|
|
|
make([]DialOption, 0),
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
r := NewRedis(tt.args.c, tt.args.options...)
|
|
|
|
if r == nil {
|
|
|
|
t.Errorf("NewRedis() error, got nil")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err := r.Close()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Close() error %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRedis_Do(t *testing.T) {
|
|
|
|
r := NewRedis(testConfig)
|
|
|
|
r.Do(context.TODO(), "FLUSHDB")
|
|
|
|
|
|
|
|
for _, cmd := range testRedisCommands {
|
|
|
|
actual, err := r.Do(context.TODO(), 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err := r.Close()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Close() error %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRedis_Conn(t *testing.T) {
|
|
|
|
type args struct {
|
|
|
|
ctx context.Context
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
p *Redis
|
|
|
|
args args
|
|
|
|
wantErr bool
|
|
|
|
g int
|
|
|
|
c int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"Close",
|
|
|
|
NewRedis(&Config{
|
|
|
|
Config: &pool.Config{
|
|
|
|
Active: 1,
|
|
|
|
Idle: 1,
|
|
|
|
},
|
|
|
|
Name: "test_get",
|
|
|
|
Proto: "tcp",
|
|
|
|
Addr: testRedisAddr,
|
|
|
|
DialTimeout: xtime.Duration(time.Second),
|
|
|
|
ReadTimeout: xtime.Duration(time.Second),
|
|
|
|
WriteTimeout: xtime.Duration(time.Second),
|
|
|
|
}),
|
|
|
|
args{context.TODO()},
|
|
|
|
false,
|
|
|
|
3,
|
|
|
|
3,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"CloseExceededPoolSize",
|
|
|
|
NewRedis(&Config{
|
|
|
|
Config: &pool.Config{
|
|
|
|
Active: 1,
|
|
|
|
Idle: 1,
|
|
|
|
},
|
|
|
|
Name: "test_get_out",
|
|
|
|
Proto: "tcp",
|
|
|
|
Addr: testRedisAddr,
|
|
|
|
DialTimeout: xtime.Duration(time.Second),
|
|
|
|
ReadTimeout: xtime.Duration(time.Second),
|
|
|
|
WriteTimeout: xtime.Duration(time.Second),
|
|
|
|
}),
|
|
|
|
args{context.TODO()},
|
|
|
|
true,
|
|
|
|
5,
|
|
|
|
3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
for i := 1; i <= tt.g; i++ {
|
|
|
|
got := tt.p.Conn(tt.args.ctx)
|
|
|
|
if err := got.Close(); err != nil {
|
|
|
|
if !tt.wantErr {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i <= tt.c {
|
|
|
|
if err := got.Close(); err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkRedisDoPing(b *testing.B) {
|
|
|
|
r := NewRedis(testConfig)
|
|
|
|
defer r.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if _, err := r.Do(context.Background(), "PING"); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkRedisDoSET(b *testing.B) {
|
|
|
|
r := NewRedis(testConfig)
|
|
|
|
defer r.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if _, err := r.Do(context.Background(), "SET", "a", "b"); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkRedisDoGET(b *testing.B) {
|
|
|
|
r := NewRedis(testConfig)
|
|
|
|
defer r.Close()
|
|
|
|
r.Do(context.Background(), "SET", "a", "b")
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if _, err := r.Do(context.Background(), "GET", "b"); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|