diff --git a/providers/gcp/services/cloudstorage/client.go b/providers/gcp/services/cloudstorage/client.go index 43e95b5..50c6377 100644 --- a/providers/gcp/services/cloudstorage/client.go +++ b/providers/gcp/services/cloudstorage/client.go @@ -13,6 +13,7 @@ import ( "google.golang.org/api/option" "github.com/LeanerCloud/cloud-commitments-go/pkg/common" + "github.com/LeanerCloud/cloud-commitments-go/providers/gcp/internal/billingcurrency" "github.com/LeanerCloud/cloud-commitments-go/providers/gcp/internal/skulist" "github.com/LeanerCloud/cloud-commitments-go/providers/gcp/internal/skumatch" ) @@ -280,8 +281,6 @@ func (c *Client) getOrCreateBillingService(ctx context.Context) (BillingService, // extractStoragePricingFromSKUs extracts on-demand and commitment pricing from SKU list. func extractStoragePricingFromSKUs(skus []*cloudbilling.Sku, storageClass, region string) (onDemand, commitment float64, currency string, err error) { - currency = "USD" - for _, sku := range skus { if !skuMatchesStorageClass(sku, storageClass, region) { continue @@ -295,8 +294,9 @@ func extractStoragePricingFromSKUs(skus []*cloudbilling.Sku, storageClass, regio continue } - if curr != "" { - currency = curr + currency, err = billingcurrency.Unify(currency, curr, sku.SkuId) + if err != nil { + return 0, 0, "", err } slot, slotErr := skumatch.Slot(sku) diff --git a/providers/gcp/services/cloudstorage/pricing_currency_test.go b/providers/gcp/services/cloudstorage/pricing_currency_test.go new file mode 100644 index 0000000..155f0d6 --- /dev/null +++ b/providers/gcp/services/cloudstorage/pricing_currency_test.go @@ -0,0 +1,64 @@ +package cloudstorage + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/api/cloudbilling/v1" +) + +func currencySKU(id, description, usageType, region, currency string, nanos int64) *cloudbilling.Sku { + return &cloudbilling.Sku{ + SkuId: id, + Description: description, + Category: &cloudbilling.Category{UsageType: usageType}, + ServiceRegions: []string{region}, + PricingInfo: []*cloudbilling.PricingInfo{{ + PricingExpression: &cloudbilling.PricingExpression{ + UsageUnit: "GiBy.mo", + TieredRates: []*cloudbilling.TierRate{{ + UnitPrice: &cloudbilling.Money{CurrencyCode: currency, Nanos: nanos}, + }}, + }, + }}, + } +} + +func TestGetStoragePricing_Currency(t *testing.T) { + const storageClass, region = "STANDARD", "us-central1" + tests := []struct { + name string + onDemandCur string + commitCur string + wantCurrency string + wantErr string + }{ + {name: "consistent non-USD currency is returned as is", onDemandCur: "EUR", commitCur: "EUR", wantCurrency: "EUR"}, + {name: "consistent USD", onDemandCur: "USD", commitCur: "USD", wantCurrency: "USD"}, + {name: "on-demand and commitment currencies differ", onDemandCur: "USD", commitCur: "EUR", wantErr: "priced in EUR but earlier SKUs are priced in USD"}, + {name: "commitment currency missing", onDemandCur: "EUR", commitCur: "", wantErr: "no currency code"}, + {name: "on-demand currency missing", onDemandCur: "", commitCur: "EUR", wantErr: "no currency code"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + client, err := NewClient(ctx, "test-project", region) + require.NoError(t, err) + client.SetBillingService(&MockBillingService{skus: &cloudbilling.ListSkusResponse{Skus: []*cloudbilling.Sku{ + currencySKU("od", storageClass+" Storage in "+region, "OnDemand", region, tt.onDemandCur, 26000000), + currencySKU("cud", storageClass+" Storage commitment in "+region, "Commit1Yr", region, tt.commitCur, 19500000), + }}}) + + got, err := client.getStoragePricing(ctx, storageClass, region, 1) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + require.NoError(t, err) + assert.Equal(t, tt.wantCurrency, got.Currency) + }) + } +}