|
|
@@ -0,0 +1,129 @@
|
|
|
+package kubecost
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "math"
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/opencost/opencost/pkg/util/timeutil"
|
|
|
+)
|
|
|
+
|
|
|
+func TestSummaryAllocationSetRangeResponse_MarshalJSON(t *testing.T) {
|
|
|
+ // Set a 1-day (start, end)
|
|
|
+ s := time.Date(2023, time.March, 13, 0, 0, 0, 0, time.UTC)
|
|
|
+ e := s.Add(timeutil.Day)
|
|
|
+
|
|
|
+ // Set some basic numbers that can be used to asset accuracy later
|
|
|
+ adjustment := -0.14
|
|
|
+ bytes := 2183471523842.00
|
|
|
+ cores := 2.78
|
|
|
+ cost := 12.50
|
|
|
+ gpus := 1.00
|
|
|
+
|
|
|
+ // Test a normal allocation for numerical accuracy
|
|
|
+ alloc := &Allocation{
|
|
|
+ Name: "cluster/node/namespace/pod/alloc",
|
|
|
+ Properties: &AllocationProperties{
|
|
|
+ Cluster: "cluster",
|
|
|
+ Node: "node",
|
|
|
+ Namespace: "namespace",
|
|
|
+ Pod: "pod",
|
|
|
+ Container: "alloc",
|
|
|
+ },
|
|
|
+ CPUCoreHours: cores,
|
|
|
+ CPUCoreRequestAverage: cores,
|
|
|
+ CPUCoreUsageAverage: cores,
|
|
|
+ CPUCost: cost,
|
|
|
+ CPUCostAdjustment: adjustment,
|
|
|
+ GPUHours: gpus,
|
|
|
+ GPUCost: cost,
|
|
|
+ GPUCostAdjustment: adjustment,
|
|
|
+ NetworkTransferBytes: bytes,
|
|
|
+ NetworkReceiveBytes: bytes,
|
|
|
+ NetworkCost: cost,
|
|
|
+ NetworkCrossZoneCost: cost,
|
|
|
+ NetworkCrossRegionCost: cost,
|
|
|
+ NetworkInternetCost: cost,
|
|
|
+ NetworkCostAdjustment: adjustment,
|
|
|
+ LoadBalancerCost: cost,
|
|
|
+ LoadBalancerCostAdjustment: adjustment,
|
|
|
+ PVs: PVAllocations{
|
|
|
+ PVKey{Cluster: "cluster", Name: "pv"}: &PVAllocation{
|
|
|
+ ByteHours: bytes,
|
|
|
+ Cost: cost,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ PVCostAdjustment: adjustment,
|
|
|
+ RAMByteHours: bytes,
|
|
|
+ RAMBytesRequestAverage: bytes,
|
|
|
+ RAMBytesUsageAverage: bytes,
|
|
|
+ RAMCost: cost,
|
|
|
+ RAMCostAdjustment: adjustment,
|
|
|
+ SharedCost: cost,
|
|
|
+ ExternalCost: cost,
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test an allocation with NaN values for JSON marshal errors
|
|
|
+ allocWithNaN := &Allocation{
|
|
|
+ Name: "cluster/node/namespace/pod/nan",
|
|
|
+ Properties: &AllocationProperties{
|
|
|
+ Cluster: "cluster",
|
|
|
+ Node: "node",
|
|
|
+ Namespace: "namespace",
|
|
|
+ Pod: "pod",
|
|
|
+ Container: "nan",
|
|
|
+ },
|
|
|
+ CPUCoreHours: math.NaN(),
|
|
|
+ CPUCoreRequestAverage: math.NaN(),
|
|
|
+ CPUCoreUsageAverage: math.NaN(),
|
|
|
+ CPUCost: math.NaN(),
|
|
|
+ CPUCostAdjustment: math.NaN(),
|
|
|
+ GPUHours: gpus,
|
|
|
+ GPUCost: cost,
|
|
|
+ GPUCostAdjustment: adjustment,
|
|
|
+ NetworkTransferBytes: bytes,
|
|
|
+ NetworkReceiveBytes: bytes,
|
|
|
+ NetworkCost: cost,
|
|
|
+ NetworkCrossZoneCost: cost,
|
|
|
+ NetworkCrossRegionCost: cost,
|
|
|
+ NetworkInternetCost: cost,
|
|
|
+ NetworkCostAdjustment: adjustment,
|
|
|
+ LoadBalancerCost: cost,
|
|
|
+ LoadBalancerCostAdjustment: adjustment,
|
|
|
+ PVs: PVAllocations{
|
|
|
+ PVKey{Cluster: "cluster", Name: "pv"}: &PVAllocation{
|
|
|
+ ByteHours: bytes,
|
|
|
+ Cost: cost,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ PVCostAdjustment: adjustment,
|
|
|
+ RAMByteHours: bytes,
|
|
|
+ RAMBytesRequestAverage: bytes,
|
|
|
+ RAMBytesUsageAverage: bytes,
|
|
|
+ RAMCost: cost,
|
|
|
+ RAMCostAdjustment: adjustment,
|
|
|
+ SharedCost: cost,
|
|
|
+ ExternalCost: cost,
|
|
|
+ }
|
|
|
+
|
|
|
+ // Convert to SummaryAllocationSetRange
|
|
|
+ as := NewAllocationSet(s, e, alloc, allocWithNaN)
|
|
|
+ sas := NewSummaryAllocationSet(as, nil, nil, true, true)
|
|
|
+ sasr := NewSummaryAllocationSetRange(sas)
|
|
|
+
|
|
|
+ // Confirm that SummaryAllocationSetRange does error because on NaN
|
|
|
+ _, err := json.Marshal(sasr)
|
|
|
+ if err == nil {
|
|
|
+ t.Fatalf("expected NaN values to cause error")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Convert to response
|
|
|
+ sasrr := sasr.ToResponse()
|
|
|
+
|
|
|
+ // Confirm that same SummaryAllocationSetRangeResponse does NOT error
|
|
|
+ _, err = json.Marshal(sasrr)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("unexpected error: %v", err)
|
|
|
+ }
|
|
|
+}
|