Files
Authentication/helper/redis_json_test.go
T
2025-11-25 15:12:31 +08:00

423 lines
9.1 KiB
Go

package helper
import (
"context"
"encoding/json"
"testing"
"time"
"authentication/redisclient"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
)
// setupTestRedis creates a mock Redis server for testing
func setupTestRedis(t *testing.T) (*miniredis.Miniredis, func()) {
mr, err := miniredis.Run()
if err != nil {
t.Fatalf("Failed to start miniredis: %v", err)
}
// Save original client
originalRDB := redisclient.RDB
// Create test client
redisclient.RDB = redis.NewClient(&redis.Options{
Addr: mr.Addr(),
})
cleanup := func() {
redisclient.RDB.Close()
redisclient.RDB = originalRDB
mr.Close()
}
return mr, cleanup
}
func TestSetJSON(t *testing.T) {
mr, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
testData := map[string]interface{}{
"name": "Test User",
"email": "test@example.com",
"age": 30,
}
// Test with default TTL
err := SetJSON(ctx, "test:user:1", testData, nil)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify data was set
val, err := redisclient.RDB.Get(ctx, "test:user:1").Result()
if err != nil {
t.Errorf("Failed to get value: %v", err)
}
var retrieved map[string]interface{}
err = json.Unmarshal([]byte(val), &retrieved)
if err != nil {
t.Errorf("Failed to unmarshal: %v", err)
}
if retrieved["name"] != testData["name"] {
t.Errorf("Expected name '%v', got '%v'", testData["name"], retrieved["name"])
}
// Verify TTL was set (miniredis returns TTL)
ttl := mr.TTL("test:user:1")
if ttl <= 0 {
t.Error("Expected TTL to be set")
}
}
func TestSetJSON_CustomTTL(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
testData := map[string]string{"key": "value"}
customTTL := 120
err := SetJSON(ctx, "test:custom:ttl", testData, &customTTL)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify data was set
val, err := redisclient.RDB.Get(ctx, "test:custom:ttl").Result()
if err != nil {
t.Errorf("Failed to get value: %v", err)
}
if val == "" {
t.Error("Expected value to be set")
}
}
func TestSlotSetJSON(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
testData := map[string]int{"count": 42}
// Test with no TTL
err := SlotSetJSON(ctx, "test:slot:1", testData, nil)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify data was set
val, err := redisclient.RDB.Get(ctx, "test:slot:1").Result()
if err != nil {
t.Errorf("Failed to get value: %v", err)
}
var retrieved map[string]int
err = json.Unmarshal([]byte(val), &retrieved)
if err != nil {
t.Errorf("Failed to unmarshal: %v", err)
}
if retrieved["count"] != testData["count"] {
t.Errorf("Expected count %d, got %d", testData["count"], retrieved["count"])
}
}
func TestSlotSetJSON_WithTTL(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
testData := []string{"item1", "item2"}
ttl := 300
err := SlotSetJSON(ctx, "test:slot:ttl", testData, &ttl)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify data exists
exists, err := redisclient.RDB.Exists(ctx, "test:slot:ttl").Result()
if err != nil {
t.Errorf("Failed to check existence: %v", err)
}
if exists != 1 {
t.Error("Expected key to exist")
}
}
func TestGetJSON(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
type TestStruct struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
original := TestStruct{
Name: "John Doe",
Email: "john@example.com",
Age: 25,
}
// Set data
err := SetJSON(ctx, "test:user:get", original, nil)
if err != nil {
t.Fatalf("Failed to set JSON: %v", err)
}
// Get data
var retrieved TestStruct
err = GetJSON(ctx, "test:user:get", &retrieved)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
if retrieved.Name != original.Name {
t.Errorf("Expected name '%s', got '%s'", original.Name, retrieved.Name)
}
if retrieved.Email != original.Email {
t.Errorf("Expected email '%s', got '%s'", original.Email, retrieved.Email)
}
if retrieved.Age != original.Age {
t.Errorf("Expected age %d, got %d", original.Age, retrieved.Age)
}
}
func TestGetJSON_NonExistentKey(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
var result map[string]string
err := GetJSON(ctx, "test:nonexistent", &result)
if err == nil {
t.Error("Expected error for nonexistent key")
}
}
func TestGetJSON_InvalidJSON(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
// Set invalid JSON
err := redisclient.RDB.Set(ctx, "test:invalid", "not valid json", time.Minute).Err()
if err != nil {
t.Fatalf("Failed to set invalid data: %v", err)
}
var result map[string]string
err = GetJSON(ctx, "test:invalid", &result)
if err == nil {
t.Error("Expected error for invalid JSON")
}
}
func TestSetTTL(t *testing.T) {
mr, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
// Set initial data
err := redisclient.RDB.Set(ctx, "test:ttl:key", "value", 0).Err()
if err != nil {
t.Fatalf("Failed to set initial data: %v", err)
}
// Update TTL
ttl := 300
err = SetTTL(ctx, "test:ttl:key", &ttl)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify TTL was set
actualTTL := mr.TTL("test:ttl:key")
if actualTTL <= 0 {
t.Error("Expected TTL to be set")
}
}
func TestSetTTL_DefaultTTL(t *testing.T) {
mr, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
// Set initial data
err := redisclient.RDB.Set(ctx, "test:ttl:default", "value", 0).Err()
if err != nil {
t.Fatalf("Failed to set initial data: %v", err)
}
// Set default TTL
err = SetTTL(ctx, "test:ttl:default", nil)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}
// Verify TTL was set
actualTTL := mr.TTL("test:ttl:default")
if actualTTL <= 0 {
t.Error("Expected default TTL to be set")
}
}
func TestSetTTL_NonExistentKey(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
err := SetTTL(ctx, "test:ttl:nonexistent", nil)
if err == nil {
t.Error("Expected error for nonexistent key")
}
expectedMsg := "failed to set TTL: key does not exist"
if err.Error() != expectedMsg {
t.Errorf("Expected error '%s', got '%s'", expectedMsg, err.Error())
}
}
func TestSetJSON_MarshalError(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
// Channel cannot be marshaled to JSON
invalidData := make(chan int)
err := SetJSON(ctx, "test:invalid", invalidData, nil)
if err == nil {
t.Error("Expected error for unmarshalable data")
}
}
func TestDefaultRedisTTLSeconds(t *testing.T) {
if defaultRedisTTLSeconds != 60 {
t.Errorf("Expected default TTL 60 seconds, got %d", defaultRedisTTLSeconds)
}
}
func TestSetJSON_RoundTrip(t *testing.T) {
_, cleanup := setupTestRedis(t)
defer cleanup()
ctx := context.Background()
type ComplexStruct struct {
ID string `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags"`
Metadata map[string]interface{} `json:"metadata"`
Active bool `json:"active"`
}
original := ComplexStruct{
ID: "123",
Name: "Test",
Tags: []string{"tag1", "tag2"},
Metadata: map[string]interface{}{"key": "value", "count": 5},
Active: true,
}
// Set
err := SetJSON(ctx, "test:complex", original, nil)
if err != nil {
t.Fatalf("Failed to set: %v", err)
}
// Get
var retrieved ComplexStruct
err = GetJSON(ctx, "test:complex", &retrieved)
if err != nil {
t.Fatalf("Failed to get: %v", err)
}
// Verify
if retrieved.ID != original.ID {
t.Errorf("ID mismatch")
}
if retrieved.Name != original.Name {
t.Errorf("Name mismatch")
}
if len(retrieved.Tags) != len(original.Tags) {
t.Errorf("Tags length mismatch")
}
if retrieved.Active != original.Active {
t.Errorf("Active mismatch")
}
}
func BenchmarkSetJSON(b *testing.B) {
mr, err := miniredis.Run()
if err != nil {
b.Fatalf("Failed to start miniredis: %v", err)
}
defer mr.Close()
originalRDB := redisclient.RDB
redisclient.RDB = redis.NewClient(&redis.Options{Addr: mr.Addr()})
defer func() {
redisclient.RDB.Close()
redisclient.RDB = originalRDB
}()
ctx := context.Background()
testData := map[string]string{"key": "value"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
SetJSON(ctx, "bench:key", testData, nil)
}
}
func BenchmarkGetJSON(b *testing.B) {
mr, err := miniredis.Run()
if err != nil {
b.Fatalf("Failed to start miniredis: %v", err)
}
defer mr.Close()
originalRDB := redisclient.RDB
redisclient.RDB = redis.NewClient(&redis.Options{Addr: mr.Addr()})
defer func() {
redisclient.RDB.Close()
redisclient.RDB = originalRDB
}()
ctx := context.Background()
testData := map[string]string{"key": "value"}
SetJSON(ctx, "bench:key", testData, nil)
b.ResetTimer()
var result map[string]string
for i := 0; i < b.N; i++ {
GetJSON(ctx, "bench:key", &result)
}
}