From 5de4e1c0a9f90c18e1cf3951f81044a8cf740d2f Mon Sep 17 00:00:00 2001 From: Astrid Gealer Date: Mon, 26 Oct 2026 19:22:39 +0000 Subject: [PATCH] chore: drop duplicate --max-list check and local Azure HTTP mocks The sanity binary validated --max-list twice: once through requireInt32Range and again inline in main(). Remove the inline copy, have the helper compare against math.MaxInt32 instead of 1<<31-1, and split the check into validateInt32Range so it is unit-testable. The error message now keeps the bound and offending value the inline copy used to print. The cache, cosmosdb, database and search client tests declared their own MockHTTPClient and createMockHTTPResponse. Delete those copies and use mocks.MockHTTPClient and mocks.CreateMockHTTPResponse from providers/azure/mocks, as compute, managedredis and synapse already do. Closes #644 Co-Authored-By: Claude Opus 5.5 --- ci_cd_sanity_tests/cmd/sanity/main.go | 17 ++- ci_cd_sanity_tests/cmd/sanity/main_test.go | 40 ++++++ providers/azure/services/cache/client_test.go | 95 +++++-------- .../azure/services/cosmosdb/client_test.go | 113 +++++++--------- .../azure/services/database/client_test.go | 119 +++++++--------- .../azure/services/search/client_test.go | 127 ++++++++---------- 6 files changed, 235 insertions(+), 276 deletions(-) create mode 100644 ci_cd_sanity_tests/cmd/sanity/main_test.go diff --git a/ci_cd_sanity_tests/cmd/sanity/main.go b/ci_cd_sanity_tests/cmd/sanity/main.go index 3249a3c2..f6ecf0ca 100644 --- a/ci_cd_sanity_tests/cmd/sanity/main.go +++ b/ci_cd_sanity_tests/cmd/sanity/main.go @@ -11,10 +11,18 @@ import ( "github.com/LeanerCloud/cloud-commitments-go/ci_cd_sanity_tests/pkg/sanity/aws" ) +// validateInt32Range reports an error when n is outside [1, math.MaxInt32]. +func validateInt32Range(flagName string, n int) error { + if n < 1 || n > math.MaxInt32 { + return fmt.Errorf("%s must be between 1 and %d, got %d", flagName, math.MaxInt32, n) + } + return nil +} + // requireInt32Range exits with an error when n is outside [1, math.MaxInt32]. func requireInt32Range(flagName string, n int) { - if n < 1 || n > (1<<31-1) { - fmt.Fprintf(os.Stderr, "ERROR: %s must be between 1 and math.MaxInt32\n", flagName) + if err := validateInt32Range(flagName, n); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) os.Exit(2) } } @@ -29,11 +37,6 @@ func main() { flag.Parse() requireInt32Range("--max-list", *maxList) - if *maxList < 1 || *maxList > math.MaxInt32 { - fmt.Fprintf(os.Stderr, "ERROR: --max-list must be between 1 and %d, got %d\n", math.MaxInt32, *maxList) - os.Exit(2) - } - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) rep, err := aws.Run(ctx, aws.Options{ diff --git a/ci_cd_sanity_tests/cmd/sanity/main_test.go b/ci_cd_sanity_tests/cmd/sanity/main_test.go new file mode 100644 index 00000000..158112f3 --- /dev/null +++ b/ci_cd_sanity_tests/cmd/sanity/main_test.go @@ -0,0 +1,40 @@ +package main + +import ( + "math" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateInt32Range(t *testing.T) { + // Computed at run time so the test still compiles where int is 32 bits; + // there it wraps to math.MinInt32, which is rejected as well. + aboveMax := math.MaxInt32 + aboveMax++ + + tests := []struct { + name string + n int + wantErr bool + }{ + {name: "zero", n: 0, wantErr: true}, + {name: "negative", n: -1, wantErr: true}, + {name: "lower bound", n: 1, wantErr: false}, + {name: "default", n: 5, wantErr: false}, + {name: "upper bound", n: math.MaxInt32, wantErr: false}, + {name: "above upper bound", n: aboveMax, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateInt32Range("--max-list", tt.n) + if !tt.wantErr { + assert.NoError(t, err) + return + } + require.Error(t, err) + assert.Contains(t, err.Error(), "--max-list must be between 1 and 2147483647") + }) + } +} diff --git a/providers/azure/services/cache/client_test.go b/providers/azure/services/cache/client_test.go index d4c7ee21..29941057 100644 --- a/providers/azure/services/cache/client_test.go +++ b/providers/azure/services/cache/client_test.go @@ -90,27 +90,6 @@ func (m *MockRedisCachesPager) NextPage(ctx context.Context) (armredis.ClientLis return page, nil } -// MockHTTPClient mocks HTTP client for testing. -type MockHTTPClient struct { - mock.Mock -} - -func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { - args := m.Called(req) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*http.Response), args.Error(1) -} - -func createMockHTTPResponse(statusCode int, body string) *http.Response { - return &http.Response{ - StatusCode: statusCode, - Body: io.NopCloser(bytes.NewBufferString(body)), - Header: make(http.Header), - } -} - func createSampleRedisPricingResponse() string { return `{ "Items": [ @@ -273,7 +252,7 @@ func TestRedisPricingStructure(t *testing.T) { func TestNewClientWithHTTP(t *testing.T) { t.Parallel() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) require.NotNil(t, client) @@ -285,10 +264,10 @@ func TestNewClientWithHTTP(t *testing.T) { func TestCacheClient_GetOfferingDetails_WithMock(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response1 := createMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) + response1 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) t.Cleanup(func() { require.NoError(t, response1.Body.Close()) }) @@ -313,10 +292,10 @@ func TestCacheClient_GetOfferingDetails_WithMock(t *testing.T) { func TestCacheClient_GetOfferingDetails_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response2 := createMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) + response2 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) t.Cleanup(func() { require.NoError(t, response2.Body.Close()) }) @@ -340,10 +319,10 @@ func TestCacheClient_GetOfferingDetails_3YearTerm(t *testing.T) { func TestCacheClient_GetOfferingDetails_NoUpfront(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response3 := createMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) + response3 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleRedisPricingResponse()) t.Cleanup(func() { require.NoError(t, response3.Body.Close()) }) @@ -367,10 +346,10 @@ func TestCacheClient_GetOfferingDetails_NoUpfront(t *testing.T) { func TestCacheClient_GetOfferingDetails_APIError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response4 := createMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") + response4 := mocks.CreateMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") t.Cleanup(func() { require.NoError(t, response4.Body.Close()) }) @@ -392,10 +371,10 @@ func TestCacheClient_GetOfferingDetails_APIError(t *testing.T) { func TestCacheClient_GetOfferingDetails_NoPricing(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response5 := createMockHTTPResponse(http.StatusOK, `{"Items": []}`) + response5 := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items": []}`) t.Cleanup(func() { require.NoError(t, response5.Body.Close()) }) @@ -437,9 +416,9 @@ func TestCacheClient_GetOfferingDetails_NoReservationPricing(t *testing.T) { "NextPageLink": "" }` - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response6 := createMockHTTPResponse(http.StatusOK, onDemandOnly) + response6 := mocks.CreateMockHTTPResponse(http.StatusOK, onDemandOnly) t.Cleanup(func() { require.NoError(t, response6.Body.Close()) }) @@ -1090,18 +1069,18 @@ func calcPriceRespJSON(orderID string) string { func TestCacheClient_PurchaseCommitment_Success(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp7 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-001")) + calculateResp7 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-001")) t.Cleanup(func() { require.NoError(t, calculateResp7.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp7, nil).Once() - purchaseResp8 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp8 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp8.Body.Close()) }) @@ -1129,18 +1108,18 @@ func TestCacheClient_PurchaseCommitment_Success(t *testing.T) { func TestCacheClient_PurchaseCommitment_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp9 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-3yr")) + calculateResp9 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-3yr")) t.Cleanup(func() { require.NoError(t, calculateResp9.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp9, nil).Once() - purchaseResp10 := createMockHTTPResponse(http.StatusCreated, `{}`) + purchaseResp10 := mocks.CreateMockHTTPResponse(http.StatusCreated, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp10.Body.Close()) }) @@ -1166,18 +1145,18 @@ func TestCacheClient_PurchaseCommitment_3YearTerm(t *testing.T) { func TestCacheClient_PurchaseCommitment_Accepted(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp11 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-202")) + calculateResp11 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-202")) t.Cleanup(func() { require.NoError(t, calculateResp11.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp11, nil).Once() - purchaseResp12 := createMockHTTPResponse(http.StatusAccepted, `{}`) + purchaseResp12 := mocks.CreateMockHTTPResponse(http.StatusAccepted, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp12.Body.Close()) }) @@ -1202,7 +1181,7 @@ func TestCacheClient_PurchaseCommitment_Accepted(t *testing.T) { func TestCacheClient_PurchaseCommitment_TokenError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{err: errors.New("token error")} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1222,7 +1201,7 @@ func TestCacheClient_PurchaseCommitment_TokenError(t *testing.T) { func TestCacheClient_PurchaseCommitment_HTTPError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1246,18 +1225,18 @@ func TestCacheClient_PurchaseCommitment_HTTPError(t *testing.T) { func TestCacheClient_PurchaseCommitment_BadStatus(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp13 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-bad")) + calculateResp13 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cache-order-bad")) t.Cleanup(func() { require.NoError(t, calculateResp13.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp13, nil).Once() - purchaseResp14 := createMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) + purchaseResp14 := mocks.CreateMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) t.Cleanup(func() { require.NoError(t, purchaseResp14.Body.Close()) }) @@ -1291,12 +1270,12 @@ func TestCacheClient_PurchaseCommitment_TagInjection(t *testing.T) { const source = common.PurchaseSourceWeb ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) var capturedBody []byte - calculateResp15 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp15 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp15.Body.Close()) }) @@ -1308,7 +1287,7 @@ func TestCacheClient_PurchaseCommitment_TagInjection(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp15, nil).Once() - purchaseResp16 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp16 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp16.Body.Close()) }) @@ -1352,7 +1331,7 @@ func TestCacheClient_PurchaseCommitment_BillingPlan(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1369,7 +1348,7 @@ func TestCacheClient_PurchaseCommitment_BillingPlan(t *testing.T) { const orderID = "cache-billingplan-test" var capturedBody []byte - calculateResp17 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp17 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp17.Body.Close()) }) @@ -1381,7 +1360,7 @@ func TestCacheClient_PurchaseCommitment_BillingPlan(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp17, nil).Once() - purchaseResp18 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp18 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp18.Body.Close()) }) @@ -1418,7 +1397,7 @@ func TestCacheClient_PurchaseCommitment_BillingPlan(t *testing.T) { func TestCacheClient_PurchaseCommitment_RequiresSource(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1437,13 +1416,13 @@ func TestCacheClient_PurchaseCommitment_RequiresSource(t *testing.T) { func TestCacheClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const orderID = "azure-cache-displayname" var capturedDisplayName string - calculateResp19 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp19 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp19.Body.Close()) }) @@ -1466,7 +1445,7 @@ func TestCacheClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t *t } return true })).Return(calculateResp19, nil).Once() - purchaseResp20 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp20 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp20.Body.Close()) }) diff --git a/providers/azure/services/cosmosdb/client_test.go b/providers/azure/services/cosmosdb/client_test.go index 07e0cb58..06a846bf 100644 --- a/providers/azure/services/cosmosdb/client_test.go +++ b/providers/azure/services/cosmosdb/client_test.go @@ -101,27 +101,6 @@ func (m *MockCosmosAccountsPager) NextPage(ctx context.Context) (armcosmos.Datab return page, nil } -// MockHTTPClient mocks HTTP client for testing. -type MockHTTPClient struct { - mock.Mock -} - -func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { - args := m.Called(req) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*http.Response), args.Error(1) -} - -func createMockHTTPResponse(statusCode int, body string) *http.Response { - return &http.Response{ - StatusCode: statusCode, - Body: io.NopCloser(bytes.NewBufferString(body)), - Header: make(http.Header), - } -} - // Synthetic totals retained for existing quote tests; reservation identity follows the captured catalog. func createSampleCosmosPricingResponse() string { return `{ @@ -272,7 +251,7 @@ func TestNewClient(t *testing.T) { func TestNewClientWithHTTP(t *testing.T) { t.Parallel() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) require.NotNil(t, client) @@ -331,10 +310,10 @@ func TestCosmosDBClient_Fields(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_WithMock(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response1 := createMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) + response1 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response1.Body.Close()) }) @@ -359,10 +338,10 @@ func TestCosmosDBClient_GetOfferingDetails_WithMock(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response2 := createMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) + response2 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response2.Body.Close()) }) @@ -386,10 +365,10 @@ func TestCosmosDBClient_GetOfferingDetails_3YearTerm(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_NoUpfront(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response3 := createMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) + response3 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response3.Body.Close()) }) @@ -413,10 +392,10 @@ func TestCosmosDBClient_GetOfferingDetails_NoUpfront(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_APIError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response4 := createMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") + response4 := mocks.CreateMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") t.Cleanup(func() { require.NoError(t, response4.Body.Close()) }) @@ -438,10 +417,10 @@ func TestCosmosDBClient_GetOfferingDetails_APIError(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_NoPricing(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response5 := createMockHTTPResponse(http.StatusOK, `{"Items": []}`) + response5 := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items": []}`) t.Cleanup(func() { require.NoError(t, response5.Body.Close()) }) @@ -485,9 +464,9 @@ func TestCosmosDBClient_GetOfferingDetails_NoReservationPricing(t *testing.T) { "NextPageLink": "" }` - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response6 := createMockHTTPResponse(http.StatusOK, onDemandOnly) + response6 := mocks.CreateMockHTTPResponse(http.StatusOK, onDemandOnly) t.Cleanup(func() { require.NoError(t, response6.Body.Close()) }) @@ -511,10 +490,10 @@ func TestCosmosDBClient_GetOfferingDetails_NoReservationPricing(t *testing.T) { func TestCosmosDBClient_GetOfferingDetails_MixedSKUsPicksRequestedSKU(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response := createMockHTTPResponse(http.StatusOK, createMixedSKUCosmosPricingResponse()) + response := mocks.CreateMockHTTPResponse(http.StatusOK, createMixedSKUCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) @@ -541,10 +520,10 @@ func TestCosmosDBClient_GetOfferingDetails_MixedSKUsPicksRequestedSKU(t *testing func TestCosmosDBClient_GetOfferingDetails_NoMatchingSKU_FailsClosed(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response := createMockHTTPResponse(http.StatusOK, createOnlyOtherSKUCosmosPricingResponse()) + response := mocks.CreateMockHTTPResponse(http.StatusOK, createOnlyOtherSKUCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) @@ -567,10 +546,10 @@ func TestCosmosDBClient_GetOfferingDetails_NoMatchingSKU_FailsClosed(t *testing. func TestCosmosDBClient_GetOfferingDetails_RequestsSKUFilter(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response := createMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) + response := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleCosmosPricingResponse()) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) @@ -1077,18 +1056,18 @@ func calcPriceRespJSON(orderID string) string { func TestCosmosDBClient_PurchaseCommitment_Success(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp7 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-001")) + calculateResp7 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-001")) t.Cleanup(func() { require.NoError(t, calculateResp7.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp7, nil).Once() - purchaseResp8 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp8 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp8.Body.Close()) }) @@ -1116,18 +1095,18 @@ func TestCosmosDBClient_PurchaseCommitment_Success(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp9 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-3yr")) + calculateResp9 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-3yr")) t.Cleanup(func() { require.NoError(t, calculateResp9.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp9, nil).Once() - purchaseResp10 := createMockHTTPResponse(http.StatusCreated, `{}`) + purchaseResp10 := mocks.CreateMockHTTPResponse(http.StatusCreated, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp10.Body.Close()) }) @@ -1153,18 +1132,18 @@ func TestCosmosDBClient_PurchaseCommitment_3YearTerm(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_Accepted(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp11 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-202")) + calculateResp11 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-202")) t.Cleanup(func() { require.NoError(t, calculateResp11.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp11, nil).Once() - purchaseResp12 := createMockHTTPResponse(http.StatusAccepted, `{}`) + purchaseResp12 := mocks.CreateMockHTTPResponse(http.StatusAccepted, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp12.Body.Close()) }) @@ -1189,7 +1168,7 @@ func TestCosmosDBClient_PurchaseCommitment_Accepted(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_TokenError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{err: errors.New("token error")} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1209,7 +1188,7 @@ func TestCosmosDBClient_PurchaseCommitment_TokenError(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_HTTPError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1233,18 +1212,18 @@ func TestCosmosDBClient_PurchaseCommitment_HTTPError(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_BadStatus(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp13 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-bad")) + calculateResp13 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("cosmos-order-bad")) t.Cleanup(func() { require.NoError(t, calculateResp13.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp13, nil).Once() - purchaseResp14 := createMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) + purchaseResp14 := mocks.CreateMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) t.Cleanup(func() { require.NoError(t, purchaseResp14.Body.Close()) }) @@ -1278,12 +1257,12 @@ func TestCosmosDBClient_PurchaseCommitment_TagInjection(t *testing.T) { const source = common.PurchaseSourceWeb ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) var capturedBody []byte - calculateResp15 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp15 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp15.Body.Close()) }) @@ -1295,7 +1274,7 @@ func TestCosmosDBClient_PurchaseCommitment_TagInjection(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp15, nil).Once() - purchaseResp16 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp16 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp16.Body.Close()) }) @@ -1339,7 +1318,7 @@ func TestCosmosDBClient_PurchaseCommitment_BillingPlan(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1356,7 +1335,7 @@ func TestCosmosDBClient_PurchaseCommitment_BillingPlan(t *testing.T) { const orderID = "cosmos-billingplan-test" var capturedBody []byte - calculateResp17 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp17 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp17.Body.Close()) }) @@ -1368,7 +1347,7 @@ func TestCosmosDBClient_PurchaseCommitment_BillingPlan(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp17, nil).Once() - purchaseResp18 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp18 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp18.Body.Close()) }) @@ -1405,7 +1384,7 @@ func TestCosmosDBClient_PurchaseCommitment_BillingPlan(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_RequiresSource(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1682,13 +1661,13 @@ func TestDetailsFromCosmosSKU(t *testing.T) { func TestCosmosDBClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const orderID = "azure-cosmos-displayname" var capturedDisplayName string - calculateResp19 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp19 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp19.Body.Close()) }) @@ -1711,7 +1690,7 @@ func TestCosmosDBClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t } return true })).Return(calculateResp19, nil).Once() - purchaseResp20 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp20 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp20.Body.Close()) }) @@ -1771,7 +1750,7 @@ func TestNewClientWithHTTP_NilFallbackIsHardened(t *testing.T) { func TestGetCosmosPricing_RejectsInjectedSKU(t *testing.T) { t.Parallel() - client := NewClientWithHTTP(nil, "sub", "eastus", &MockHTTPClient{}) + client := NewClientWithHTTP(nil, "sub", "eastus", &mocks.MockHTTPClient{}) _, err := client.getCosmosPricing(context.Background(), "Cosmos_DB_x' or armSkuName ne '", "eastus", 1) require.Error(t, err) assert.Contains(t, err.Error(), "Retail Prices filter") @@ -1779,9 +1758,9 @@ func TestGetCosmosPricing_RejectsInjectedSKU(t *testing.T) { func TestGetCosmosPricing_LegitimateSKUBuildsExactFilter(t *testing.T) { t.Parallel() - response := createMockHTTPResponse(http.StatusOK, `{"Items":[]}`) + response := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items":[]}`) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.Anything).Return(response, nil).Once() _, err := NewClientWithHTTP(nil, "sub", "eastus", mockHTTP).getCosmosPricing(context.Background(), "100RU", "eastus", 1) require.Error(t, err) diff --git a/providers/azure/services/database/client_test.go b/providers/azure/services/database/client_test.go index 9d7c5a29..bbf7ee93 100644 --- a/providers/azure/services/database/client_test.go +++ b/providers/azure/services/database/client_test.go @@ -83,27 +83,6 @@ func (m *MockCapabilitiesClient) ListByLocation(ctx context.Context, locationNam return m.response, nil } -// MockHTTPClient mocks HTTP client for testing. -type MockHTTPClient struct { - mock.Mock -} - -func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { - args := m.Called(req) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*http.Response), args.Error(1) -} - -func createMockHTTPResponse(statusCode int, body string) *http.Response { - return &http.Response{ - StatusCode: statusCode, - Body: io.NopCloser(bytes.NewBufferString(body)), - Header: make(http.Header), - } -} - // This vCore catalog row is synthetic; it tests selection, not live SKU availability. func createSampleSQLPricingResponse() string { return `{ @@ -243,7 +222,7 @@ func TestDatabaseClient_Fields(t *testing.T) { func TestNewClientWithHTTP(t *testing.T) { t.Parallel() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) require.NotNil(t, client) @@ -255,10 +234,10 @@ func TestNewClientWithHTTP(t *testing.T) { func TestDatabaseClient_GetOfferingDetails_WithMock(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response1 := createMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) + response1 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) t.Cleanup(func() { require.NoError(t, response1.Body.Close()) }) @@ -288,10 +267,10 @@ func TestDatabaseClient_GetOfferingDetails_WithMock(t *testing.T) { func TestDatabaseClient_GetOfferingDetails_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response2 := createMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) + response2 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) t.Cleanup(func() { require.NoError(t, response2.Body.Close()) }) @@ -319,10 +298,10 @@ func TestDatabaseClient_GetOfferingDetails_3YearTerm(t *testing.T) { func TestDatabaseClient_GetOfferingDetails_NoUpfront(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response3 := createMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) + response3 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSQLPricingResponse()) t.Cleanup(func() { require.NoError(t, response3.Body.Close()) }) @@ -347,10 +326,10 @@ func TestDatabaseClient_GetOfferingDetails_NoUpfront(t *testing.T) { func TestDatabaseClient_GetOfferingDetails_APIError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response4 := createMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") + response4 := mocks.CreateMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") t.Cleanup(func() { require.NoError(t, response4.Body.Close()) }) @@ -372,10 +351,10 @@ func TestDatabaseClient_GetOfferingDetails_APIError(t *testing.T) { func TestDatabaseClient_GetOfferingDetails_NoPricing(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response5 := createMockHTTPResponse(http.StatusOK, `{"Items": []}`) + response5 := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items": []}`) t.Cleanup(func() { require.NoError(t, response5.Body.Close()) }) @@ -417,9 +396,9 @@ func TestDatabaseClient_GetOfferingDetails_NoReservationPricing(t *testing.T) { "NextPageLink": "" }` - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response6 := createMockHTTPResponse(http.StatusOK, onDemandOnly) + response6 := mocks.CreateMockHTTPResponse(http.StatusOK, onDemandOnly) t.Cleanup(func() { require.NoError(t, response6.Body.Close()) }) @@ -519,8 +498,8 @@ func TestDatabaseClient_GetOfferingDetails_SelectsSyntheticVCoreRow(t *testing.T t.Run(tt.name, func(t *testing.T) { body, err := json.Marshal(AzureRetailPrice{Items: tt.items}) require.NoError(t, err) - mockHTTP := &MockHTTPClient{} - response := createMockHTTPResponse(http.StatusOK, string(body)) + mockHTTP := &mocks.MockHTTPClient{} + response := mocks.CreateMockHTTPResponse(http.StatusOK, string(body)) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) @@ -572,7 +551,7 @@ func TestDatabaseClient_GetOfferingDetails_RejectsQuoteInRegionAndSKU(t *testing t.Parallel() // Quote characters are rejected outright (not escaped); the mock has no // expectations, so any request would panic. - client := NewClientWithHTTP(nil, "sub", "east'us", &MockHTTPClient{}) + client := NewClientWithHTTP(nil, "sub", "east'us", &mocks.MockHTTPClient{}) details, err := client.GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: "GeneralPurpose_Gen5_'2", Term: "1yr", PaymentOption: "upfront", }) @@ -606,12 +585,12 @@ func TestDatabaseClient_GetOfferingDetails_ReservationAcrossPages(t *testing.T) require.NoError(t, err) secondBody, err := json.Marshal(AzureRetailPrice{Items: []azpricing.RetailPriceItem{tt.second}}) require.NoError(t, err) - mockHTTP := &MockHTTPClient{} - firstResponse := createMockHTTPResponse(http.StatusOK, string(firstBody)) + mockHTTP := &mocks.MockHTTPClient{} + firstResponse := mocks.CreateMockHTTPResponse(http.StatusOK, string(firstBody)) t.Cleanup(func() { require.NoError(t, firstResponse.Body.Close()) }) - secondResponse := createMockHTTPResponse(http.StatusOK, string(secondBody)) + secondResponse := mocks.CreateMockHTTPResponse(http.StatusOK, string(secondBody)) t.Cleanup(func() { require.NoError(t, secondResponse.Body.Close()) }) @@ -1182,18 +1161,18 @@ func calcPriceRespJSON(orderID string) string { func TestDatabaseClient_PurchaseCommitment_Success(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp7 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-001")) + calculateResp7 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-001")) t.Cleanup(func() { require.NoError(t, calculateResp7.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp7, nil).Once() - purchaseResp8 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp8 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp8.Body.Close()) }) @@ -1221,18 +1200,18 @@ func TestDatabaseClient_PurchaseCommitment_Success(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp9 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-3yr")) + calculateResp9 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-3yr")) t.Cleanup(func() { require.NoError(t, calculateResp9.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp9, nil).Once() - purchaseResp10 := createMockHTTPResponse(http.StatusCreated, `{}`) + purchaseResp10 := mocks.CreateMockHTTPResponse(http.StatusCreated, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp10.Body.Close()) }) @@ -1258,18 +1237,18 @@ func TestDatabaseClient_PurchaseCommitment_3YearTerm(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_Accepted(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp11 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-202")) + calculateResp11 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-202")) t.Cleanup(func() { require.NoError(t, calculateResp11.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp11, nil).Once() - purchaseResp12 := createMockHTTPResponse(http.StatusAccepted, `{}`) + purchaseResp12 := mocks.CreateMockHTTPResponse(http.StatusAccepted, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp12.Body.Close()) }) @@ -1294,7 +1273,7 @@ func TestDatabaseClient_PurchaseCommitment_Accepted(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_TokenError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{err: errors.New("token error")} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1314,7 +1293,7 @@ func TestDatabaseClient_PurchaseCommitment_TokenError(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_HTTPError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1338,18 +1317,18 @@ func TestDatabaseClient_PurchaseCommitment_HTTPError(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_BadStatus(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp13 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-bad")) + calculateResp13 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("db-order-bad")) t.Cleanup(func() { require.NoError(t, calculateResp13.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp13, nil).Once() - purchaseResp14 := createMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) + purchaseResp14 := mocks.CreateMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) t.Cleanup(func() { require.NoError(t, purchaseResp14.Body.Close()) }) @@ -1383,12 +1362,12 @@ func TestDatabaseClient_PurchaseCommitment_TagInjection(t *testing.T) { const source = common.PurchaseSourceWeb ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) var capturedBody []byte - calculateResp15 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp15 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp15.Body.Close()) }) @@ -1400,7 +1379,7 @@ func TestDatabaseClient_PurchaseCommitment_TagInjection(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp15, nil).Once() - purchaseResp16 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp16 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp16.Body.Close()) }) @@ -1443,7 +1422,7 @@ func TestDatabaseClient_PurchaseCommitment_BillingPlan(t *testing.T) { } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1460,7 +1439,7 @@ func TestDatabaseClient_PurchaseCommitment_BillingPlan(t *testing.T) { const orderID = "db-billingplan-test" var capturedBody []byte - calculateResp17 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp17 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp17.Body.Close()) }) @@ -1472,7 +1451,7 @@ func TestDatabaseClient_PurchaseCommitment_BillingPlan(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp17, nil).Once() - purchaseResp18 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp18 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp18.Body.Close()) }) @@ -1509,7 +1488,7 @@ func TestDatabaseClient_PurchaseCommitment_BillingPlan(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_RequiresSource(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1636,13 +1615,13 @@ func TestDatabaseClient_ValidateOffering_CaseInsensitive(t *testing.T) { func TestDatabaseClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const orderID = "azure-db-displayname" var capturedDisplayName string - calculateResp19 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp19 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp19.Body.Close()) }) @@ -1665,7 +1644,7 @@ func TestDatabaseClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t } return true })).Return(calculateResp19, nil).Once() - purchaseResp20 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp20 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp20.Body.Close()) }) @@ -1698,13 +1677,13 @@ func TestDatabaseClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t func TestDatabaseClient_PurchaseCommitment_CanonicalReservedResourceType(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const orderID = "azure-db-rrt" var capturedRRT string - calculateResp21 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp21 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp21.Body.Close()) }) @@ -1727,7 +1706,7 @@ func TestDatabaseClient_PurchaseCommitment_CanonicalReservedResourceType(t *test } return true })).Return(calculateResp21, nil).Once() - purchaseResp22 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp22 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp22.Body.Close()) }) @@ -2162,7 +2141,7 @@ func TestGetSQLPricing_RejectsInjectedFilterValues(t *testing.T) { {"region", "GP_Gen5_2", "eastus' or '1' eq '1"}, } { t.Run(tc.name, func(t *testing.T) { - client := NewClientWithHTTP(nil, "test-subscription", "eastus", &MockHTTPClient{}) + client := NewClientWithHTTP(nil, "test-subscription", "eastus", &mocks.MockHTTPClient{}) _, err := client.getSQLPricing(context.Background(), tc.sku, tc.region, 1) require.Error(t, err) assert.Contains(t, err.Error(), "Retail Prices filter") @@ -2180,8 +2159,8 @@ func TestDatabaseClient_GetOfferingDetails_ExactReservationFilter(t *testing.T) } body, err := json.Marshal(AzureRetailPrice{Items: []azpricing.RetailPriceItem{row}}) require.NoError(t, err) - mockHTTP := &MockHTTPClient{} - response := createMockHTTPResponse(http.StatusOK, string(body)) + mockHTTP := &mocks.MockHTTPClient{} + response := mocks.CreateMockHTTPResponse(http.StatusOK, string(body)) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) diff --git a/providers/azure/services/search/client_test.go b/providers/azure/services/search/client_test.go index f9dd6b42..cfda5ecd 100644 --- a/providers/azure/services/search/client_test.go +++ b/providers/azure/services/search/client_test.go @@ -88,27 +88,6 @@ func (m *MockSearchServicesPager) NextPage(ctx context.Context) (armsearch.Servi return page, nil } -// MockHTTPClient mocks HTTP client for testing. -type MockHTTPClient struct { - mock.Mock -} - -func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { - args := m.Called(req) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*http.Response), args.Error(1) -} - -func createMockHTTPResponse(statusCode int, body string) *http.Response { - return &http.Response{ - StatusCode: statusCode, - Body: io.NopCloser(bytes.NewBufferString(body)), - Header: make(http.Header), - } -} - // createSampleSearchPricingResponse is synthetic; the captured eastus catalog has no Reservation rows. func createSampleSearchPricingResponse() string { return `{ @@ -164,7 +143,7 @@ func TestNewClient(t *testing.T) { func TestNewClientWithHTTP(t *testing.T) { t.Parallel() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) require.NotNil(t, client) @@ -223,10 +202,10 @@ func TestSearchClient_Fields(t *testing.T) { func TestSearchClient_GetOfferingDetails_WithMock(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response1 := createMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) + response1 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) t.Cleanup(func() { require.NoError(t, response1.Body.Close()) }) @@ -253,10 +232,10 @@ func TestSearchClient_GetOfferingDetails_WithMock(t *testing.T) { func TestSearchClient_GetOfferingDetails_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response2 := createMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) + response2 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) t.Cleanup(func() { require.NoError(t, response2.Body.Close()) }) @@ -283,10 +262,10 @@ func TestSearchClient_GetOfferingDetails_3YearTerm(t *testing.T) { func TestSearchClient_GetOfferingDetails_NoUpfront(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response3 := createMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) + response3 := mocks.CreateMockHTTPResponse(http.StatusOK, createSampleSearchPricingResponse()) t.Cleanup(func() { require.NoError(t, response3.Body.Close()) }) @@ -310,10 +289,10 @@ func TestSearchClient_GetOfferingDetails_NoUpfront(t *testing.T) { func TestSearchClient_GetOfferingDetails_APIError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response4 := createMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") + response4 := mocks.CreateMockHTTPResponse(http.StatusInternalServerError, "Internal Server Error") t.Cleanup(func() { require.NoError(t, response4.Body.Close()) }) @@ -335,10 +314,10 @@ func TestSearchClient_GetOfferingDetails_APIError(t *testing.T) { func TestSearchClient_GetOfferingDetails_NoPricing(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response5 := createMockHTTPResponse(http.StatusOK, `{"Items": []}`) + response5 := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items": []}`) t.Cleanup(func() { require.NoError(t, response5.Body.Close()) }) @@ -378,9 +357,9 @@ func TestSearchClient_GetOfferingDetails_NoReservationPricing(t *testing.T) { ] }` - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} client := NewClientWithHTTP(nil, "test-subscription", "eastus", mockHTTP) - response6 := createMockHTTPResponse(http.StatusOK, onDemandOnly) + response6 := mocks.CreateMockHTTPResponse(http.StatusOK, onDemandOnly) t.Cleanup(func() { require.NoError(t, response6.Body.Close()) }) @@ -411,9 +390,9 @@ func TestSearchClient_GetOfferingDetails_SearchDisplaySKUs(t *testing.T) { "unitOfMeasure": "1 Hour", "retailPrice": 600, "currencyCode": "USD", }}}) require.NoError(t, err) - response := createMockHTTPResponse(http.StatusOK, string(body)) + response := mocks.CreateMockHTTPResponse(http.StatusOK, string(body)) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.Anything).Return(response, nil).Once() details, err := NewClientWithHTTP(nil, "sub", "eastus", mockHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: tc.sdk, Term: "1yr", PaymentOption: "upfront", @@ -449,9 +428,9 @@ func TestSearchClient_GetOfferingDetails_MixedTermsBothOrders(t *testing.T) { t.Run(tc.name, func(t *testing.T) { body, err := json.Marshal(AzureRetailPrice{Items: tc.items}) require.NoError(t, err) - response := createMockHTTPResponse(http.StatusOK, string(body)) + response := mocks.CreateMockHTTPResponse(http.StatusOK, string(body)) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.Anything).Return(response, nil).Once() details, err := NewClientWithHTTP(nil, "sub", "eastus", mockHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: "standard", Term: tc.term, PaymentOption: tc.payment, @@ -522,9 +501,9 @@ func TestSearchClient_GetOfferingDetails_ReservationSelection(t *testing.T) { t.Run(tc.name, func(t *testing.T) { body, err := json.Marshal(map[string]any{"Items": tc.items}) require.NoError(t, err) - response := createMockHTTPResponse(http.StatusOK, string(body)) + response := mocks.CreateMockHTTPResponse(http.StatusOK, string(body)) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.Anything).Return(response, nil).Once() details, err := NewClientWithHTTP(nil, "sub", "eastus", mockHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: "standard", Term: "1yr", PaymentOption: "all-upfront", Count: 3, @@ -569,13 +548,13 @@ func TestSearchClient_GetOfferingDetails_Pagination(t *testing.T) { require.NoError(t, err) secondBody, err := json.Marshal(AzureRetailPrice{Items: []pricing.RetailPriceItem{tc.second}}) require.NoError(t, err) - firstResponse := createMockHTTPResponse(http.StatusOK, string(firstBody)) - secondResponse := createMockHTTPResponse(http.StatusOK, string(secondBody)) + firstResponse := mocks.CreateMockHTTPResponse(http.StatusOK, string(firstBody)) + secondResponse := mocks.CreateMockHTTPResponse(http.StatusOK, string(secondBody)) t.Cleanup(func() { require.NoError(t, firstResponse.Body.Close()) require.NoError(t, secondResponse.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.MatchedBy(func(req *http.Request) bool { return req.URL.Query().Get("$skip") == "" })).Return(firstResponse, nil).Once() mockHTTP.On("Do", mock.MatchedBy(func(req *http.Request) bool { return req.URL.String() == nextURL })).Return(secondResponse, nil).Once() details, err := NewClientWithHTTP(nil, "sub", "eastus", mockHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ @@ -597,7 +576,7 @@ func TestSearchClient_GetOfferingDetails_Pagination(t *testing.T) { func TestGetSearchPricing_RejectsInjectedRegion(t *testing.T) { t.Parallel() - client := NewClientWithHTTP(nil, "sub", "eastus", &MockHTTPClient{}) + client := NewClientWithHTTP(nil, "sub", "eastus", &mocks.MockHTTPClient{}) _, err := client.getSearchPricing(context.Background(), "standard", "eastus' or '1' eq '1", 1) require.Error(t, err) assert.Contains(t, err.Error(), "Retail Prices filter") @@ -606,9 +585,9 @@ func TestGetSearchPricing_RejectsInjectedRegion(t *testing.T) { func TestSearchClient_GetOfferingDetails_BuildsExactFilterAndRejectsUnknownTier(t *testing.T) { t.Parallel() const region = "eastus" - response := createMockHTTPResponse(http.StatusOK, `{"Items":[{"serviceName":"Azure Cognitive Search","armRegionName":"eastus","skuName":"Standard S1","type":"Reservation","reservationTerm":"1 Year","unitOfMeasure":"1 Hour","retailPrice":800,"currencyCode":"USD"}]}`) + response := mocks.CreateMockHTTPResponse(http.StatusOK, `{"Items":[{"serviceName":"Azure Cognitive Search","armRegionName":"eastus","skuName":"Standard S1","type":"Reservation","reservationTerm":"1 Year","unitOfMeasure":"1 Hour","retailPrice":800,"currencyCode":"USD"}]}`) t.Cleanup(func() { require.NoError(t, response.Body.Close()) }) - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockHTTP.On("Do", mock.Anything).Return(response, nil).Once() details, err := NewClientWithHTTP(nil, "sub", region, mockHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: "standard", Term: "1yr", PaymentOption: "upfront", @@ -620,7 +599,7 @@ func TestSearchClient_GetOfferingDetails_BuildsExactFilterAndRejectsUnknownTier( assert.Contains(t, req.URL.RawQuery, "%24filter=") mockHTTP.AssertExpectations(t) - unknownHTTP := &MockHTTPClient{} + unknownHTTP := &mocks.MockHTTPClient{} _, err = NewClientWithHTTP(nil, "sub", "eastus", unknownHTTP).GetOfferingDetails(context.Background(), common.Recommendation{ ResourceType: "Standard_S1", Term: "1yr", PaymentOption: "upfront", }) @@ -1046,18 +1025,18 @@ func calcPriceRespJSON(orderID string) string { func TestSearchClient_PurchaseCommitment_Success(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp7 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-001")) + calculateResp7 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-001")) t.Cleanup(func() { require.NoError(t, calculateResp7.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp7, nil).Once() - purchaseResp8 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp8 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp8.Body.Close()) }) @@ -1085,18 +1064,18 @@ func TestSearchClient_PurchaseCommitment_Success(t *testing.T) { func TestSearchClient_PurchaseCommitment_3YearTerm(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp9 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-3yr")) + calculateResp9 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-3yr")) t.Cleanup(func() { require.NoError(t, calculateResp9.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp9, nil).Once() - purchaseResp10 := createMockHTTPResponse(http.StatusCreated, `{}`) + purchaseResp10 := mocks.CreateMockHTTPResponse(http.StatusCreated, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp10.Body.Close()) }) @@ -1122,18 +1101,18 @@ func TestSearchClient_PurchaseCommitment_3YearTerm(t *testing.T) { func TestSearchClient_PurchaseCommitment_Accepted(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp11 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-202")) + calculateResp11 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-202")) t.Cleanup(func() { require.NoError(t, calculateResp11.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp11, nil).Once() - purchaseResp12 := createMockHTTPResponse(http.StatusAccepted, `{}`) + purchaseResp12 := mocks.CreateMockHTTPResponse(http.StatusAccepted, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp12.Body.Close()) }) @@ -1158,7 +1137,7 @@ func TestSearchClient_PurchaseCommitment_Accepted(t *testing.T) { func TestSearchClient_PurchaseCommitment_TokenError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{err: errors.New("token error")} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1178,7 +1157,7 @@ func TestSearchClient_PurchaseCommitment_TokenError(t *testing.T) { func TestSearchClient_PurchaseCommitment_HTTPError(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1202,18 +1181,18 @@ func TestSearchClient_PurchaseCommitment_HTTPError(t *testing.T) { func TestSearchClient_PurchaseCommitment_BadStatus(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) - calculateResp13 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-bad")) + calculateResp13 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON("search-order-bad")) t.Cleanup(func() { require.NoError(t, calculateResp13.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp13, nil).Once() - purchaseResp14 := createMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) + purchaseResp14 := mocks.CreateMockHTTPResponse(http.StatusBadRequest, `{"error": "invalid request"}`) t.Cleanup(func() { require.NoError(t, purchaseResp14.Body.Close()) }) @@ -1301,20 +1280,20 @@ func TestSearchClient_ValidateOffering_Invalid(t *testing.T) { func TestSearchClient_PurchaseCommitment_TwoStepFlow(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const azureMintedOrderID = "azure-search-order-677" - calculateResp15 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(azureMintedOrderID)) + calculateResp15 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(azureMintedOrderID)) t.Cleanup(func() { require.NoError(t, calculateResp15.Body.Close()) }) mockHTTP.On("Do", mock.MatchedBy(func(r *http.Request) bool { return r.Method == http.MethodPost && r.URL.Path == "/providers/Microsoft.Capacity/calculatePrice" })).Return(calculateResp15, nil).Once() - purchaseResp16 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp16 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp16.Body.Close()) }) @@ -1351,12 +1330,12 @@ func TestSearchClient_PurchaseCommitment_TagInjection(t *testing.T) { const source = "cudly-web" ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) var capturedBody []byte - calculateResp17 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp17 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp17.Body.Close()) }) @@ -1368,7 +1347,7 @@ func TestSearchClient_PurchaseCommitment_TagInjection(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp17, nil).Once() - purchaseResp18 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp18 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp18.Body.Close()) }) @@ -1417,7 +1396,7 @@ func TestSearchClient_PurchaseCommitment_BillingPlan(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1434,7 +1413,7 @@ func TestSearchClient_PurchaseCommitment_BillingPlan(t *testing.T) { const orderID = "search-billingplan-test" var capturedBody []byte - calculateResp19 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp19 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp19.Body.Close()) }) @@ -1446,7 +1425,7 @@ func TestSearchClient_PurchaseCommitment_BillingPlan(t *testing.T) { r.Body = io.NopCloser(bytes.NewReader(capturedBody)) return true })).Return(calculateResp19, nil).Once() - purchaseResp20 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp20 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp20.Body.Close()) }) @@ -1483,7 +1462,7 @@ func TestSearchClient_PurchaseCommitment_BillingPlan(t *testing.T) { func TestSearchClient_PurchaseCommitment_RequiresSource(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) @@ -1537,13 +1516,13 @@ func TestSearchClient_ValidateOffering_CaseInsensitive(t *testing.T) { func TestSearchClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t *testing.T) { t.Parallel() ctx := context.Background() - mockHTTP := &MockHTTPClient{} + mockHTTP := &mocks.MockHTTPClient{} mockCred := &MockTokenCredential{token: "test-token"} client := NewClientWithHTTP(mockCred, "test-subscription", "eastus", mockHTTP) const orderID = "azure-search-displayname" var capturedDisplayName string - calculateResp21 := createMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) + calculateResp21 := mocks.CreateMockHTTPResponse(http.StatusOK, calcPriceRespJSON(orderID)) t.Cleanup(func() { require.NoError(t, calculateResp21.Body.Close()) }) @@ -1566,7 +1545,7 @@ func TestSearchClient_PurchaseCommitment_DisplayNameConformsToAzureAllowlist(t * } return true })).Return(calculateResp21, nil).Once() - purchaseResp22 := createMockHTTPResponse(http.StatusOK, `{}`) + purchaseResp22 := mocks.CreateMockHTTPResponse(http.StatusOK, `{}`) t.Cleanup(func() { require.NoError(t, purchaseResp22.Body.Close()) })