Repository navigation
fix(gcp): price 1-year and 3-year commitment SKUs separately #628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
29b9de4
fix(gcp): price 1-year and 3-year commitment SKUs separately
cristim 740263b
test(gcp): cover 3-year request against a 1-year-only catalog
cristim dd0e378
fix(gcp): reject unsupported commitment terms instead of pricing one …
cristim 5e9b9c9
Merge branch 'main' into fix/254-gcp-commit-term-slots
cristim File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package skumatch | ||
|
|
||
| import "fmt" | ||
|
|
||
| // TermYears parses a recommendation term label into commitment years. It | ||
| // accepts "1yr", "1" and "" (an unset term has always meant one year) for one | ||
| // year and "3yr", "3" for three. Anything else is an error: guessing a term | ||
| // would price the wrong commitment. | ||
| func TermYears(term string) (int, error) { | ||
| switch term { | ||
| case "", "1yr", "1": | ||
| return 1, nil | ||
| case "3yr", "3": | ||
| return 3, nil | ||
| } | ||
| return 0, fmt.Errorf("unsupported commitment term %q, want 1yr or 3yr", term) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package skumatch | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestTermYears(t *testing.T) { | ||
| for term, want := range map[string]int{"": 1, "1yr": 1, "1": 1, "3yr": 3, "3": 3} { | ||
| got, err := TermYears(term) | ||
| require.NoError(t, err, term) | ||
| assert.Equal(t, want, got, term) | ||
| } | ||
| for _, term := range []string{"2yr", "2", "5yr", "3yrs", "1Yr", " 3yr", "monthly"} { | ||
| _, err := TermYears(term) | ||
| require.Error(t, err, term) | ||
| assert.Contains(t, err.Error(), "unsupported commitment term") | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package cloudsql | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| "google.golang.org/api/cloudbilling/v1" | ||
|
|
||
| "github.com/LeanerCloud/cloud-commitments-go/pkg/common" | ||
| ) | ||
|
|
||
| // A catalog that only lists 1-year commitment SKUs must not price a 3-year | ||
| // request (#254): the missing term is an error, not a zero price. | ||
| func TestSQLClient_GetOfferingDetails_3yrWithOnly1yrCatalogErrors(t *testing.T) { | ||
| t.Parallel() | ||
| const region = "europe-west1" | ||
| ctx := context.Background() | ||
| client, _ := NewClient(ctx, "test-project", region) | ||
| client.SetBillingService(&MockBillingService{skus: &cloudbilling.ListSkusResponse{Skus: []*cloudbilling.Sku{ | ||
| currencySKU("od", "db-n1-standard-1 Cloud SQL", "OnDemand", region, "EUR", 200000000), | ||
| currencySKU("cud", "db-n1-standard-1 Cloud SQL commitment 1yr", "Commit1Yr", region, "EUR", 137000000), | ||
| }}}) | ||
|
|
||
| details, err := client.GetOfferingDetails(ctx, common.Recommendation{ResourceType: "db-n1-standard-1", Region: region, Term: "3yr", PaymentOption: "monthly"}) | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "no commitment pricing found") | ||
| assert.Nil(t, details) | ||
| } | ||
|
|
||
| // An unsupported term must error instead of being priced as one year (#254). | ||
| func TestSQLClient_GetOfferingDetails_UnsupportedTermErrors(t *testing.T) { | ||
| t.Parallel() | ||
| const region = "europe-west1" | ||
| ctx := context.Background() | ||
| client, _ := NewClient(ctx, "test-project", region) | ||
| client.SetBillingService(&MockBillingService{skus: &cloudbilling.ListSkusResponse{Skus: []*cloudbilling.Sku{ | ||
| currencySKU("od", "db-n1-standard-1 Cloud SQL", "OnDemand", region, "EUR", 200000000), | ||
| currencySKU("cud", "db-n1-standard-1 Cloud SQL commitment 1yr", "Commit1Yr", region, "EUR", 137000000), | ||
| currencySKU("cud-3y", "db-n1-standard-1 Cloud SQL commitment 3yr", "Commit3Yr", region, "EUR", 100000000), | ||
| }}}) | ||
|
|
||
| details, err := client.GetOfferingDetails(ctx, common.Recommendation{ResourceType: "db-n1-standard-1", Region: region, Term: "2yr", PaymentOption: "monthly"}) | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "unsupported commitment term") | ||
| assert.Nil(t, details) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package cloudsql | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| "google.golang.org/api/cloudbilling/v1" | ||
| ) | ||
|
|
||
| // TestExtractPricing_CommitmentTerm covers issue #254: 1-year and 3-year | ||
| // commitment SKUs priced differently must not be conflated. | ||
| func TestExtractPricing_CommitmentTerm(t *testing.T) { | ||
| const tier, region = "db-n1-standard-1", "europe-west4" | ||
| sku := func(id, usage string, nanos int64) *cloudbilling.Sku { | ||
| return currencySKU(id, "Cloud SQL for MySQL "+tier+" in "+region, usage, region, "USD", nanos) | ||
| } | ||
| od, y1, y3 := sku("od", "OnDemand", 50000000), sku("y1", "Commit1Yr", 40000000), sku("y3", "Commit3Yr", 30000000) | ||
| y1dup := sku("y1-dup", "Commit1Yr", 39000000) | ||
| orders := map[string][]*cloudbilling.Sku{"1yr first": {od, y1, y3}, "3yr first": {od, y3, y1}} | ||
|
|
||
| for order, skus := range orders { | ||
| for _, tc := range []struct { | ||
| term int | ||
| want float64 | ||
| }{{1, 0.04}, {3, 0.03}} { | ||
| t.Run(fmt.Sprintf("%s/%dyr", order, tc.term), func(t *testing.T) { | ||
| onDemand, commitment, _, err := extractSQLPricingFromSKUs(skus, tier, region, tc.term) | ||
| require.NoError(t, err) | ||
| assert.InDelta(t, 0.05, onDemand, 1e-12) | ||
| assert.InDelta(t, tc.want, commitment, 1e-12) | ||
| }) | ||
| } | ||
| } | ||
| t.Run("same-term duplicate at different prices is ambiguous", func(t *testing.T) { | ||
| _, _, _, err := extractSQLPricingFromSKUs([]*cloudbilling.Sku{od, y1, y3, y1dup}, tier, region, 1) | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "ambiguous catalog: 1-year commitment SKU y1-dup") | ||
| }) | ||
| t.Run("only the other term present yields no commitment", func(t *testing.T) { | ||
| _, commitment, _, err := extractSQLPricingFromSKUs([]*cloudbilling.Sku{od, y1}, tier, region, 3) | ||
| require.NoError(t, err) | ||
| assert.Zero(t, commitment) | ||
| }) | ||
| t.Run("unknown term is an error", func(t *testing.T) { | ||
| _, _, _, err := extractSQLPricingFromSKUs([]*cloudbilling.Sku{od, y1, y3}, tier, region, 2) | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "unsupported commitment term") | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.