mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-04 12:52:27 +08:00
* fix: correct non-standard 'yml' tag to 'yaml' in RedisOpts * fix: apply MaxActive config to Redis PoolSize * fix: clarify config semantics, enhance timeout & pool options, and maintain backward compatibility * test: update unit test for redis * refactor: apply suggestions from code review * test: add comprehensive coverage for redis * refactor: resolve funlen linter errors in redis unit tests * refactor: remove empty else-if branch in NewRedis function
313 lines
8.2 KiB
Go
313 lines
8.2 KiB
Go
package cache
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/alicebob/miniredis/v2"
|
||
"github.com/go-redis/redis/v8"
|
||
)
|
||
|
||
func TestRedis(t *testing.T) {
|
||
server, err := miniredis.Run()
|
||
if err != nil {
|
||
t.Error("miniredis.Run Error", err)
|
||
}
|
||
t.Cleanup(server.Close)
|
||
var (
|
||
timeoutDuration = time.Second
|
||
ctx = context.Background()
|
||
opts = &RedisOpts{
|
||
Host: server.Addr(),
|
||
Password: "",
|
||
Database: 0,
|
||
PoolSize: 10,
|
||
MinIdleConns: 5,
|
||
DialTimeout: 5,
|
||
ReadTimeout: 5,
|
||
WriteTimeout: 5,
|
||
PoolTimeout: 5,
|
||
IdleTimeout: 300,
|
||
}
|
||
redis = NewRedis(ctx, opts)
|
||
val = "silenceper"
|
||
key = "username"
|
||
)
|
||
redis.SetConn(redis.conn)
|
||
redis.SetRedisCtx(ctx)
|
||
|
||
if err = redis.Set(key, val, timeoutDuration); err != nil {
|
||
t.Error("set Error", err)
|
||
}
|
||
|
||
if !redis.IsExist(key) {
|
||
t.Error("IsExist Error")
|
||
}
|
||
|
||
name := redis.Get(key).(string)
|
||
if name != val {
|
||
t.Error("get Error")
|
||
}
|
||
|
||
if err = redis.Delete(key); err != nil {
|
||
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)
|
||
}
|
||
}
|