redis/redis_test.go

160 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package redis_test
import (
"fmt"
"net"
"os"
"testing"
"time"
"apigo.cc/go/config"
"apigo.cc/go/redis"
)
type userInfo struct {
ID int
Name string
Phone string
Time time.Time
}
func TestMain(m *testing.M) {
// 检查 Redis 是否可用,不可用则跳过测试
os.Setenv("REDIS_TEST", "redis://:@localhost:6379/2?timeout=100ms&logSlow=10us")
conn, err := net.DialTimeout("tcp", "localhost:6379", 500*time.Millisecond)
if err != nil {
fmt.Println("Redis server is not running at localhost:6379, skipping redis tests.")
os.Exit(0)
}
_ = conn.Close()
_ = config.Load("redis", nil)
os.Exit(m.Run())
}
func TestBase(t *testing.T) {
rd := redis.GetRedis("test", nil)
if rd.Error != nil {
t.Fatal("GetRedis error", rd.Error)
}
rd.DEL("redisName", "redisUser", "redisIDs")
// 测试不存在的 Key
r := rd.GET("redisNotExists")
if r.Error != nil || r.String() != "" || r.Int() != 0 {
t.Fatal("GET NotExists should return empty", r.Error, r.String(), r.Int())
}
// 测试 EXISTS
exists := rd.EXISTS("redisName")
if exists {
t.Fatal("EXISTS should be false")
}
// 测试 SET/GET
rd.SET("redisName", "12345")
if rd.GET("redisName").String() != "12345" {
t.Fatal("GET mismatch")
}
// 测试 GETSET
r = rd.GETSET("redisName", 12345)
if r.String() != "12345" {
t.Fatal("GETSET String mismatch", r.String())
}
if rd.GET("redisName").Int() != 12345 {
t.Fatal("Int conversion mismatch")
}
// 测试 Expire
rd.SET("redisExpire", "val")
rd.EXPIRE("redisExpire", 1)
time.Sleep(1100 * time.Millisecond)
if rd.EXISTS("redisExpire") {
t.Fatal("Key should have expired")
}
// 测试 Struct 自动序列化
info := userInfo{
Name: "aaa",
ID: 123,
Time: time.Now().Truncate(time.Second),
}
rd.SET("redisUser", info)
var ru userInfo
rd.GET("redisUser").To(&ru)
if ru.Name != info.Name || ru.ID != info.ID || !ru.Time.Equal(info.Time) {
t.Fatalf("Struct mismatch: expected %+v, got %+v", info, ru)
}
// 测试 MSET/MGET
rd.MSET("redisK1", "V1", "redisK2", "V2")
results := rd.MGET("redisK1", "redisK2")
if len(results) != 2 || results[0].String() != "V1" || results[1].String() != "V2" {
t.Fatal("MGET mismatch")
}
// 清理
rd.DEL("redisName", "redisUser", "redisK1", "redisK2")
}
func TestIDMaker(t *testing.T) {
rd := redis.GetRedis("test", nil)
maker := redis.NewIDMaker(rd)
// 测试生成唯一性
ids := make(map[string]bool)
for i := 0; i < 200; i++ {
id := maker.Get(10)
if ids[id] {
t.Fatalf("Duplicate ID generated: %s", id)
}
ids[id] = true
}
// 测试针对数据库优化的版本
idMysql := maker.GetForMysql(16)
if len(idMysql) != 16 {
t.Fatalf("Invalid MySQL ID length: %d", len(idMysql))
}
idPg := maker.GetForPostgreSQL(16)
if len(idPg) != 16 {
t.Fatalf("Invalid PostgreSQL ID length: %d", len(idPg))
}
}
func TestGenerics(t *testing.T) {
rd := redis.GetRedis("test", nil)
rd.SET("gen_test", userInfo{Name: "Generics", ID: 888})
defer rd.DEL("gen_test")
r := rd.GET("gen_test")
user := redis.To[userInfo](r)
if user.Name != "Generics" || user.ID != 888 {
t.Fatal("Generics To[T] mismatch", user)
}
}
func TestRetry(t *testing.T) {
rd := redis.GetRedis("test", nil)
rd.SET("retry_test", "ok")
// 模拟连接失效(通过直接关闭底层连接池中的连接比较困难,
// 我们这里通过执行一个非法的命令或直接调用 do 模拟)
// 实际上 redis.Pool 已经处理了失效连接的弃用。
// 这里的 retry 主要是针对 Do 过程中的网络抖动。
// 为了真实测试 retry我们可以获取连接后手动关闭它然后再次调用 Do
conn, _ := rd.GetConnection()
_ = conn.Close() // 这里的 Close 只是归还连接池,不一定会导致报错,除非连接池已满或被标记为失效
// 验证重试逻辑Do 方法内部会自动尝试 GetNewConnection
r := rd.Do("GET", "retry_test")
if r.Error != nil || r.String() != "ok" {
t.Fatal("Retry failed", r.Error)
}
rd.DEL("retry_test")
}