package aws import ( "testing" "github.com/opencost/opencost/core/pkg/pricing" ) func TestNewAWSPricingSource(t *testing.T) { config := AWSPricingSourceConfig{ CurrencyCode: "USD", } source := NewAWSPricingSource(config) if source == nil { t.Fatal("NewAWSPricingSource() returned nil") } if source.config.CurrencyCode != "USD" { t.Errorf("CurrencyCode = %v, want USD", source.config.CurrencyCode) } } func TestUsageTypeRegex(t *testing.T) { tests := []struct { name string usageType string wantMatch bool wantGroup string }{ { name: "Standard EBS usage", usageType: "USE1-EBS:VolumeUsage.gp3", wantMatch: true, wantGroup: "EBS:VolumeUsage.gp3", }, { name: "GP2 volume", usageType: "USW2-EBS:VolumeUsage.gp2", wantMatch: true, wantGroup: "EBS:VolumeUsage.gp2", }, { name: "Standard volume", usageType: "USE1-EBS:VolumeUsage", wantMatch: true, wantGroup: "EBS:VolumeUsage", }, { name: "IO1 volume", usageType: "USE1-EBS:VolumeUsage.piops", wantMatch: true, wantGroup: "EBS:VolumeUsage.piops", }, { name: "No region prefix", usageType: "EBS:VolumeUsage.gp3", wantMatch: true, wantGroup: "EBS:VolumeUsage.gp3", }, { name: "Non-EBS usage", usageType: "BoxUsage:t3.medium", wantMatch: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { matches := usageTypeRegex.FindStringSubmatch(tt.usageType) if tt.wantMatch { if len(matches) == 0 { t.Errorf("usageTypeRegex did not match %q", tt.usageType) return } // The last group should contain the EBS usage type actualGroup := matches[len(matches)-1] if actualGroup != tt.wantGroup { t.Errorf("usageTypeRegex matched %q, want %q", actualGroup, tt.wantGroup) } } else { if len(matches) > 0 { t.Errorf("usageTypeRegex unexpectedly matched %q", tt.usageType) } } }) } } func TestAWSVolumeTypes(t *testing.T) { tests := []struct { usageType string expectedType pricing.VolumeType shouldExist bool }{ { usageType: "EBS:VolumeUsage.gp2", expectedType: pricing.VolumeTypeGP2, shouldExist: true, }, { usageType: "EBS:VolumeUsage.gp3", expectedType: pricing.VolumeTypeGP3, shouldExist: true, }, { usageType: "EBS:VolumeUsage", expectedType: pricing.VolumeTypeStandard, shouldExist: true, }, { usageType: "EBS:VolumeUsage.sc1", expectedType: pricing.VolumeTypeSC1, shouldExist: true, }, { usageType: "EBS:VolumeP-IOPS.piops", expectedType: pricing.VolumeTypeIO1, shouldExist: true, }, { usageType: "EBS:VolumeUsage.st1", expectedType: pricing.VolumeTypeST1, shouldExist: true, }, { usageType: "EBS:VolumeUsage.piops", expectedType: pricing.VolumeTypeIO1, shouldExist: true, }, { usageType: "EBS:VolumeUsage.io2", expectedType: pricing.VolumeTypeIO2, shouldExist: true, }, { usageType: "EBS:VolumeUsage.unknown", shouldExist: false, }, } for _, tt := range tests { t.Run(tt.usageType, func(t *testing.T) { volumeType, exists := awsVolumeTypes[tt.usageType] if exists != tt.shouldExist { t.Errorf("awsVolumeTypes[%q] exists = %v, want %v", tt.usageType, exists, tt.shouldExist) return } if tt.shouldExist && volumeType != tt.expectedType { t.Errorf("awsVolumeTypes[%q] = %v, want %v", tt.usageType, volumeType, tt.expectedType) } }) } } func TestOnDemandRateCodes(t *testing.T) { // Test that expected rate codes exist expectedCodes := []string{"JRTCKXETXF"} for _, code := range expectedCodes { if _, exists := OnDemandRateCodes[code]; !exists { t.Errorf("OnDemandRateCodes missing expected code: %s", code) } } // Test that we have at least one code if len(OnDemandRateCodes) == 0 { t.Error("OnDemandRateCodes is empty") } } func TestOnDemandRateCodesCn(t *testing.T) { // Test that expected China rate codes exist expectedCodes := []string{"99YE2YK9UR", "5Y9WH78GDR", "KW44MY7SZN"} for _, code := range expectedCodes { if _, exists := OnDemandRateCodesCn[code]; !exists { t.Errorf("OnDemandRateCodesCn missing expected code: %s", code) } } // Test that we have at least one code if len(OnDemandRateCodesCn) == 0 { t.Error("OnDemandRateCodesCn is empty") } } func TestHourlyRateCodes(t *testing.T) { if HourlyRateCode == "" { t.Error("HourlyRateCode is empty") } if HourlyRateCodeCn == "" { t.Error("HourlyRateCodeCn is empty") } if HourlyRateCode == HourlyRateCodeCn { t.Error("HourlyRateCode and HourlyRateCodeCn should be different") } } func TestPriceListEC2PricePerUnit_ForCurrency(t *testing.T) { tests := []struct { name string price PriceListEC2PricePerUnit currency string expected string }{ { name: "USD currency", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "0.2800", }, currency: "USD", expected: "0.0416", }, { name: "CNY currency", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "0.2800", }, currency: "CNY", expected: "0.2800", }, { name: "CNY lowercase", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "0.2800", }, currency: "cny", expected: "0.2800", }, { name: "Unknown currency defaults to USD", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "0.2800", }, currency: "EUR", expected: "0.0416", }, { name: "CNY empty falls back to USD", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "", }, currency: "CNY", expected: "0.0416", }, { name: "Empty currency defaults to USD", price: PriceListEC2PricePerUnit{ USD: "0.0416", CNY: "0.2800", }, currency: "", expected: "0.0416", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.price.ForCurrency(tt.currency) if result != tt.expected { t.Errorf("ForCurrency(%q) = %v, want %v", tt.currency, result, tt.expected) } }) } }