226 lines
5.6 KiB
Plaintext
226 lines
5.6 KiB
Plaintext
package app
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"github.com/gochat/gochat/internal/config"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// TestParseRedisURL 测试 parseRedisURL 函数的各种 URL 格式解析
|
|
func TestParseRedisURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string // 测试用例名称
|
|
urlStr string // 输入的 Redis URL
|
|
wantErr bool // 是否期望返回错误
|
|
want *redis.Options // 期望的解析结果(仅检查关键字段)
|
|
}{
|
|
{
|
|
name: "标准Redis URL - host:port/db",
|
|
urlStr: "redis://localhost:6379/0",
|
|
wantErr: false,
|
|
want: &redis.Options{
|
|
Addr: "localhost:6379",
|
|
DB: 0,
|
|
},
|
|
},
|
|
{
|
|
name: "带用户名密码的Redis URL",
|
|
urlStr: "redis://user:password@localhost:6379/1",
|
|
wantErr: false,
|
|
want: &redis.Options{
|
|
Addr: "localhost:6379",
|
|
DB: 1,
|
|
Username: "user",
|
|
Password: "password",
|
|
},
|
|
},
|
|
{
|
|
name: "仅密码的Redis URL",
|
|
urlStr: "redis://:secretpass@localhost:6379/2",
|
|
wantErr: false,
|
|
want: &redis.Options{
|
|
Addr: "localhost:6379",
|
|
DB: 2,
|
|
Password: "secretpass",
|
|
},
|
|
},
|
|
{
|
|
name: "简单host:port格式 - 回退解析",
|
|
urlStr: "redis://myhost:6380",
|
|
wantErr: false,
|
|
want: &redis.Options{
|
|
Addr: "myhost:6380",
|
|
},
|
|
},
|
|
{
|
|
name: "无效URL - 空字符串",
|
|
urlStr: "",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "无效URL - 非Redis协议",
|
|
urlStr: "http://localhost:6379",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "无效URL - 端口不是数字",
|
|
urlStr: "redis://localhost:abc",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
opts, err := parseRedisURL(tt.urlStr)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("parseRedisURL(%q) 期望返回错误,但未返回错误", tt.urlStr)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Errorf("parseRedisURL(%q) 未期望返回错误,但返回了: %v", tt.urlStr, err)
|
|
return
|
|
}
|
|
// 检查关键字段
|
|
if opts.Addr != tt.want.Addr {
|
|
t.Errorf("parseRedisURL(%q) Addr = %q, 期望 %q", tt.urlStr, opts.Addr, tt.want.Addr)
|
|
}
|
|
if opts.DB != tt.want.DB {
|
|
t.Errorf("parseRedisURL(%q) DB = %d, 期望 %d", tt.urlStr, opts.DB, tt.want.DB)
|
|
}
|
|
if tt.want.Username != "" && opts.Username != tt.want.Username {
|
|
t.Errorf("parseRedisURL(%q) Username = %q, 期望 %q", tt.urlStr, opts.Username, tt.want.Username)
|
|
}
|
|
if tt.want.Password != "" && opts.Password != tt.want.Password {
|
|
t.Errorf("parseRedisURL(%q) Password = %q, 期望 %q", tt.urlStr, opts.Password, tt.want.Password)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestNewRedisClient_Success 使用 miniredis 模拟 Redis 服务,测试成功连接
|
|
func TestNewRedisClient_Success(t *testing.T) {
|
|
// 启动 miniredis 模拟服务器
|
|
mr, err := miniredis.Run()
|
|
if err != nil {
|
|
t.Fatalf("启动 miniredis 失败: %v", err)
|
|
}
|
|
defer mr.Close()
|
|
|
|
cfg := &config.RedisConfig{
|
|
URL: "redis://" + mr.Addr(),
|
|
}
|
|
|
|
client, err := NewRedisClient(cfg)
|
|
if err != nil {
|
|
t.Fatalf("NewRedisClient 返回了意外的错误: %v", err)
|
|
}
|
|
defer client.Close()
|
|
|
|
// 验证客户端可以正常执行命令
|
|
ctx := context.Background()
|
|
val, err := client.Set(ctx, "test_key", "test_value", 0).Result()
|
|
if err != nil {
|
|
t.Errorf("Set 命令执行失败: %v", err)
|
|
}
|
|
if val != "OK" {
|
|
t.Errorf("Set 返回值 = %q, 期望 %q", val, "OK")
|
|
}
|
|
|
|
got, err := client.Get(ctx, "test_key").Result()
|
|
if err != nil {
|
|
t.Errorf("Get 命令执行失败: %v", err)
|
|
}
|
|
if got != "test_value" {
|
|
t.Errorf("Get 返回值 = %q, 期望 %q", got, "test_value")
|
|
}
|
|
}
|
|
|
|
// TestNewRedisClient_SuccessWithPassword 使用 miniredis 测试带密码的成功连接
|
|
func TestNewRedisClient_SuccessWithPassword(t *testing.T) {
|
|
mr, err := miniredis.Run()
|
|
if err != nil {
|
|
t.Fatalf("启动 miniredis 失败: %v", err)
|
|
}
|
|
defer mr.Close()
|
|
|
|
// 设置 miniredis 密码
|
|
mr.RequireAuth("testpassword")
|
|
|
|
cfg := &config.RedisConfig{
|
|
URL: "redis://" + mr.Addr(),
|
|
Password: "testpassword",
|
|
}
|
|
|
|
client, err := NewRedisClient(cfg)
|
|
if err != nil {
|
|
t.Fatalf("NewRedisClient 返回了意外的错误: %v", err)
|
|
}
|
|
defer client.Close()
|
|
|
|
// 验证客户端可以正常执行命令
|
|
ctx := context.Background()
|
|
result, err := client.Ping(ctx).Result()
|
|
if err != nil {
|
|
t.Errorf("Ping 命令执行失败: %v", err)
|
|
}
|
|
if result != "PONG" {
|
|
t.Errorf("Ping 返回值 = %q, 期望 %q", result, "PONG")
|
|
}
|
|
}
|
|
|
|
// TestNewRedisClient_InvalidURL 测试无效 URL 时 NewRedisClient 返回错误
|
|
func TestNewRedisClient_InvalidURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
url string
|
|
}{
|
|
{
|
|
name: "空字符串URL",
|
|
url: "",
|
|
},
|
|
{
|
|
name: "缺少端口的URL",
|
|
url: "redis://localhost",
|
|
},
|
|
{
|
|
name: "端口格式错误",
|
|
url: "redis://localhost:notaport",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cfg := &config.RedisConfig{
|
|
URL: tt.url,
|
|
}
|
|
client, err := NewRedisClient(cfg)
|
|
if err == nil {
|
|
client.Close()
|
|
t.Errorf("NewRedisClient(url=%q) 期望返回错误,但未返回错误", tt.url)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestNewRedisClient_ConnectionFailure 测试连接到不可达的 Redis 服务器时返回错误
|
|
func TestNewRedisClient_ConnectionFailure(t *testing.T) {
|
|
cfg := &config.RedisConfig{
|
|
// 使用一个不会存在的端口,确保连接失败
|
|
URL: "redis://127.0.0.1:19999",
|
|
}
|
|
|
|
client, err := NewRedisClient(cfg)
|
|
if err == nil {
|
|
client.Close()
|
|
t.Errorf("NewRedisClient 期望连接失败返回错误,但未返回错误")
|
|
}
|
|
// 期望包含 "failed to connect to Redis" 的错误信息
|
|
if err != nil && client != nil {
|
|
t.Logf("连接失败返回了预期的错误: %v", err)
|
|
}
|
|
} |