423 lines
9.1 KiB
Go
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)
|
|
}
|
|
}
|