package services import ( "context" "fmt" "testing" "time" "go.uber.org/zap" ) func TestNewCDNService(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) if service == nil { t.Error("NewCDNService() returned nil") } if service.logger == nil { t.Error("NewCDNService() returned service with nil logger") } if service.config.Provider != CDNProviderCloudFront { t.Errorf("NewCDNService() provider = %v, want %v", service.config.Provider, CDNProviderCloudFront) } } func TestCDNService_GetURL(t *testing.T) { tests := []struct { name string config CDNConfig path string expected string }{ { name: "CloudFront enabled", config: CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), }, path: "/audio/track123.mp3", expected: "https://d1234567890.cloudfront.net/audio/track123.mp3", }, { name: "CDN disabled", config: CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: false, Logger: zap.NewNop(), }, path: "/audio/track123.mp3", expected: "/audio/track123.mp3", }, { name: "None provider", config: CDNConfig{ Provider: CDNProviderNone, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), }, path: "/audio/track123.mp3", expected: "/audio/track123.mp3", }, { name: "Path without leading slash", config: CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), }, path: "audio/track123.mp3", expected: "https://d1234567890.cloudfront.net/audio/track123.mp3", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { service := NewCDNService(tt.config) result := service.GetURL(tt.path) if result != tt.expected { t.Errorf("GetURL(%s) = %s, want %s", tt.path, result, tt.expected) } }) } } func TestCDNService_GetAssetURL(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) url := service.GetAssetURL("js", "app.js") expected := "https://d1234567890.cloudfront.net/assets/js/app.js" if url != expected { t.Errorf("GetAssetURL() = %s, want %s", url, expected) } } func TestCDNService_GetAudioURL(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) url := service.GetAudioURL("track-123", "audio.mp3") expected := "https://d1234567890.cloudfront.net/audio/track-123/audio.mp3" if url != expected { t.Errorf("GetAudioURL() = %s, want %s", url, expected) } } func TestCDNService_GetHLSURL(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) url := service.GetHLSURL("track-123", "master.m3u8") expected := "https://d1234567890.cloudfront.net/hls/track-123/master.m3u8" if url != expected { t.Errorf("GetHLSURL() = %s, want %s", url, expected) } } func TestCDNService_GetImageURL(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) url := service.GetImageURL("avatars", "user-123.jpg") expected := "https://d1234567890.cloudfront.net/images/avatars/user-123.jpg" if url != expected { t.Errorf("GetImageURL() = %s, want %s", url, expected) } } func TestCDNService_IsEnabled(t *testing.T) { tests := []struct { name string config CDNConfig expected bool }{ { name: "enabled CloudFront", config: CDNConfig{ Provider: CDNProviderCloudFront, Enabled: true, Logger: zap.NewNop(), }, expected: true, }, { name: "disabled", config: CDNConfig{ Provider: CDNProviderCloudFront, Enabled: false, Logger: zap.NewNop(), }, expected: false, }, { name: "none provider", config: CDNConfig{ Provider: CDNProviderNone, Enabled: true, Logger: zap.NewNop(), }, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { service := NewCDNService(tt.config) result := service.IsEnabled() if result != tt.expected { t.Errorf("IsEnabled() = %v, want %v", result, tt.expected) } }) } } func TestCDNService_GetProvider(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudflare, Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) provider := service.GetProvider() if provider != CDNProviderCloudflare { t.Errorf("GetProvider() = %v, want %v", provider, CDNProviderCloudflare) } } func TestCDNService_GetBaseURL(t *testing.T) { expectedURL := "https://d1234567890.cloudfront.net" config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: expectedURL, Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) baseURL := service.GetBaseURL() if baseURL != expectedURL { t.Errorf("GetBaseURL() = %s, want %s", baseURL, expectedURL) } } func TestCDNService_GetCacheHeaders(t *testing.T) { tests := []struct { name string config CDNConfig expectedHeader string }{ { name: "CloudFront enabled", config: CDNConfig{ Provider: CDNProviderCloudFront, Enabled: true, Logger: zap.NewNop(), }, expectedHeader: "public, max-age=31536000, immutable", }, { name: "Cloudflare enabled", config: CDNConfig{ Provider: CDNProviderCloudflare, Enabled: true, Logger: zap.NewNop(), }, expectedHeader: "public, max-age=31536000, immutable", }, { name: "CDN disabled", config: CDNConfig{ Provider: CDNProviderCloudFront, Enabled: false, Logger: zap.NewNop(), }, expectedHeader: "no-cache", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { service := NewCDNService(tt.config) headers := service.GetCacheHeaders() cacheControl := headers["Cache-Control"] if cacheControl != tt.expectedHeader { t.Errorf("GetCacheHeaders() Cache-Control = %s, want %s", cacheControl, tt.expectedHeader) } }) } } func TestCDNService_InvalidateCache(t *testing.T) { config := CDNConfig{ Provider: CDNProviderGeneric, BaseURL: "https://cdn.example.com", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) ctx := context.Background() paths := []string{"/audio/track1.mp3", "/audio/track2.mp3"} err := service.InvalidateCache(ctx, paths) if err != nil { t.Errorf("InvalidateCache() error = %v", err) } } func TestCDNService_BatchInvalidate(t *testing.T) { config := CDNConfig{ Provider: CDNProviderGeneric, BaseURL: "https://cdn.example.com", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) ctx := context.Background() paths := make([]string, 25) for i := 0; i < 25; i++ { paths[i] = fmt.Sprintf("/audio/track%d.mp3", i) } err := service.BatchInvalidate(ctx, paths, 10) if err != nil { t.Errorf("BatchInvalidate() error = %v", err) } } func TestCDNService_GenerateSignedURL(t *testing.T) { config := CDNConfig{ Provider: CDNProviderCloudFront, BaseURL: "https://d1234567890.cloudfront.net", Enabled: true, Logger: zap.NewNop(), } service := NewCDNService(config) url, err := service.GenerateSignedURL("/audio/track123.mp3", time.Hour) if err != nil { t.Errorf("GenerateSignedURL() error = %v", err) } if url == "" { t.Error("GenerateSignedURL() returned empty URL") } } // Note: Full integration tests would require: // 1. Real CDN provider credentials // 2. Actual CDN distribution/zone // 3. Verification of cache invalidation // 4. Testing of signed URL generation // // Example integration test structure: // func TestCDNService_InvalidateCache_Integration(t *testing.T) { // // Skip if CDN not configured // if os.Getenv("CDN_ENABLED") != "true" { // t.Skip("CDN not configured") // } // // config := CDNConfig{ // Provider: CDNProviderCloudFront, // BaseURL: os.Getenv("CDN_BASE_URL"), // DistributionID: os.Getenv("CDN_DISTRIBUTION_ID"), // APIKey: os.Getenv("CDN_API_KEY"), // Enabled: true, // Logger: zap.NewNop(), // } // // service := NewCDNService(config) // ctx := context.Background() // // paths := []string{"/test/path1.mp3", "/test/path2.mp3"} // err := service.InvalidateCache(ctx, paths) // if err != nil { // t.Fatalf("InvalidateCache() error = %v", err) // } // // // Verify invalidation was successful (check CDN API) // }