asg-server/pkg/cache/memory_test.go
2025-09-24 13:47:55 +07:00

492 lines
10 KiB
Go

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")
}
}