From 13323520516989804511681942fbef684b77c43a Mon Sep 17 00:00:00 2001 From: HardingEthan15 Date: Wed, 17 Jun 2026 15:46:05 -0500 Subject: [PATCH 1/4] Added invalid parameter tests Signed-off-by: HardingEthan15 --- pkg/api/api.go | 13 +++ .../invalid_query_parameter_test.go | 89 +++++++++++++++++++ test/integration/api/allocation/test.bats | 5 ++ .../api/asset/invalid_query_parameter_test.go | 57 ++++++++++++ test/integration/api/asset/test.bats | 4 + 5 files changed, 168 insertions(+) create mode 100644 test/integration/api/allocation/invalid_query_parameter_test.go create mode 100644 test/integration/api/asset/invalid_query_parameter_test.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 49613a1..749246d 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -52,6 +52,19 @@ func decodeJSONResponse(url string, httpResp *http.Response, response interface{ } bodyStr := strings.TrimSpace(string(body)) + + // Handle Http errors (4xx and 5xx) + if httpResp.StatusCode >= 400 { + + retryable = isRetryableHTTPResponse(httpResp.StatusCode, bodyStr) + + return retryable, fmt.Errorf( + "HTTP %d: %s", + httpResp.StatusCode, + bodyStr, + ) + } + if err := json.Unmarshal(body, response); err != nil { retryable = isRetryableHTTPResponse(httpResp.StatusCode, bodyStr) log.Errorf( diff --git a/test/integration/api/allocation/invalid_query_parameter_test.go b/test/integration/api/allocation/invalid_query_parameter_test.go new file mode 100644 index 0000000..235aaee --- /dev/null +++ b/test/integration/api/allocation/invalid_query_parameter_test.go @@ -0,0 +1,89 @@ +package allocation + +// Validates that allocation api handles invalid parameters correctly. +// Passing Criteria: +// Returns a HTTP 400 error instead of a response with no error or an HTTP 500 error. + +import ( + "strings" + "testing" + + "github.com/opencost/opencost-integration-tests/pkg/api" +) + +func TestAllocationInvalidParameters(t *testing.T) { + apiObj := api.NewAPI() + + invalidWindowTestCases := []struct { + name string + window string + filter string + aggregate string + accumulate string + includeidle string + }{ + { + name: "ReverseWindow", + window: "2026-06-16T00:00:00Z,2026-06-15T00:00:00Z", + aggregate: "namespace", + }, + { + name: "InvalidWindowFormat", + window: "invalid-window-format", + aggregate: "namespace", + }, + { + name: "InvalidAggregate", + window: "24h", + aggregate: "invalid-aggregate", + accumulate: "true", + includeidle: "true", + }, + { + name: "InvalidFilter", + window: "24h", + filter: "invalid-filter", + accumulate: "true", + includeidle: "true", + aggregate: "namespace", + }, + { + name: "InvalidAccumulate", + window: "24h", + accumulate: "invalid-accumulate", + includeidle: "true", + aggregate: "namespace", + }, + { + name: "InvalidIncludeIdle", + window: "24h", + accumulate: "true", + includeidle: "invalid-include-idle", + aggregate: "namespace", + }, + } + + for _, tc := range invalidWindowTestCases { + t.Run(tc.name, func(t *testing.T) { + t.Logf("Testing: %s - %s", tc.name) + + _, err := apiObj.GetAllocation(api.AllocationRequest{ + Window: tc.window, + Filter: tc.filter, + Accumulate: tc.accumulate, + IncludeIdle: tc.includeidle, + Aggregate: tc.aggregate, + }) + + // Assert that an error was returned since input is invalid. + if err == nil { + t.Fatalf("Expected an error for invalid input, but got a successful response") + } + + // Assert that it is a 400 error. + if !strings.Contains(err.Error(), "HTTP 400") { + t.Fatalf("expected HTTP 400 error, got %v", err) + } + }) + } +} diff --git a/test/integration/api/allocation/test.bats b/test/integration/api/allocation/test.bats index 2d41bd7..9f5c736 100644 --- a/test/integration/api/allocation/test.bats +++ b/test/integration/api/allocation/test.bats @@ -6,6 +6,7 @@ setup() { teardown() { : # nothing to tear down } + @test "allocation: controller kind consistency" { go test allocation_controller_consistency_test.go } @@ -45,3 +46,7 @@ teardown() { @test "validate_api: validate if all of idle costs are spread" { go test share_idle_shares_test.go } + +@test "validate_api: validate api can handle invalid parameters" { + go test invalid_query_parameter_test.go +} diff --git a/test/integration/api/asset/invalid_query_parameter_test.go b/test/integration/api/asset/invalid_query_parameter_test.go new file mode 100644 index 0000000..d66406f --- /dev/null +++ b/test/integration/api/asset/invalid_query_parameter_test.go @@ -0,0 +1,57 @@ +package assets + +// Validates that assets api handles invalid parameters correctly. +// Passing Criteria: +// Returns a HTTP 400 error instead of a response with no error or an HTTP 500 error. + +import ( + "strings" + "testing" + + "github.com/opencost/opencost-integration-tests/pkg/api" +) + +func TestAllocationInvalidParameters(t *testing.T) { + apiObj := api.NewAPI() + + invalidWindowTestCases := []struct { + name string + window string + assetType string + }{ + { + name: "ReverseWindow", + window: "2026-06-16T00:00:00Z,2026-06-15T00:00:00Z", + assetType: "node", + }, + { + name: "InvalidWindowFormat", + window: "invalid-window-format", + assetType: "node", + }, + { + name: "InvalidFilter", + window: "24h", + assetType: "invalid-filter", + }, + } + + for _, tc := range invalidWindowTestCases { + t.Run(tc.name, func(t *testing.T) { + t.Logf("Testing: %s - %s", tc.name) + + _, err := apiObj.GetAssets(api.AssetsRequest{ + Window: tc.window, + Filter: tc.assetType, + }) + + if err == nil { + t.Fatalf("Expected an error for invalid input, but got a successful response") + } + + if !strings.Contains(err.Error(), "HTTP 400") { + t.Fatalf("expected HTTP 400 error, got %v", err) + } + }) + } +} diff --git a/test/integration/api/asset/test.bats b/test/integration/api/asset/test.bats index a642c16..f66f6f1 100644 --- a/test/integration/api/asset/test.bats +++ b/test/integration/api/asset/test.bats @@ -7,6 +7,10 @@ teardown() { : # nothing to tear down } +@test "asset: Invalid Parameters" { + go test invalid_query_parameter_test.go +} + @test "asset: Node Labels" { go test node_labels_test.go } From 1d75a0e7662a96d271b0d9ffb65253e77be176f1 Mon Sep 17 00:00:00 2001 From: HardingEthan15 Date: Wed, 17 Jun 2026 16:14:30 -0500 Subject: [PATCH 2/4] Fixed Syntax Errors Signed-off-by: HardingEthan15 --- test/integration/api/allocation/invalid_query_parameter_test.go | 2 +- test/integration/api/asset/invalid_query_parameter_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/api/allocation/invalid_query_parameter_test.go b/test/integration/api/allocation/invalid_query_parameter_test.go index 235aaee..6c71120 100644 --- a/test/integration/api/allocation/invalid_query_parameter_test.go +++ b/test/integration/api/allocation/invalid_query_parameter_test.go @@ -65,7 +65,7 @@ func TestAllocationInvalidParameters(t *testing.T) { for _, tc := range invalidWindowTestCases { t.Run(tc.name, func(t *testing.T) { - t.Logf("Testing: %s - %s", tc.name) + t.Logf("Testing: %s", tc.name) _, err := apiObj.GetAllocation(api.AllocationRequest{ Window: tc.window, diff --git a/test/integration/api/asset/invalid_query_parameter_test.go b/test/integration/api/asset/invalid_query_parameter_test.go index d66406f..5839c6f 100644 --- a/test/integration/api/asset/invalid_query_parameter_test.go +++ b/test/integration/api/asset/invalid_query_parameter_test.go @@ -38,7 +38,7 @@ func TestAllocationInvalidParameters(t *testing.T) { for _, tc := range invalidWindowTestCases { t.Run(tc.name, func(t *testing.T) { - t.Logf("Testing: %s - %s", tc.name) + t.Logf("Testing: %s", tc.name) _, err := apiObj.GetAssets(api.AssetsRequest{ Window: tc.window, From 1f7b7e1862f9a47ed8241fdff668768a3ce2d494 Mon Sep 17 00:00:00 2001 From: HardingEthan15 Date: Wed, 17 Jun 2026 16:16:03 -0500 Subject: [PATCH 3/4] Changed a name of a function to be more accurate Signed-off-by: HardingEthan15 --- test/integration/api/asset/invalid_query_parameter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/api/asset/invalid_query_parameter_test.go b/test/integration/api/asset/invalid_query_parameter_test.go index 5839c6f..951c87e 100644 --- a/test/integration/api/asset/invalid_query_parameter_test.go +++ b/test/integration/api/asset/invalid_query_parameter_test.go @@ -11,7 +11,7 @@ import ( "github.com/opencost/opencost-integration-tests/pkg/api" ) -func TestAllocationInvalidParameters(t *testing.T) { +func TestAssetInvalidParameters(t *testing.T) { apiObj := api.NewAPI() invalidWindowTestCases := []struct { From 52149e2e0b77bf7848536d08bf242012ec323028 Mon Sep 17 00:00:00 2001 From: HardingEthan15 Date: Wed, 17 Jun 2026 20:29:42 -0500 Subject: [PATCH 4/4] removed changes to api and fixed variable names Signed-off-by: HardingEthan15 --- pkg/api/api.go | 12 ------------ .../api/allocation/invalid_query_parameter_test.go | 4 ++-- .../api/asset/invalid_query_parameter_test.go | 4 ++-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 749246d..61d8c1c 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -53,18 +53,6 @@ func decodeJSONResponse(url string, httpResp *http.Response, response interface{ bodyStr := strings.TrimSpace(string(body)) - // Handle Http errors (4xx and 5xx) - if httpResp.StatusCode >= 400 { - - retryable = isRetryableHTTPResponse(httpResp.StatusCode, bodyStr) - - return retryable, fmt.Errorf( - "HTTP %d: %s", - httpResp.StatusCode, - bodyStr, - ) - } - if err := json.Unmarshal(body, response); err != nil { retryable = isRetryableHTTPResponse(httpResp.StatusCode, bodyStr) log.Errorf( diff --git a/test/integration/api/allocation/invalid_query_parameter_test.go b/test/integration/api/allocation/invalid_query_parameter_test.go index 6c71120..9485b83 100644 --- a/test/integration/api/allocation/invalid_query_parameter_test.go +++ b/test/integration/api/allocation/invalid_query_parameter_test.go @@ -14,7 +14,7 @@ import ( func TestAllocationInvalidParameters(t *testing.T) { apiObj := api.NewAPI() - invalidWindowTestCases := []struct { + invalidParameterTestCases := []struct { name string window string filter string @@ -63,7 +63,7 @@ func TestAllocationInvalidParameters(t *testing.T) { }, } - for _, tc := range invalidWindowTestCases { + for _, tc := range invalidParameterTestCases { t.Run(tc.name, func(t *testing.T) { t.Logf("Testing: %s", tc.name) diff --git a/test/integration/api/asset/invalid_query_parameter_test.go b/test/integration/api/asset/invalid_query_parameter_test.go index 951c87e..e8277e7 100644 --- a/test/integration/api/asset/invalid_query_parameter_test.go +++ b/test/integration/api/asset/invalid_query_parameter_test.go @@ -14,7 +14,7 @@ import ( func TestAssetInvalidParameters(t *testing.T) { apiObj := api.NewAPI() - invalidWindowTestCases := []struct { + invalidParameterTestCases := []struct { name string window string assetType string @@ -36,7 +36,7 @@ func TestAssetInvalidParameters(t *testing.T) { }, } - for _, tc := range invalidWindowTestCases { + for _, tc := range invalidParameterTestCases { t.Run(tc.name, func(t *testing.T) { t.Logf("Testing: %s", tc.name)