v1
This commit is contained in:
380
test/auth_test.go
Normal file
380
test/auth_test.go
Normal file
@ -0,0 +1,380 @@
|
||||
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/auth"
|
||||
"github.com/kms/api-key-service/internal/domain"
|
||||
"github.com/kms/api-key-service/internal/services"
|
||||
)
|
||||
|
||||
// MockConfig implements ConfigProvider for testing
|
||||
type MockConfig struct {
|
||||
values map[string]string
|
||||
}
|
||||
|
||||
func NewMockConfig() *MockConfig {
|
||||
return &MockConfig{
|
||||
values: map[string]string{
|
||||
"JWT_SECRET": "test-jwt-secret-for-testing-only",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockConfig) GetString(key string) string {
|
||||
return m.values[key]
|
||||
}
|
||||
|
||||
func (m *MockConfig) GetInt(key string) int { return 0 }
|
||||
func (m *MockConfig) GetBool(key string) bool { return false }
|
||||
func (m *MockConfig) GetDuration(key string) time.Duration { return 0 }
|
||||
func (m *MockConfig) GetStringSlice(key string) []string { return nil }
|
||||
func (m *MockConfig) IsSet(key string) bool { return m.values[key] != "" }
|
||||
func (m *MockConfig) Validate() error { return nil }
|
||||
func (m *MockConfig) GetDatabaseDSN() string { return "" }
|
||||
func (m *MockConfig) GetServerAddress() string { return "" }
|
||||
func (m *MockConfig) GetMetricsAddress() string { return "" }
|
||||
func (m *MockConfig) GetJWTSecret() string { return m.GetString("JWT_SECRET") }
|
||||
func (m *MockConfig) IsDevelopment() bool { return true }
|
||||
func (m *MockConfig) IsProduction() bool { return false }
|
||||
|
||||
func TestJWTManager_GenerateToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read", "write"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
Claims: map[string]string{
|
||||
"email": "test@example.com",
|
||||
"name": "Test User",
|
||||
},
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, tokenString)
|
||||
|
||||
// Verify the token can be validated
|
||||
claims, err := jwtManager.ValidateToken(tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, claims.UserID)
|
||||
assert.Equal(t, userToken.AppID, claims.AppID)
|
||||
assert.Equal(t, userToken.Permissions, claims.Permissions)
|
||||
assert.Equal(t, userToken.TokenType, claims.TokenType)
|
||||
assert.Equal(t, userToken.Claims, claims.Claims)
|
||||
}
|
||||
|
||||
func TestJWTManager_ValidateToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test valid token
|
||||
claims, err := jwtManager.ValidateToken(tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, claims.UserID)
|
||||
assert.Equal(t, userToken.AppID, claims.AppID)
|
||||
|
||||
// Test invalid token
|
||||
_, err = jwtManager.ValidateToken("invalid-token")
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test empty token
|
||||
_, err = jwtManager.ValidateToken("")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestJWTManager_ExpiredToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
// Create an expired token
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now().Add(-2 * time.Hour),
|
||||
ExpiresAt: time.Now().Add(-time.Hour), // Expired 1 hour ago
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Validation should fail for expired token
|
||||
_, err = jwtManager.ValidateToken(tokenString)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestJWTManager_MaxValidAtExpired(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
// Create a token that's past max valid time
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now().Add(-2 * time.Hour),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(-time.Hour), // Max valid time expired
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Validation should fail for token past max valid time
|
||||
_, err = jwtManager.ValidateToken(tokenString)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestJWTManager_RefreshToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
originalToken, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Refresh the token
|
||||
newExpiration := time.Now().Add(2 * time.Hour)
|
||||
refreshedToken, err := jwtManager.RefreshToken(originalToken, newExpiration)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, refreshedToken)
|
||||
assert.NotEqual(t, originalToken, refreshedToken)
|
||||
|
||||
// Validate the refreshed token
|
||||
claims, err := jwtManager.ValidateToken(refreshedToken)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, claims.UserID)
|
||||
assert.Equal(t, userToken.AppID, claims.AppID)
|
||||
}
|
||||
|
||||
func TestJWTManager_ExtractClaims(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(-time.Hour), // Expired token
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Extract claims from expired token (should work)
|
||||
claims, err := jwtManager.ExtractClaims(tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, claims.UserID)
|
||||
assert.Equal(t, userToken.AppID, claims.AppID)
|
||||
}
|
||||
|
||||
func TestJWTManager_GetTokenInfo(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
info := jwtManager.GetTokenInfo(tokenString)
|
||||
assert.Equal(t, userToken.UserID, info["user_id"])
|
||||
assert.Equal(t, userToken.AppID, info["app_id"])
|
||||
assert.Equal(t, userToken.Permissions, info["permissions"])
|
||||
assert.Equal(t, userToken.TokenType, info["token_type"])
|
||||
}
|
||||
|
||||
func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
authService := services.NewAuthenticationService(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read", "write"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
Claims: map[string]string{
|
||||
"email": "test@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
// Generate token
|
||||
tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Validate token
|
||||
authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, authContext.UserID)
|
||||
assert.Equal(t, userToken.AppID, authContext.AppID)
|
||||
assert.Equal(t, userToken.Permissions, authContext.Permissions)
|
||||
assert.Equal(t, userToken.TokenType, authContext.TokenType)
|
||||
assert.Equal(t, userToken.Claims, authContext.Claims)
|
||||
}
|
||||
|
||||
func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
authService := services.NewAuthenticationService(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, tokenString)
|
||||
|
||||
// Verify token can be validated
|
||||
authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, authContext.UserID)
|
||||
}
|
||||
|
||||
func TestAuthenticationService_RefreshJWTToken(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
authService := services.NewAuthenticationService(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
originalToken, err := authService.GenerateJWTToken(context.Background(), userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Refresh token
|
||||
newExpiration := time.Now().Add(2 * time.Hour)
|
||||
refreshedToken, err := authService.RefreshJWTToken(context.Background(), originalToken, newExpiration)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, refreshedToken)
|
||||
assert.NotEqual(t, originalToken, refreshedToken)
|
||||
|
||||
// Validate refreshed token
|
||||
authContext, err := authService.ValidateJWTToken(context.Background(), refreshedToken)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, userToken.UserID, authContext.UserID)
|
||||
}
|
||||
|
||||
func TestJWTManager_InvalidSecret(t *testing.T) {
|
||||
// Test with empty JWT secret
|
||||
config := &MockConfig{values: map[string]string{"JWT_SECRET": ""}}
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
_, err := jwtManager.GenerateToken(userToken)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestJWTManager_TokenRevocation(t *testing.T) {
|
||||
config := NewMockConfig()
|
||||
logger := zap.NewNop()
|
||||
jwtManager := auth.NewJWTManager(config, logger)
|
||||
|
||||
userToken := &domain.UserToken{
|
||||
AppID: "test-app",
|
||||
UserID: "test-user",
|
||||
Permissions: []string{"read"},
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
MaxValidAt: time.Now().Add(24 * time.Hour),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
tokenString, err := jwtManager.GenerateToken(userToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check revocation status (should be false initially)
|
||||
revoked, err := jwtManager.IsTokenRevoked(tokenString)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, revoked)
|
||||
|
||||
// Revoke token (currently just logs, doesn't actually revoke)
|
||||
err = jwtManager.RevokeToken(tokenString)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Note: Current implementation doesn't actually implement blacklisting,
|
||||
// so this test just verifies the methods don't error
|
||||
}
|
||||
453
test/cache_test.go
Normal file
453
test/cache_test.go
Normal file
@ -0,0 +1,453 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// MockConfig implements ConfigProvider for testing
|
||||
type MockConfig struct {
|
||||
values map[string]string
|
||||
}
|
||||
|
||||
func NewMockConfig() *MockConfig {
|
||||
return &MockConfig{
|
||||
values: map[string]string{
|
||||
"CACHE_ENABLED": "true",
|
||||
"CACHE_TTL": "1h",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockConfig) GetString(key string) string {
|
||||
return m.values[key]
|
||||
}
|
||||
|
||||
func (m *MockConfig) GetInt(key string) int { return 0 }
|
||||
func (m *MockConfig) GetBool(key string) bool {
|
||||
if key == "CACHE_ENABLED" {
|
||||
return m.values[key] == "true"
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (m *MockConfig) GetDuration(key string) time.Duration {
|
||||
if key == "CACHE_TTL" {
|
||||
if d, err := time.ParseDuration(m.values[key]); err == nil {
|
||||
return d
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (m *MockConfig) GetStringSlice(key string) []string { return nil }
|
||||
func (m *MockConfig) IsSet(key string) bool { return m.values[key] != "" }
|
||||
func (m *MockConfig) Validate() error { return nil }
|
||||
func (m *MockConfig) GetDatabaseDSN() string { return "" }
|
||||
func (m *MockConfig) GetServerAddress() string { return "" }
|
||||
func (m *MockConfig) GetMetricsAddress() string { return "" }
|
||||
func (m *MockConfig) GetJWTSecret() string { return m.GetString("JWT_SECRET") }
|
||||
func (m *MockConfig) IsDevelopment() bool { return true }
|
||||
func (m *MockConfig) IsProduction() bool { return false }
|
||||
|
||||
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 := &MockConfig{
|
||||
values: map[string]string{
|
||||
"CACHE_ENABLED": "true",
|
||||
"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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user