409 lines
9.6 KiB
Go
409 lines
9.6 KiB
Go
package test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/kms/api-key-service/internal/cache"
|
|
)
|
|
|
|
|
|
func TestMemoryCache_SetAndGet(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "test-key"
|
|
value := []byte("test-value")
|
|
ttl := time.Hour
|
|
|
|
// Set value
|
|
err := memCache.Set(ctx, key, value, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Get value
|
|
retrieved, err := memCache.Get(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, value, retrieved)
|
|
}
|
|
|
|
func TestMemoryCache_GetNonExistent(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "non-existent-key"
|
|
|
|
// Try to get non-existent key
|
|
_, err := memCache.Get(ctx, key)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestMemoryCache_Expiration(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "expiring-key"
|
|
value := []byte("expiring-value")
|
|
ttl := 100 * time.Millisecond
|
|
|
|
// Set value with short TTL
|
|
err := memCache.Set(ctx, key, value, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Get value immediately (should work)
|
|
retrieved, err := memCache.Get(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, value, retrieved)
|
|
|
|
// Wait for expiration
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
// Try to get expired value
|
|
_, err = memCache.Get(ctx, key)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestMemoryCache_Delete(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "delete-key"
|
|
value := []byte("delete-value")
|
|
ttl := time.Hour
|
|
|
|
// Set value
|
|
err := memCache.Set(ctx, key, value, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Verify it exists
|
|
exists, err := memCache.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
|
|
// Delete value
|
|
err = memCache.Delete(ctx, key)
|
|
require.NoError(t, err)
|
|
|
|
// Verify it no longer exists
|
|
exists, err = memCache.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestMemoryCache_Exists(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "exists-key"
|
|
value := []byte("exists-value")
|
|
ttl := time.Hour
|
|
|
|
// Check non-existent key
|
|
exists, err := memCache.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
|
|
// Set value
|
|
err = memCache.Set(ctx, key, value, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Check existing key
|
|
exists, err = memCache.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
}
|
|
|
|
func TestMemoryCache_Clear(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
ttl := time.Hour
|
|
|
|
// Set multiple values
|
|
err := memCache.Set(ctx, "key1", []byte("value1"), ttl)
|
|
require.NoError(t, err)
|
|
err = memCache.Set(ctx, "key2", []byte("value2"), ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Verify they exist
|
|
exists, err := memCache.Exists(ctx, "key1")
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
exists, err = memCache.Exists(ctx, "key2")
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
|
|
// Clear cache
|
|
err = memCache.Clear(ctx)
|
|
require.NoError(t, err)
|
|
|
|
// Verify they no longer exist
|
|
exists, err = memCache.Exists(ctx, "key1")
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
exists, err = memCache.Exists(ctx, "key2")
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestCacheManager_SetAndGetJSON(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "json-key"
|
|
ttl := time.Hour
|
|
|
|
// Test data
|
|
originalData := map[string]interface{}{
|
|
"name": "test",
|
|
"value": 42,
|
|
"items": []string{"a", "b", "c"},
|
|
}
|
|
|
|
// Set JSON
|
|
err := cacheManager.SetJSON(ctx, key, originalData, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Get JSON
|
|
var retrievedData map[string]interface{}
|
|
err = cacheManager.GetJSON(ctx, key, &retrievedData)
|
|
require.NoError(t, err)
|
|
|
|
// Compare data
|
|
assert.Equal(t, originalData["name"], retrievedData["name"])
|
|
assert.Equal(t, float64(42), retrievedData["value"]) // JSON numbers are float64
|
|
|
|
// JSON arrays become []interface{}, so we need to compare differently
|
|
retrievedItems := retrievedData["items"].([]interface{})
|
|
expectedItems := []interface{}{"a", "b", "c"}
|
|
assert.Equal(t, expectedItems, retrievedItems)
|
|
}
|
|
|
|
func TestCacheManager_GetJSONNonExistent(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "non-existent-json-key"
|
|
|
|
var data map[string]interface{}
|
|
err := cacheManager.GetJSON(ctx, key, &data)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestCacheManager_RawBytesOperations(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "raw-key"
|
|
value := []byte("raw-value")
|
|
ttl := time.Hour
|
|
|
|
// Set raw bytes
|
|
err := cacheManager.Set(ctx, key, value, ttl)
|
|
require.NoError(t, err)
|
|
|
|
// Get raw bytes
|
|
retrieved, err := cacheManager.Get(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, value, retrieved)
|
|
|
|
// Check exists
|
|
exists, err := cacheManager.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
|
|
// Delete
|
|
err = cacheManager.Delete(ctx, key)
|
|
require.NoError(t, err)
|
|
|
|
// Verify deleted
|
|
exists, err = cacheManager.Exists(ctx, key)
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestCacheKey(t *testing.T) {
|
|
prefix := "test"
|
|
key := "key123"
|
|
expected := "test:key123"
|
|
|
|
result := cache.CacheKey(prefix, key)
|
|
assert.Equal(t, expected, result)
|
|
}
|
|
|
|
func TestCacheKeyPrefixes(t *testing.T) {
|
|
// Test that constants are defined
|
|
assert.Equal(t, "perm", cache.KeyPrefixPermission)
|
|
assert.Equal(t, "app", cache.KeyPrefixApplication)
|
|
assert.Equal(t, "token", cache.KeyPrefixToken)
|
|
assert.Equal(t, "user_claims", cache.KeyPrefixUserClaims)
|
|
assert.Equal(t, "token_revoked", cache.KeyPrefixTokenRevoked)
|
|
}
|
|
|
|
func TestCacheManager_ConfigMethods(t *testing.T) {
|
|
// Create mock config with cache settings
|
|
config := NewMockConfig()
|
|
config.values["CACHE_ENABLED"] = "true"
|
|
config.values["CACHE_TTL"] = "1h"
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
// Test IsEnabled
|
|
assert.True(t, cacheManager.IsEnabled())
|
|
|
|
// Test GetDefaultTTL
|
|
ttl := cacheManager.GetDefaultTTL()
|
|
assert.Equal(t, time.Hour, ttl)
|
|
}
|
|
|
|
func TestCacheManager_InvalidJSON(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "invalid-json-key"
|
|
|
|
// Set invalid JSON data manually
|
|
invalidJSON := []byte("{invalid json}")
|
|
err := cacheManager.Set(ctx, key, invalidJSON, time.Hour)
|
|
require.NoError(t, err)
|
|
|
|
// Try to get as JSON (should fail)
|
|
var data map[string]interface{}
|
|
err = cacheManager.GetJSON(ctx, key, &data)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestCacheManager_SetJSONMarshalError(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "marshal-error-key"
|
|
|
|
// Try to set data that can't be marshaled (function)
|
|
invalidData := func() {}
|
|
err := cacheManager.SetJSON(ctx, key, invalidData, time.Hour)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkMemoryCache_Set(b *testing.B) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
value := []byte("benchmark-value")
|
|
ttl := time.Hour
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := "benchmark-key-" + string(rune(i))
|
|
memCache.Set(ctx, key, value, ttl)
|
|
}
|
|
}
|
|
|
|
func BenchmarkMemoryCache_Get(b *testing.B) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
memCache := cache.NewMemoryCache(config, logger)
|
|
defer memCache.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "benchmark-get-key"
|
|
value := []byte("benchmark-value")
|
|
ttl := time.Hour
|
|
|
|
// Pre-populate cache
|
|
memCache.Set(ctx, key, value, ttl)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
memCache.Get(ctx, key)
|
|
}
|
|
}
|
|
|
|
func BenchmarkCacheManager_SetJSON(b *testing.B) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
data := map[string]interface{}{
|
|
"name": "benchmark",
|
|
"value": 42,
|
|
"items": []string{"a", "b", "c"},
|
|
}
|
|
ttl := time.Hour
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := "benchmark-json-key-" + string(rune(i))
|
|
cacheManager.SetJSON(ctx, key, data, ttl)
|
|
}
|
|
}
|
|
|
|
func BenchmarkCacheManager_GetJSON(b *testing.B) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
cacheManager := cache.NewCacheManager(config, logger)
|
|
defer cacheManager.Close()
|
|
|
|
ctx := context.Background()
|
|
key := "benchmark-json-get-key"
|
|
data := map[string]interface{}{
|
|
"name": "benchmark",
|
|
"value": 42,
|
|
"items": []string{"a", "b", "c"},
|
|
}
|
|
ttl := time.Hour
|
|
|
|
// Pre-populate cache
|
|
cacheManager.SetJSON(ctx, key, data, ttl)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
var retrieved map[string]interface{}
|
|
cacheManager.GetJSON(ctx, key, &retrieved)
|
|
}
|
|
}
|