package cache_test import ( "context" "testing" "time" "github.com/android-sms-gateway/server/pkg/cache" ) func TestMemoryCache_SetAndGet(t *testing.T) { cache := cache.NewMemory(0) // No TTL for basic tests ctx := context.Background() key := "test-key" value := "test-value" // Test setting a value err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Test getting the value retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_SetAndGetWithTTL(t *testing.T) { c := cache.NewMemory(0) // No default TTL ctx := context.Background() key := "test-key" value := "test-value" ttl := 2 * time.Hour // Test setting a value with TTL err := c.Set(ctx, key, value, cache.WithTTL(ttl)) if err != nil { t.Fatalf("Set with TTL failed: %v", err) } // Test getting the value retrieved, err := c.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_SetAndGetWithValidUntil(t *testing.T) { c := cache.NewMemory(0) // No default TTL ctx := context.Background() key := "test-key" value := "test-value" validUntil := time.Now().Add(2 * time.Hour) // Test setting a value with validUntil err := c.Set(ctx, key, value, cache.WithValidUntil(validUntil)) if err != nil { t.Fatalf("Set with validUntil failed: %v", err) } // Test getting the value retrieved, err := c.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_SetAndGetWithDefaultTTL(t *testing.T) { defaultTTL := 1 * time.Hour cache := cache.NewMemory(defaultTTL) // With default TTL ctx := context.Background() key := "test-key" value := "test-value" // Test setting a value without explicit TTL (should use default) err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Test getting the value retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_GetNotFound(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() key := "non-existent-key" _, err := c.Get(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound, got %v", err) } } func TestMemoryCache_SetOrFailNewKey(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "test-key" value := "test-value" // Test SetOrFail with new key err := cache.SetOrFail(ctx, key, value) if err != nil { t.Fatalf("SetOrFail failed: %v", err) } // Verify the value was set retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_SetOrFailExistingKey(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() key := "test-key" value1 := "value1" value2 := "value2" // Set initial value err := c.Set(ctx, key, value1) if err != nil { t.Fatalf("Set failed: %v", err) } // Try SetOrFail with existing key err = c.SetOrFail(ctx, key, value2) if err != cache.ErrKeyExists { t.Errorf("Expected ErrKeyExists, got %v", err) } // Verify original value is still there retrieved, err := c.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value1 { t.Errorf("Expected %s, got %s", value1, retrieved) } } func TestMemoryCache_Delete(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() key := "test-key" value := "test-value" // Set a value err := c.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Delete the key err = c.Delete(ctx, key) if err != nil { t.Fatalf("Delete failed: %v", err) } // Verify the key is gone _, err = c.Get(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound after delete, got %v", err) } } func TestMemoryCache_DeleteNonExistent(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "non-existent-key" // Delete non-existent key should not fail err := cache.Delete(ctx, key) if err != nil { t.Errorf("Delete of non-existent key failed: %v", err) } } func TestMemoryCache_GetAndDelete(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() key := "test-key" value := "test-value" // Set a value err := c.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Get and delete the key retrieved, err := c.GetAndDelete(ctx, key) if err != nil { t.Fatalf("GetAndDelete failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } // Verify the key is gone _, err = c.Get(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound after GetAndDelete, got %v", err) } } func TestMemoryCache_GetAndDeleteNonExistent(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() key := "non-existent-key" // GetAndDelete non-existent key should return ErrKeyNotFound _, err := c.GetAndDelete(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound, got %v", err) } } func TestMemoryCache_Drain(t *testing.T) { c := cache.NewMemory(0) ctx := context.Background() items := map[string]string{ "key1": "value1", "key2": "value2", "key3": "value3", } // Set multiple values for key, value := range items { err := c.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed for %s: %v", key, err) } } // Drain the cache drained, err := c.Drain(ctx) if err != nil { t.Fatalf("Drain failed: %v", err) } // Verify all items are drained if len(drained) != len(items) { t.Errorf("Expected %d items, got %d", len(items), len(drained)) } for key, expectedValue := range items { actualValue, ok := drained[key] if !ok { t.Errorf("Expected key %s in drained items", key) continue } if actualValue != expectedValue { t.Errorf("Expected %s, got %s for key %s", expectedValue, actualValue, key) } } // Verify cache is now empty for key := range items { _, err := c.Get(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound for key %s after drain, got %v", key, err) } } } func TestMemoryCache_DrainEmpty(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() // Drain empty cache drained, err := cache.Drain(ctx) if err != nil { t.Fatalf("Drain failed: %v", err) } if len(drained) != 0 { t.Errorf("Expected 0 items from empty cache, got %d", len(drained)) } } func TestMemoryCache_Cleanup(t *testing.T) { c := cache.NewMemory(0) // No default TTL ctx := context.Background() key := "test-key" value := "test-value" shortTTL := 100 * time.Millisecond // Set a value with short TTL err := c.Set(ctx, key, value, cache.WithTTL(shortTTL)) if err != nil { t.Fatalf("Set with TTL failed: %v", err) } // Verify the value is there initially _, err = c.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } // Wait for the item to expire time.Sleep(2 * shortTTL) // Run cleanup err = c.Cleanup(ctx) if err != nil { t.Fatalf("Cleanup failed: %v", err) } // Verify the expired item is gone _, err = c.Get(ctx, key) if err != cache.ErrKeyNotFound { t.Errorf("Expected ErrKeyNotFound after cleanup, got %v", err) } } func TestMemoryCache_CleanupNoExpired(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "test-key" value := "test-value" // Set a value without TTL err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Run cleanup on cache with no expired items err = cache.Cleanup(ctx) if err != nil { t.Fatalf("Cleanup failed: %v", err) } // Verify the value is still there retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_Overwrite(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "test-key" value1 := "value1" value2 := "value2" // Set initial value err := cache.Set(ctx, key, value1) if err != nil { t.Fatalf("Set failed: %v", err) } // Overwrite with new value err = cache.Set(ctx, key, value2) if err != nil { t.Fatalf("Set failed: %v", err) } // Verify the new value is there retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value2 { t.Errorf("Expected %s, got %s", value2, retrieved) } } func TestMemoryCache_EmptyValue(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "test-key" value := "" // Set empty value err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Get the empty value retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected empty string, got %s", retrieved) } } func TestMemoryCache_SpecialCharacters(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "test:key/with@special#chars" value := "value with special chars: !@#$%^&*()" // Set value with special characters err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Get the value retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Expected %s, got %s", value, retrieved) } } func TestMemoryCache_LargeValue(t *testing.T) { cache := cache.NewMemory(0) ctx := context.Background() key := "large-key" value := string(make([]byte, 1024*1024)) // 1MB value // Set large value err := cache.Set(ctx, key, value) if err != nil { t.Fatalf("Set failed: %v", err) } // Get the large value retrieved, err := cache.Get(ctx, key) if err != nil { t.Fatalf("Get failed: %v", err) } if retrieved != value { t.Errorf("Large value mismatch") } }