Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion providers/gcp/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
cloud.google.com/go/redis v1.18.3
cloud.google.com/go/resourcemanager v1.10.7
cloud.google.com/go/storage v1.59.2
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261013221254-77bc8a993eb8
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261015085730-498b74f31f01
github.com/googleapis/gax-go/v2 v2.21.0
github.com/stretchr/testify v1.11.1
golang.org/x/oauth2 v0.36.0
Expand Down
4 changes: 2 additions & 2 deletions providers/gcp/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261013221254-77bc8a993eb8 h1:0EMP5PHw8RnQ5Xl8B2firZ8CwRSpmxitMZ4cdYuL8p4=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261013221254-77bc8a993eb8/go.mod h1:8RTmzPazA8IeVZfn7wNaU7ILx0VK5eHZQozO21Mvtq8=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261015085730-498b74f31f01 h1:R2EQAvwLAxPrdlZXmF+bI7ioQYh1CxBkethx5hq6WWA=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261015085730-498b74f31f01/go.mod h1:8RTmzPazA8IeVZfn7wNaU7ILx0VK5eHZQozO21Mvtq8=
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
Expand Down
1 change: 1 addition & 0 deletions providers/gcp/services/cloudsql/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ func (c *Client) fillSQLPricing(ctx context.Context, rec *common.Recommendation,
if pricing.CommitmentPrice > 0 {
monthly := pricing.CommitmentPrice / float64(termYears*12)
rec.RecurringMonthlyCost = &monthly
rec.CommitmentCurrency = pricing.Currency
}
rec.OnDemandCost = pricing.OnDemandPrice
rec.SavingsPercentage = pricing.SavingsPercentage
Expand Down
11 changes: 8 additions & 3 deletions providers/gcp/services/cloudsql/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
UnitPrice: &cloudbilling.Money{
Units: 0,
Nanos: int64(onDemandHourly * 1e9),
CurrencyCode: "USD",
CurrencyCode: "EUR",
},
},
},
Expand All @@ -912,7 +912,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
UnitPrice: &cloudbilling.Money{
Units: 0,
Nanos: int64(commitmentHourly * 1e9),
CurrencyCode: "USD",
CurrencyCode: "EUR",
},
},
},
Expand All @@ -931,7 +931,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
Category: recommenderpb.Impact_COST,
Projection: &recommenderpb.Impact_CostProjection{
CostProjection: &recommenderpb.CostProjection{
Cost: &money.Money{Units: -100, CurrencyCode: "USD"},
Cost: &money.Money{Units: -100, CurrencyCode: "JPY"},
},
},
},
Expand All @@ -952,6 +952,8 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
rec := client.convertGCPRecommendation(ctx, gcpRec, common.RecommendationParams{Term: term, PaymentOption: payment})
rec.Count = 3
rec.AccountName = "fixture"
assert.Equal(t, "EUR", rec.CommitmentCurrency)
assert.Equal(t, float64(100), rec.EstimatedSavings)
require.NotNil(t, rec.RecurringMonthlyCost)
assert.Zero(t, rec.CommitmentCost)
assert.InDelta(t, 100, *rec.RecurringMonthlyCost, 0.00001)
Expand All @@ -968,6 +970,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
scaled, err := common.ResizeCount(*rec, 2)
require.NoError(t, err)
assert.Equal(t, 2, scaled.Count)
assert.Equal(t, "EUR", scaled.CommitmentCurrency)
assert.InDelta(t, 800*months/12, scaled.CommitmentCost+*scaled.RecurringMonthlyCost*months, 0.0001)
assert.InDelta(t, 100, *rec.RecurringMonthlyCost, 0.00001)
quote, err := client.GetOfferingDetails(ctx, *rec)
Expand All @@ -984,6 +987,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *testing
assert.Zero(t, rec.CommitmentCost)
assert.Zero(t, rec.BreakEvenMonths)
assert.Nil(t, rec.RecurringMonthlyCost)
assert.Empty(t, rec.CommitmentCurrency)
})
}

Expand Down Expand Up @@ -1012,6 +1016,7 @@ func TestCloudSQLClient_ConvertGCPRecommendation_RecurringMonthlyCost_BillingFai
assert.Zero(t, rec.CommitmentCost)
assert.Zero(t, rec.BreakEvenMonths)
assert.Nil(t, rec.RecurringMonthlyCost)
assert.Empty(t, rec.CommitmentCurrency)
})
}
}
Expand Down
8 changes: 8 additions & 0 deletions providers/gcp/services/cloudsql/pricing_currency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/api/cloudbilling/v1"

"github.com/LeanerCloud/cloud-commitments-go/pkg/common"
)

func currencySKU(id, description, usageType, region, currency string, nanos int64) *cloudbilling.Sku {
Expand Down Expand Up @@ -51,13 +53,19 @@ func TestGetSQLPricing_Currency(t *testing.T) {
}}})

got, err := client.getSQLPricing(ctx, tier, region, 1)
rec := common.Recommendation{ResourceType: tier, Term: "1yr"}
client.fillSQLPricing(ctx, &rec, 1)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
assert.Empty(t, rec.CommitmentCurrency)
assert.Nil(t, rec.RecurringMonthlyCost)
return
}
require.NoError(t, err)
assert.Equal(t, tt.wantCurrency, got.Currency)
assert.Equal(t, tt.wantCurrency, rec.CommitmentCurrency)
require.NotNil(t, rec.RecurringMonthlyCost)
})
}
}
1 change: 1 addition & 0 deletions providers/gcp/services/computeengine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,7 @@ func (c *Client) enrichRecWithPricing(ctx context.Context, rec *common.Recommend
termMonths := float64(termYears * 12)
monthly := pricing.CommitmentPrice / termMonths
rec.RecurringMonthlyCost = &monthly
rec.CommitmentCurrency = pricing.Currency
rec.OnDemandCost = pricing.OnDemandPrice / termMonths
rec.SavingsPercentage = pricing.SavingsPercentage
}
Expand Down
9 changes: 8 additions & 1 deletion providers/gcp/services/computeengine/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1342,12 +1342,19 @@ func TestConverterToInsert_CountNonZero_VCPUAmountSet(t *testing.T) {
func TestConverterFillsPricingForScorer(t *testing.T) {
ctx := context.Background()
client, _ := NewClient(ctx, "test-project", "us-central1")
client.SetBillingService(mockBillingWithCommitment())
billing := mockBillingWithCommitment()
for _, sku := range billing.skus.Skus {
sku.PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.CurrencyCode = "EUR"
}
client.SetBillingService(billing)

gcpRec := realisticCUDRecommendation()
gcpRec.PrimaryImpact.GetCostProjection().Cost.CurrencyCode = "JPY"
rec, err := client.convertGCPRecommendation(ctx, gcpRec, common.RecommendationParams{})
require.NoError(t, err)
require.NotNil(t, rec)
assert.Equal(t, "EUR", rec.CommitmentCurrency)
assert.Equal(t, float64(200), rec.EstimatedSavings)

// C2: SavingsPercentage must be > 0 so a MinSavingsPct filter doesn't silently drop the rec.
require.Greater(t, rec.SavingsPercentage, float64(0),
Expand Down
19 changes: 19 additions & 0 deletions providers/gcp/services/computeengine/pricing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,28 @@ func TestEnrichRecWithPricing_MonthlyFiguresPerTerm(t *testing.T) {
client.enrichRecWithPricing(ctx, &rec)

assert.Zero(t, rec.CommitmentCost)
assert.Equal(t, "USD", rec.CommitmentCurrency)
require.NotNil(t, rec.RecurringMonthlyCost)
assert.InDelta(t, tc.commitHourly*730, *rec.RecurringMonthlyCost, 1e-6)
assert.InDelta(t, tc.odHourly*730, rec.OnDemandCost, 1e-6, "OnDemandCost is the monthly on-demand price")
})
}
}

func TestEnrichRecWithPricing_InvalidCurrency(t *testing.T) {
for _, currency := range []string{"", "EUR"} {
t.Run("commitment currency "+currency, func(t *testing.T) {
ctx := context.Background()
client, err := NewClient(ctx, "test-project", "us-central1")
require.NoError(t, err)
skus := n2AmericasSKUs()
skus[2].PricingInfo[0].PricingExpression.TieredRates[0].UnitPrice.CurrencyCode = currency
client.SetBillingService(&MockBillingService{skus: &cloudbilling.ListSkusResponse{Skus: skus}})
rec := newRec("n2-standard-4", 4, 16)
rec.Term = "1yr"
client.enrichRecWithPricing(ctx, &rec)
assert.Empty(t, rec.CommitmentCurrency)
assert.Nil(t, rec.RecurringMonthlyCost)
})
}
}
1 change: 1 addition & 0 deletions providers/gcp/services/memorystore/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ func (c *Client) fillRedisPricing(ctx context.Context, rec *common.Recommendatio
if pricing.CommitmentPrice > 0 {
monthly := pricing.CommitmentPrice / float64(termYears*12)
rec.RecurringMonthlyCost = &monthly
rec.CommitmentCurrency = pricing.Currency
}
rec.OnDemandCost = pricing.OnDemandPrice
rec.SavingsPercentage = pricing.SavingsPercentage
Expand Down
15 changes: 13 additions & 2 deletions providers/gcp/services/memorystore/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/require"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/iterator"
"google.golang.org/genproto/googleapis/type/money"

"github.com/LeanerCloud/cloud-commitments-go/pkg/common"
"github.com/LeanerCloud/cloud-commitments-go/pkg/reporter"
Expand Down Expand Up @@ -837,7 +838,7 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test
UnitPrice: &cloudbilling.Money{
Units: 0,
Nanos: int64(onDemandHourly * 1e9),
CurrencyCode: "USD",
CurrencyCode: "EUR",
},
},
},
Expand All @@ -859,7 +860,7 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test
UnitPrice: &cloudbilling.Money{
Units: 0,
Nanos: int64(commitmentHourly * 1e9),
CurrencyCode: "USD",
CurrencyCode: "EUR",
},
},
},
Expand All @@ -874,6 +875,11 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test

gcpRec := &recommenderpb.Recommendation{
Name: "test-rec",
PrimaryImpact: &recommenderpb.Impact{
Projection: &recommenderpb.Impact_CostProjection{
CostProjection: &recommenderpb.CostProjection{Cost: &money.Money{Units: -100, CurrencyCode: "JPY"}},
},
},
Content: &recommenderpb.RecommendationContent{
OperationGroups: []*recommenderpb.OperationGroup{
{
Expand All @@ -891,6 +897,8 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test
rec := client.convertGCPRecommendation(ctx, gcpRec, common.RecommendationParams{Term: term, PaymentOption: payment})
rec.Count = 3
rec.AccountName = "fixture"
assert.Equal(t, "EUR", rec.CommitmentCurrency)
assert.Equal(t, float64(100), rec.EstimatedSavings)
require.NotNil(t, rec.RecurringMonthlyCost)
assert.Zero(t, rec.CommitmentCost)
assert.InDelta(t, 100, *rec.RecurringMonthlyCost, 0.00001)
Expand All @@ -907,6 +915,7 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test
scaled, err := common.ResizeCount(*rec, 2)
require.NoError(t, err)
assert.Equal(t, 2, scaled.Count)
assert.Equal(t, "EUR", scaled.CommitmentCurrency)
assert.InDelta(t, 800*months/12, scaled.CommitmentCost+*scaled.RecurringMonthlyCost*months, 0.0001)
assert.InDelta(t, 100, *rec.RecurringMonthlyCost, 0.00001)
quote, err := client.GetOfferingDetails(ctx, *rec)
Expand All @@ -923,6 +932,7 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost(t *test
assert.Zero(t, rec.CommitmentCost)
assert.Zero(t, rec.BreakEvenMonths)
assert.Nil(t, rec.RecurringMonthlyCost)
assert.Empty(t, rec.CommitmentCurrency)
})
}

Expand Down Expand Up @@ -950,6 +960,7 @@ func TestMemorystoreClient_ConvertGCPRecommendation_RecurringMonthlyCost_Billing
assert.Zero(t, rec.CommitmentCost)
assert.Zero(t, rec.BreakEvenMonths)
assert.Nil(t, rec.RecurringMonthlyCost)
assert.Empty(t, rec.CommitmentCurrency)
})
}
}
8 changes: 8 additions & 0 deletions providers/gcp/services/memorystore/pricing_currency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/api/cloudbilling/v1"

"github.com/LeanerCloud/cloud-commitments-go/pkg/common"
)

func currencySKU(id, description, usageType, region, currency string, nanos int64) *cloudbilling.Sku {
Expand Down Expand Up @@ -51,13 +53,19 @@ func TestGetRedisPricing_Currency(t *testing.T) {
}}})

got, err := client.getRedisPricing(ctx, tier, region, 1)
rec := common.Recommendation{ResourceType: tier, Term: "1yr"}
client.fillRedisPricing(ctx, &rec, 1)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
assert.Empty(t, rec.CommitmentCurrency)
assert.Nil(t, rec.RecurringMonthlyCost)
return
}
require.NoError(t, err)
assert.Equal(t, tt.wantCurrency, got.Currency)
assert.Equal(t, tt.wantCurrency, rec.CommitmentCurrency)
require.NotNil(t, rec.RecurringMonthlyCost)
})
}
}
Loading