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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions test/integration/api/allocation/empty_window_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package allocation

import (
"testing"

"github.com/opencost/opencost-integration-tests/pkg/api"
)

// TestAllocationEmptyWindow validates that allocation API returns a clean, well-formed
// empty response for valid but data-less windows.
//
// Expected response shape for empty windows:
// - HTTP Code: 200 (success)
// - Data: empty slice [] or list of empty allocations
// - No panic or 5xx errors
func TestAllocationEmptyWindow(t *testing.T) {
apiObj := api.NewAPI()

testCases := []struct {
name string
window string
aggregate string
}{
Comment thread
HardingEthan15 marked this conversation as resolved.
{
name: "FarPastWindow",
window: "1970-01-01T00:00:00Z,1970-01-02T00:00:00Z",
aggregate: "namespace",
},
{
name: "FutureWindow",
window: "2099-01-01T00:00:00Z,2099-01-02T00:00:00Z",
aggregate: "namespace",
},
{
name: "BeyondRetentionWindow",
window: "2000-01-01T00:00:00Z,2000-01-02T00:00:00Z",
aggregate: "cluster",
},
{
name: "TestPodEmptyWindow",
window: "1970-01-01T00:00:00Z,1970-01-02T00:00:00Z",
aggregate: "pod",
},
{
name: "TestContainerEmptyWindow",
window: "1970-01-01T00:00:00Z,1970-01-02T00:00:00Z",
aggregate: "container",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Logf("Testing: %s - %s", tc.name, tc.window)

response, err := apiObj.GetAllocation(api.AllocationRequest{
Window: tc.window,
Aggregate: tc.aggregate,
})

// Validate no errors occurred
if err != nil {
t.Fatalf("Unexpected error calling allocation API: %v", err)
}

// Validate HTTP 200
if response.Code != 200 {
t.Fatalf("Expected HTTP 200, got %d", response.Code)
}

// Validate response structure is well-formed
if response.Data == nil {
t.Fatalf("Expected non-nil data slice, got nil")
}

// Empty window should have empty data or a single empty map
// The exact format depends on the step parameter, but we should
// have at least one "window" entry even if no allocations
if len(response.Data) == 0 {
t.Logf("Data is empty slice (expected for empty window): %v", response.Data)
} else {
// If data has entries, each should be a map
for i, dataMap := range response.Data {
if len(dataMap) == 0 {
t.Logf("Data[%d] is empty map (expected for empty window)", i)
} else {
t.Fatalf("expected empty allocation data for empty window, data[%d] contained allocations: %v", i, dataMap)
}
}
}
})
}
}

4 changes: 4 additions & 0 deletions test/integration/api/allocation/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ teardown() {
@test "validate_api: validate if all of idle costs are spread" {
go test share_idle_shares_test.go
}

@test "validate_api: validate if api handles empty windows correctly" {
go test empty_window_test.go
}
78 changes: 78 additions & 0 deletions test/integration/api/asset/empty_window_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package assets

import (
"testing"

"github.com/opencost/opencost-integration-tests/pkg/api"
)

// TestAssetsEmptyWindow validates that assets API returns a clean, well-formed
// empty response for valid but data-less windows.
//
// Expected response shape for empty windows:
// - HTTP Code: 200 (success)
// - Data: empty map {} (no assets in the window)
// - No panic or 5xx errors
func TestAssetsEmptyWindow(t *testing.T) {
apiObj := api.NewAPI()

testCases := []struct {
name string
window string
assetType string
}{
{
name: "FarPastWindow",
window: "1970-01-01T00:00:00Z,1970-01-02T00:00:00Z",
assetType: "node",
},
{
name: "FutureWindow",
window: "2099-01-01T00:00:00Z,2099-01-02T00:00:00Z",
assetType: "node",
},
{
name: "BeyondRetentionWindow",
window: "2000-01-01T00:00:00Z,2000-01-02T00:00:00Z",
assetType: "disk",
},
{
name: "EmptyWindowPVC",
window: "1970-01-01T00:00:00Z,1970-01-02T00:00:00Z",
assetType: "pvc",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Logf("Testing: %s - %s", tc.name, tc.window)

response, err := apiObj.GetAssets(api.AssetsRequest{
Window: tc.window,
Filter: tc.assetType,
})

// Validate no errors occurred
if err != nil {
t.Fatalf("Unexpected error calling assets API: %v", err)
}

// Validate HTTP 200
if response.Code != 200 {
t.Fatalf("Expected HTTP 200, got %d", response.Code)
}

// Validate response structure is well-formed
if response.Data == nil {
t.Fatalf("Expected non-nil data map, got nil")
}

// Empty window should return empty map
if len(response.Data) == 0 {
t.Logf("Data is empty map (expected for empty window)")
} else {
t.Fatalf("Data has %d entries (filter: %s)", len(response.Data), tc.assetType)
}
})
}
}
4 changes: 4 additions & 0 deletions test/integration/api/asset/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ teardown() {
@test "asset: Spot Node" {
go test spot_nodes_test.go
}

@test "asset: Empty Window" {
go test empty_window_test.go
}
Loading