|
|
@@ -1,6 +1,7 @@
|
|
|
package costmodel
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
"reflect"
|
|
|
"testing"
|
|
|
"time"
|
|
|
@@ -150,32 +151,39 @@ func TestGetIntervalPointsFromWindows(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
+ pod1Key := newPodKey("cluster1", "namespace1", "pod1")
|
|
|
+ pod2Key := newPodKey("cluster1", "namespace1", "pod2")
|
|
|
+ pod3Key := newPodKey("cluster1", "namespace1", "pod3")
|
|
|
+ pod4Key := newPodKey("cluster1", "namespace1", "pod4")
|
|
|
+ ummountedPodKey := newPodKey("cluster1", kubecost.UnmountedSuffix, kubecost.UnmountedSuffix)
|
|
|
+
|
|
|
pvc1 := &pvc{
|
|
|
- Bytes: 0,
|
|
|
+ Bytes: 100 * 1024 * 1024 * 1024,
|
|
|
Name: "pvc1",
|
|
|
Cluster: "cluster1",
|
|
|
Namespace: "namespace1",
|
|
|
Start: time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC),
|
|
|
End: time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC),
|
|
|
}
|
|
|
- pod1Key := newPodKey("cluster1", "namespace1", "pod1")
|
|
|
- pod2Key := newPodKey("cluster1", "namespace1", "pod2")
|
|
|
- pod3Key := newPodKey("cluster1", "namespace1", "pod3")
|
|
|
- pod4Key := newPodKey("cluster1", "namespace1", "pod4")
|
|
|
- ummountedPodKey := newPodKey("cluster1", kubecost.UnmountedSuffix, kubecost.UnmountedSuffix)
|
|
|
|
|
|
- zeroDuration, _ := time.ParseDuration("0m0s")
|
|
|
- fiveMinOffset, _ := time.ParseDuration("5m")
|
|
|
- // Reflects the pvc that is offset by duration, the actual case that happens in allocation workflow.
|
|
|
- // before core-370, the offset was causing a unmounted shared pvc coefficient map for the duration of the offset.
|
|
|
- pvcWithDurationOffset := &pvc{
|
|
|
- Bytes: 0,
|
|
|
- Name: "pvc1",
|
|
|
+ pvc2 := &pvc{
|
|
|
+ Bytes: 100 * 1024 * 1024 * 1024,
|
|
|
+ Name: "pvc2",
|
|
|
Cluster: "cluster1",
|
|
|
Namespace: "namespace1",
|
|
|
- Start: time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC).Add(-fiveMinOffset),
|
|
|
+ Start: time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC),
|
|
|
End: time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC),
|
|
|
}
|
|
|
+
|
|
|
+ pvc3 := &pvc{
|
|
|
+ Bytes: 100 * 1024 * 1024 * 1024,
|
|
|
+ Name: "pvc3",
|
|
|
+ Cluster: "cluster1",
|
|
|
+ Namespace: "namespace1",
|
|
|
+ Start: time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC),
|
|
|
+ End: time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC),
|
|
|
+ }
|
|
|
+
|
|
|
cases := []struct {
|
|
|
name string
|
|
|
pvc *pvc
|
|
|
@@ -183,6 +191,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
intervals []IntervalPoint
|
|
|
resolution time.Duration
|
|
|
expected map[podKey][]CoefficientComponent
|
|
|
+ expError error
|
|
|
}{
|
|
|
{
|
|
|
name: "four pods w/ various overlaps",
|
|
|
@@ -197,7 +206,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod3Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod1Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{0.5, 0.25},
|
|
|
@@ -226,7 +235,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 30, 0, 0, time.UTC), "end", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod2Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{1.0, 0.5},
|
|
|
@@ -245,7 +254,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod2Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{0.5, 0.5},
|
|
|
@@ -265,7 +274,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC), "start", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod1Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{1.0, 1.0},
|
|
|
@@ -281,7 +290,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 45, 0, 0, time.UTC), "start", pod2Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod2Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{1.0, 0.25},
|
|
|
@@ -301,7 +310,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 15, 0, 0, time.UTC), "start", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 45, 0, 0, time.UTC), "end", pod1Key),
|
|
|
},
|
|
|
- resolution: zeroDuration,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{1.0, 0.5},
|
|
|
@@ -312,17 +321,16 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
- // Test case to ensure the offset doesnt cause any unmounted
|
|
|
{
|
|
|
- name: "pvcMap with duration offset not causing any unmounted entry in sharedPV Coefficient",
|
|
|
- pvc: pvcWithDurationOffset,
|
|
|
+ name: "back to back pods, full coverage",
|
|
|
+ pvc: pvc2,
|
|
|
intervals: []IntervalPoint{
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC), "start", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 30, 0, 0, time.UTC), "start", pod2Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 8, 30, 0, 0, time.UTC), "end", pod1Key),
|
|
|
NewIntervalPoint(time.Date(2021, 2, 19, 9, 0, 0, 0, time.UTC), "end", pod2Key),
|
|
|
},
|
|
|
- resolution: fiveMinOffset,
|
|
|
+ expError: nil,
|
|
|
expected: map[podKey][]CoefficientComponent{
|
|
|
pod1Key: {
|
|
|
{1.0, 0.5},
|
|
|
@@ -332,11 +340,31 @@ func TestGetPVCCostCoefficients(t *testing.T) {
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
+ {
|
|
|
+ name: "zero duration",
|
|
|
+ pvc: pvc3,
|
|
|
+ intervals: []IntervalPoint{
|
|
|
+ NewIntervalPoint(time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC), "start", pod1Key),
|
|
|
+ NewIntervalPoint(time.Date(2021, 2, 19, 8, 0, 0, 0, time.UTC), "end", pod1Key),
|
|
|
+ },
|
|
|
+ expError: fmt.Errorf("detected PVC with window of zero duration: %s/%s/%s", "cluster1", "namespace1", "pvc3"),
|
|
|
+ expected: nil,
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
for _, testCase := range cases {
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
- result := getPVCCostCoefficients(testCase.intervals, testCase.pvc, testCase.resolution)
|
|
|
+ result, err := getPVCCostCoefficients(testCase.intervals, testCase.pvc)
|
|
|
+ if err != nil {
|
|
|
+ if testCase.expError == nil {
|
|
|
+ t.Errorf("getPVCCostCoefficients failed: got unexpected error: %v", err)
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if err == nil && testCase.expError != nil {
|
|
|
+ t.Errorf("getPVCCostCoefficients failed: did not get expected error: %v", testCase.expError)
|
|
|
+ }
|
|
|
|
|
|
if !reflect.DeepEqual(result, testCase.expected) {
|
|
|
t.Errorf("getPVCCostCoefficients test failed: %s: Got %+v but expected %+v", testCase.name, result, testCase.expected)
|