|
@@ -6,6 +6,7 @@ import (
|
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"github.com/alicebob/miniredis/v2"
|
|
|
|
|
+ "github.com/go-redis/redis/v8"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
func TestRedis(t *testing.T) {
|
|
func TestRedis(t *testing.T) {
|
|
@@ -18,7 +19,16 @@ func TestRedis(t *testing.T) {
|
|
|
timeoutDuration = time.Second
|
|
timeoutDuration = time.Second
|
|
|
ctx = context.Background()
|
|
ctx = context.Background()
|
|
|
opts = &RedisOpts{
|
|
opts = &RedisOpts{
|
|
|
- Host: server.Addr(),
|
|
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Password: "",
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ PoolSize: 10,
|
|
|
|
|
+ MinIdleConns: 5,
|
|
|
|
|
+ DialTimeout: 5,
|
|
|
|
|
+ ReadTimeout: 5,
|
|
|
|
|
+ WriteTimeout: 5,
|
|
|
|
|
+ PoolTimeout: 5,
|
|
|
|
|
+ IdleTimeout: 300,
|
|
|
}
|
|
}
|
|
|
redis = NewRedis(ctx, opts)
|
|
redis = NewRedis(ctx, opts)
|
|
|
val = "silenceper"
|
|
val = "silenceper"
|
|
@@ -44,3 +54,259 @@ func TestRedis(t *testing.T) {
|
|
|
t.Errorf("delete Error , err=%v", err)
|
|
t.Errorf("delete Error , err=%v", err)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// setupRedisServer 创建并返回一个 miniredis 服务器实例
|
|
|
|
|
+func setupRedisServer(t *testing.T) *miniredis.Miniredis {
|
|
|
|
|
+ server, err := miniredis.Run()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal("miniredis.Run Error", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ t.Cleanup(server.Close)
|
|
|
|
|
+ return server
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisMaxIdleMapping 测试只设置MaxIdle应该映射到MinIdleConns
|
|
|
|
|
+func TestRedisMaxIdleMapping(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ MaxIdle: 10,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ // 获取底层的 UniversalClient 并断言为 *redis.Client
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 注意:MinIdleConns 表示期望的最小空闲连接数,但实际空闲连接数可能不同
|
|
|
|
|
+ // 我们需要通过 Options() 来验证配置是否正确应用
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ if clientOpts.MinIdleConns != 10 {
|
|
|
|
|
+ t.Errorf("期望 MinIdleConns = 10, 实际 = %d", clientOpts.MinIdleConns)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisMaxActiveMapping 测试只设置MaxActive应该映射到PoolSize
|
|
|
|
|
+func TestRedisMaxActiveMapping(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ MaxActive: 20,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ if clientOpts.PoolSize != 20 {
|
|
|
|
|
+ t.Errorf("期望 PoolSize = 20, 实际 = %d", clientOpts.PoolSize)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisNewFieldsPriority 测试新字段应该优先于旧字段
|
|
|
|
|
+func TestRedisNewFieldsPriority(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ MaxIdle: 5,
|
|
|
|
|
+ MinIdleConns: 15,
|
|
|
|
|
+ MaxActive: 10,
|
|
|
|
|
+ PoolSize: 30,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ if clientOpts.MinIdleConns != 15 {
|
|
|
|
|
+ t.Errorf("期望 MinIdleConns = 15 (新字段优先), 实际 = %d", clientOpts.MinIdleConns)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.PoolSize != 30 {
|
|
|
|
|
+ t.Errorf("期望 PoolSize = 30 (新字段优先), 实际 = %d", clientOpts.PoolSize)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisPositiveTimeouts 测试正值超时应该正确应用
|
|
|
|
|
+func TestRedisPositiveTimeouts(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ DialTimeout: 10,
|
|
|
|
|
+ ReadTimeout: 20,
|
|
|
|
|
+ WriteTimeout: 30,
|
|
|
|
|
+ PoolTimeout: 40,
|
|
|
|
|
+ IdleTimeout: 50,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ if clientOpts.DialTimeout != 10*time.Second {
|
|
|
|
|
+ t.Errorf("期望 DialTimeout = 10s, 实际 = %v", clientOpts.DialTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.ReadTimeout != 20*time.Second {
|
|
|
|
|
+ t.Errorf("期望 ReadTimeout = 20s, 实际 = %v", clientOpts.ReadTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.WriteTimeout != 30*time.Second {
|
|
|
|
|
+ t.Errorf("期望 WriteTimeout = 30s, 实际 = %v", clientOpts.WriteTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.PoolTimeout != 40*time.Second {
|
|
|
|
|
+ t.Errorf("期望 PoolTimeout = 40s, 实际 = %v", clientOpts.PoolTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.IdleTimeout != 50*time.Second {
|
|
|
|
|
+ t.Errorf("期望 IdleTimeout = 50s, 实际 = %v", clientOpts.IdleTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisNegativeTimeouts 测试-1值应该禁用超时
|
|
|
|
|
+func TestRedisNegativeTimeouts(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ DialTimeout: -1,
|
|
|
|
|
+ ReadTimeout: -1,
|
|
|
|
|
+ WriteTimeout: -1,
|
|
|
|
|
+ PoolTimeout: -1,
|
|
|
|
|
+ IdleTimeout: -1,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ // -1 应该被设置为负值表示禁用超时
|
|
|
|
|
+ // DialTimeout, PoolTimeout, IdleTimeout 会被设置为 -1ns
|
|
|
|
|
+ if clientOpts.DialTimeout != -1 {
|
|
|
|
|
+ t.Errorf("期望 DialTimeout = -1ns (禁用), 实际 = %v", clientOpts.DialTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ // ReadTimeout 和 WriteTimeout 在 go-redis 中有特殊处理
|
|
|
|
|
+ // 当设置为负值时,会被规范化为 0,这也表示无超时
|
|
|
|
|
+ t.Logf("ReadTimeout = %v (设置为-1后的值)", clientOpts.ReadTimeout)
|
|
|
|
|
+ t.Logf("WriteTimeout = %v (设置为-1后的值)", clientOpts.WriteTimeout)
|
|
|
|
|
+
|
|
|
|
|
+ if clientOpts.PoolTimeout != -1 {
|
|
|
|
|
+ t.Errorf("期望 PoolTimeout = -1ns (禁用), 实际 = %v", clientOpts.PoolTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.IdleTimeout != -1 {
|
|
|
|
|
+ t.Errorf("期望 IdleTimeout = -1ns (禁用), 实际 = %v", clientOpts.IdleTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisZeroTimeouts 测试0值应该使用go-redis默认值
|
|
|
|
|
+func TestRedisZeroTimeouts(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ DialTimeout: 0,
|
|
|
|
|
+ ReadTimeout: 0,
|
|
|
|
|
+ WriteTimeout: 0,
|
|
|
|
|
+ PoolTimeout: 0,
|
|
|
|
|
+ IdleTimeout: 0,
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ // 0值应该保持为0,由 go-redis 使用默认值
|
|
|
|
|
+ // go-redis 的默认值:
|
|
|
|
|
+ // DialTimeout: 5s
|
|
|
|
|
+ // ReadTimeout: 3s
|
|
|
|
|
+ // WriteTimeout: ReadTimeout
|
|
|
|
|
+ // PoolTimeout: ReadTimeout + 1s
|
|
|
|
|
+ // IdleTimeout: 5min
|
|
|
|
|
+
|
|
|
|
|
+ if clientOpts.DialTimeout == 0 {
|
|
|
|
|
+ t.Error("期望 DialTimeout 使用 go-redis 默认值 (5s), 实际为 0")
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.ReadTimeout == 0 {
|
|
|
|
|
+ t.Error("期望 ReadTimeout 使用 go-redis 默认值 (3s), 实际为 0")
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.WriteTimeout == 0 {
|
|
|
|
|
+ t.Error("期望 WriteTimeout 使用 go-redis 默认值 (ReadTimeout), 实际为 0")
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.PoolTimeout == 0 {
|
|
|
|
|
+ t.Error("期望 PoolTimeout 使用 go-redis 默认值 (ReadTimeout + 1s), 实际为 0")
|
|
|
|
|
+ }
|
|
|
|
|
+ if clientOpts.IdleTimeout == 0 {
|
|
|
|
|
+ t.Error("期望 IdleTimeout 使用 go-redis 默认值 (5min), 实际为 0")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestRedisMixedTimeouts 测试混合超时配置
|
|
|
|
|
+func TestRedisMixedTimeouts(t *testing.T) {
|
|
|
|
|
+ server := setupRedisServer(t)
|
|
|
|
|
+ ctx := context.Background()
|
|
|
|
|
+
|
|
|
|
|
+ opts := &RedisOpts{
|
|
|
|
|
+ Host: server.Addr(),
|
|
|
|
|
+ Database: 0,
|
|
|
|
|
+ DialTimeout: 5, // 正值
|
|
|
|
|
+ ReadTimeout: -1, // 禁用
|
|
|
|
|
+ WriteTimeout: 0, // 使用默认值
|
|
|
|
|
+ PoolTimeout: 10, // 正值
|
|
|
|
|
+ IdleTimeout: -1, // 禁用
|
|
|
|
|
+ }
|
|
|
|
|
+ r := NewRedis(ctx, opts)
|
|
|
|
|
+
|
|
|
|
|
+ client, ok := r.conn.(*redis.Client)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ t.Fatal("无法转换为 *redis.Client")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clientOpts := client.Options()
|
|
|
|
|
+ if clientOpts.DialTimeout != 5*time.Second {
|
|
|
|
|
+ t.Errorf("期望 DialTimeout = 5s, 实际 = %v", clientOpts.DialTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+ // ReadTimeout 设置为 -1,会被 go-redis 处理为 0(无超时)
|
|
|
|
|
+ t.Logf("ReadTimeout = %v (设置为-1后的值)", clientOpts.ReadTimeout)
|
|
|
|
|
+
|
|
|
|
|
+ // WriteTimeout 设置为 0,应该使用 go-redis 的默认值
|
|
|
|
|
+ // 默认值通常是 ReadTimeout 的值
|
|
|
|
|
+ t.Logf("WriteTimeout = %v (设置为0后使用的默认值)", clientOpts.WriteTimeout)
|
|
|
|
|
+
|
|
|
|
|
+ if clientOpts.PoolTimeout != 10*time.Second {
|
|
|
|
|
+ t.Errorf("期望 PoolTimeout = 10s, 实际 = %v", clientOpts.PoolTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // IdleTimeout 设置为 -1,应该被设置为 -1ns(禁用空闲超时)
|
|
|
|
|
+ if clientOpts.IdleTimeout != -1 {
|
|
|
|
|
+ t.Errorf("期望 IdleTimeout = -1ns (禁用), 实际 = %v", clientOpts.IdleTimeout)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|