|
|
@@ -0,0 +1,212 @@
|
|
|
+package kubecost
|
|
|
+
|
|
|
+import (
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/kubecost/cost-model/pkg/util"
|
|
|
+)
|
|
|
+
|
|
|
+func TestSummaryAllocation_Add(t *testing.T) {
|
|
|
+ window, _ := ParseWindowUTC("yesterday")
|
|
|
+
|
|
|
+ var sa1, sa2, osa1, osa2, nilsa *SummaryAllocation
|
|
|
+ var err error
|
|
|
+
|
|
|
+ sa1Start := *window.Start()
|
|
|
+
|
|
|
+ sa1End := *window.End()
|
|
|
+
|
|
|
+ sa1 = &SummaryAllocation{
|
|
|
+ Name: "cluster1/namespace1/pod1/container1",
|
|
|
+ Properties: &AllocationProperties{
|
|
|
+ Cluster: "cluster1",
|
|
|
+ Namespace: "namespace1",
|
|
|
+ Pod: "pod1",
|
|
|
+ Container: "container1",
|
|
|
+ },
|
|
|
+ Start: sa1Start,
|
|
|
+ End: sa1End,
|
|
|
+ CPUCoreRequestAverage: 0.5,
|
|
|
+ CPUCoreUsageAverage: 0.1,
|
|
|
+ CPUCost: 0.2,
|
|
|
+ GPUCost: 1.0,
|
|
|
+ NetworkCost: 0.1,
|
|
|
+ LoadBalancerCost: 0.6,
|
|
|
+ PVCost: 0.005,
|
|
|
+ RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
|
|
|
+ RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
|
|
|
+ RAMCost: 0.05,
|
|
|
+ SharedCost: 1.0,
|
|
|
+ ExternalCost: 1.0,
|
|
|
+ }
|
|
|
+ osa1 = sa1.Clone()
|
|
|
+
|
|
|
+ // sa2 is just as expensive, with twice as much usage and request, and half
|
|
|
+ // the time compared to sa1
|
|
|
+
|
|
|
+ sa2Start := *window.Start()
|
|
|
+ sa2Start = sa2Start.Add(6 * time.Hour)
|
|
|
+
|
|
|
+ sa2End := *window.End()
|
|
|
+ sa2End = sa2End.Add(-6 * time.Hour)
|
|
|
+
|
|
|
+ sa2 = &SummaryAllocation{
|
|
|
+ Name: "cluster1/namespace1/pod2/container2",
|
|
|
+ Properties: &AllocationProperties{
|
|
|
+ Cluster: "cluster1",
|
|
|
+ Namespace: "namespace1",
|
|
|
+ Pod: "pod2",
|
|
|
+ Container: "container2",
|
|
|
+ },
|
|
|
+ Start: sa2Start,
|
|
|
+ End: sa2End,
|
|
|
+ CPUCoreRequestAverage: sa1.CPUCoreRequestAverage * 2.0,
|
|
|
+ CPUCoreUsageAverage: sa1.CPUCoreUsageAverage * 2.0,
|
|
|
+ CPUCost: sa1.CPUCost,
|
|
|
+ GPUCost: sa1.GPUCost,
|
|
|
+ NetworkCost: sa1.NetworkCost,
|
|
|
+ LoadBalancerCost: sa1.LoadBalancerCost,
|
|
|
+ PVCost: sa1.PVCost,
|
|
|
+ RAMBytesRequestAverage: sa1.RAMBytesRequestAverage * 2.0,
|
|
|
+ RAMBytesUsageAverage: sa1.RAMBytesUsageAverage * 2.0,
|
|
|
+ RAMCost: sa1.RAMCost,
|
|
|
+ SharedCost: sa1.SharedCost,
|
|
|
+ ExternalCost: sa1.ExternalCost,
|
|
|
+ }
|
|
|
+ osa2 = sa2.Clone()
|
|
|
+
|
|
|
+ // add nil to nil, expect and error
|
|
|
+ t.Run("nil.Add(nil)", func(t *testing.T) {
|
|
|
+ err = nilsa.Add(nilsa)
|
|
|
+ if err == nil {
|
|
|
+ t.Fatalf("expected error: cannot add nil SummaryAllocations")
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // reset
|
|
|
+ sa1 = osa1.Clone()
|
|
|
+ sa2 = osa2.Clone()
|
|
|
+
|
|
|
+ // add sa1 to nil, expect and error
|
|
|
+ t.Run("nil.Add(sa1)", func(t *testing.T) {
|
|
|
+ err = nilsa.Add(sa1)
|
|
|
+ if err == nil {
|
|
|
+ t.Fatalf("expected error: cannot add nil SummaryAllocations")
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // reset
|
|
|
+ sa1 = osa1.Clone()
|
|
|
+ sa2 = osa2.Clone()
|
|
|
+
|
|
|
+ // add nil to sa1, expect and error
|
|
|
+ t.Run("sa1.Add(nil)", func(t *testing.T) {
|
|
|
+ err = sa1.Add(nilsa)
|
|
|
+ if err == nil {
|
|
|
+ t.Fatalf("expected error: cannot add nil SummaryAllocations")
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // reset
|
|
|
+ sa1 = osa1.Clone()
|
|
|
+ sa2 = osa2.Clone()
|
|
|
+
|
|
|
+ // add sa1 to sa2 and expect same averages, but double costs
|
|
|
+ t.Run("sa2.Add(sa1)", func(t *testing.T) {
|
|
|
+ err = sa2.Add(sa1)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("unexpected error: %s", err)
|
|
|
+ }
|
|
|
+ if sa2.Properties != nil {
|
|
|
+ t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
|
|
|
+ t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
|
|
|
+ t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
|
|
|
+ t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
|
|
|
+ t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.CPUCost, osa2.CPUCost+osa1.CPUCost) {
|
|
|
+ t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.GPUCost, osa2.GPUCost+osa1.GPUCost) {
|
|
|
+ t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
|
|
|
+ t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
|
|
|
+ t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.PVCost, osa2.PVCost+osa1.PVCost) {
|
|
|
+ t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.RAMCost, osa2.RAMCost+osa1.RAMCost) {
|
|
|
+ t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.SharedCost, osa2.SharedCost+osa1.SharedCost) {
|
|
|
+ t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa2.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
|
|
|
+ t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // reset
|
|
|
+ sa1 = osa1.Clone()
|
|
|
+ sa2 = osa2.Clone()
|
|
|
+
|
|
|
+ // add sa2 to sa1 and expect same averages, but double costs
|
|
|
+ t.Run("sa1.Add(sa2)", func(t *testing.T) {
|
|
|
+ err = sa1.Add(sa2)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("unexpected error: %s", err)
|
|
|
+ }
|
|
|
+ if sa1.Properties != nil {
|
|
|
+ t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
|
|
|
+ t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
|
|
|
+ t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
|
|
|
+ t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
|
|
|
+ t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.CPUCost, osa2.CPUCost+osa1.CPUCost) {
|
|
|
+ t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.GPUCost, osa2.GPUCost+osa1.GPUCost) {
|
|
|
+ t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
|
|
|
+ t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
|
|
|
+ t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.PVCost, osa2.PVCost+osa1.PVCost) {
|
|
|
+ t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.RAMCost, osa2.RAMCost+osa1.RAMCost) {
|
|
|
+ t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.SharedCost, osa2.SharedCost+osa1.SharedCost) {
|
|
|
+ t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
|
|
|
+ }
|
|
|
+ if !util.IsApproximately(sa1.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
|
|
|
+ t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|