Skip to content

Commit 2414cfd

Browse files
committed
kubelet/eviction: improve unit test coverage
Signed-off-by: TommyStarK <[email protected]>
1 parent 4aca09b commit 2414cfd

File tree

2 files changed

+236
-6
lines changed

2 files changed

+236
-6
lines changed

pkg/kubelet/eviction/helpers_test.go

Lines changed: 195 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"time"
2727

2828
"github.com/google/go-cmp/cmp"
29+
"github.com/stretchr/testify/assert"
2930
v1 "k8s.io/api/core/v1"
3031
"k8s.io/apimachinery/pkg/api/resource"
3132
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -46,7 +47,10 @@ func quantityMustParse(value string) *resource.Quantity {
4647

4748
func TestGetReclaimableThreshold(t *testing.T) {
4849
testCases := map[string]struct {
49-
thresholds []evictionapi.Threshold
50+
thresholds []evictionapi.Threshold
51+
expectedThreshold evictionapi.Threshold
52+
expectedResourceName v1.ResourceName
53+
expectedReclaimableToBeFound bool
5054
}{
5155
"": {
5256
thresholds: []evictionapi.Threshold{
@@ -101,14 +105,40 @@ func TestGetReclaimableThreshold(t *testing.T) {
101105
},
102106
},
103107
},
108+
expectedThreshold: evictionapi.Threshold{
109+
Signal: evictionapi.Signal("memory.available"),
110+
Operator: evictionapi.OpLessThan,
111+
Value: evictionapi.ThresholdValue{
112+
Quantity: quantityMustParse("150Mi"),
113+
},
114+
},
115+
expectedResourceName: v1.ResourceName("memory"),
116+
expectedReclaimableToBeFound: true,
117+
},
118+
"no thresholds": {
119+
thresholds: []evictionapi.Threshold{},
120+
expectedThreshold: evictionapi.Threshold{},
121+
expectedResourceName: v1.ResourceName(""),
122+
},
123+
"threshold was crossed but reclaim not implemented (invalid signal)": {
124+
thresholds: []evictionapi.Threshold{
125+
{
126+
Signal: "mem.available",
127+
},
128+
},
129+
expectedThreshold: evictionapi.Threshold{},
130+
expectedResourceName: v1.ResourceName(""),
104131
},
105132
}
106-
for testName, testCase := range testCases {
133+
for _, testCase := range testCases {
107134
sort.Sort(byEvictionPriority(testCase.thresholds))
108-
_, _, ok := getReclaimableThreshold(testCase.thresholds)
109-
if !ok {
110-
t.Errorf("Didn't find reclaimable threshold, test: %v", testName)
111-
}
135+
threshold, ressourceName, found := getReclaimableThreshold(testCase.thresholds)
136+
assert.Equal(t, testCase.expectedReclaimableToBeFound, found)
137+
assert.Equal(t, testCase.expectedResourceName, ressourceName)
138+
assert.Equal(t, testCase.expectedThreshold.Signal, threshold.Signal)
139+
assert.Equal(t, testCase.expectedThreshold.Operator, threshold.Operator)
140+
assert.Equal(t, testCase.expectedThreshold.Value.Quantity.String(), threshold.Value.Quantity.String())
141+
assert.Equal(t, testCase.expectedThreshold.GracePeriod, threshold.GracePeriod)
112142
}
113143
}
114144

@@ -455,6 +485,78 @@ func TestParseThresholdConfig(t *testing.T) {
455485
expectErr: true,
456486
expectThresholds: []evictionapi.Threshold{},
457487
},
488+
"min-reclaim-invalid-signal": {
489+
allocatableConfig: []string{},
490+
evictionHard: map[string]string{},
491+
evictionSoft: map[string]string{},
492+
evictionSoftGracePeriod: map[string]string{},
493+
evictionMinReclaim: map[string]string{"mem.available": "300Mi"},
494+
expectErr: true,
495+
expectThresholds: []evictionapi.Threshold{},
496+
},
497+
"min-reclaim-empty-value": {
498+
allocatableConfig: []string{},
499+
evictionHard: map[string]string{},
500+
evictionSoft: map[string]string{},
501+
evictionSoftGracePeriod: map[string]string{},
502+
evictionMinReclaim: map[string]string{"memory.available": ""},
503+
expectErr: true,
504+
expectThresholds: []evictionapi.Threshold{},
505+
},
506+
"min-reclaim-negative-percentage": {
507+
allocatableConfig: []string{},
508+
evictionHard: map[string]string{},
509+
evictionSoft: map[string]string{},
510+
evictionSoftGracePeriod: map[string]string{},
511+
evictionMinReclaim: map[string]string{"memory.available": "-15%"},
512+
expectErr: true,
513+
expectThresholds: []evictionapi.Threshold{},
514+
},
515+
"min-reclaim-invalid-percentage": {
516+
allocatableConfig: []string{},
517+
evictionHard: map[string]string{},
518+
evictionSoft: map[string]string{},
519+
evictionSoftGracePeriod: map[string]string{},
520+
evictionMinReclaim: map[string]string{"memory.available": "10..5%"},
521+
expectErr: true,
522+
expectThresholds: []evictionapi.Threshold{},
523+
},
524+
"hard-signal-empty-eviction-value": {
525+
allocatableConfig: []string{},
526+
evictionHard: map[string]string{"memory.available": ""},
527+
evictionSoft: map[string]string{},
528+
evictionSoftGracePeriod: map[string]string{},
529+
evictionMinReclaim: map[string]string{},
530+
expectErr: true,
531+
expectThresholds: []evictionapi.Threshold{},
532+
},
533+
"hard-signal-invalid-float-percentage": {
534+
allocatableConfig: []string{},
535+
evictionHard: map[string]string{"memory.available": "10..5%"},
536+
evictionSoft: map[string]string{},
537+
evictionSoftGracePeriod: map[string]string{},
538+
evictionMinReclaim: map[string]string{},
539+
expectErr: true,
540+
expectThresholds: []evictionapi.Threshold{},
541+
},
542+
"soft-grace-period-invalid-signal": {
543+
allocatableConfig: []string{},
544+
evictionHard: map[string]string{},
545+
evictionSoft: map[string]string{"memory.available": "150Mi"},
546+
evictionSoftGracePeriod: map[string]string{"mem.available": "30s"},
547+
evictionMinReclaim: map[string]string{},
548+
expectErr: true,
549+
expectThresholds: []evictionapi.Threshold{},
550+
},
551+
"soft-invalid-grace-period": {
552+
allocatableConfig: []string{},
553+
evictionHard: map[string]string{},
554+
evictionSoft: map[string]string{"memory.available": "150Mi"},
555+
evictionSoftGracePeriod: map[string]string{"memory.available": "30mins"},
556+
evictionMinReclaim: map[string]string{},
557+
expectErr: true,
558+
expectThresholds: []evictionapi.Threshold{},
559+
},
458560
}
459561
for testName, testCase := range testCases {
460562
thresholds, err := ParseThresholdConfig(testCase.allocatableConfig, testCase.evictionHard, testCase.evictionSoft, testCase.evictionSoftGracePeriod, testCase.evictionMinReclaim)
@@ -648,6 +750,47 @@ func TestAddAllocatableThresholds(t *testing.T) {
648750
}
649751
}
650752

753+
func TestFallbackResourcesUsage(t *testing.T) {
754+
for _, test := range []struct {
755+
description string
756+
usageFuncName string
757+
usageFunc func() int64
758+
}{
759+
{
760+
description: "disk usage, fallback value",
761+
usageFuncName: "diskUsage",
762+
usageFunc: func() int64 {
763+
return diskUsage(&statsapi.FsStats{}).Value()
764+
},
765+
},
766+
{
767+
description: "inode usage, fallback value",
768+
usageFuncName: "inodeUsage",
769+
usageFunc: func() int64 {
770+
return inodeUsage(&statsapi.FsStats{}).Value()
771+
},
772+
},
773+
{
774+
description: "memory usage, fallback value",
775+
usageFuncName: "memoryUsage",
776+
usageFunc: func() int64 {
777+
return memoryUsage(&statsapi.MemoryStats{}).Value()
778+
},
779+
},
780+
{
781+
description: "process usage, fallback value",
782+
usageFuncName: "processUsage",
783+
usageFunc: func() int64 {
784+
return int64(processUsage(&statsapi.ProcessStats{}))
785+
},
786+
},
787+
} {
788+
t.Run(test.description, func(t *testing.T) {
789+
assert.NotEqual(t, 0, test.usageFunc(), fmt.Sprintf("%s: unexpected fallback value", test.usageFuncName))
790+
})
791+
}
792+
}
793+
651794
func thresholdsEqual(expected []evictionapi.Threshold, actual []evictionapi.Threshold) bool {
652795
if len(expected) != len(actual) {
653796
return false
@@ -3259,3 +3402,49 @@ func TestEvictonMessageWithResourceResize(t *testing.T) {
32593402
})
32603403
}
32613404
}
3405+
3406+
func TestStatsNotFoundForPod(t *testing.T) {
3407+
pod1 := newPod("fake-pod1", defaultPriority, []v1.Container{
3408+
newContainer("fake-container1", newResourceList("", "", ""), newResourceList("", "", "")),
3409+
}, nil)
3410+
pod2 := newPod("fake-pod2", defaultPriority, []v1.Container{
3411+
newContainer("fake-container2", newResourceList("", "", ""), newResourceList("", "", "")),
3412+
}, nil)
3413+
statsFn := func(pod *v1.Pod) (statsapi.PodStats, bool) {
3414+
return statsapi.PodStats{}, false
3415+
}
3416+
3417+
for _, test := range []struct {
3418+
description string
3419+
compFunc func(stats statsFunc) cmpFunc
3420+
}{
3421+
{
3422+
description: "process",
3423+
compFunc: process,
3424+
},
3425+
{
3426+
description: "memory",
3427+
compFunc: memory,
3428+
},
3429+
{
3430+
description: "exceedMemoryRequests",
3431+
compFunc: exceedMemoryRequests,
3432+
},
3433+
{
3434+
description: "exceedDiskRequests",
3435+
compFunc: func(stats statsFunc) cmpFunc {
3436+
return exceedDiskRequests(stats, nil, "")
3437+
},
3438+
},
3439+
{
3440+
description: "disk",
3441+
compFunc: func(stats statsFunc) cmpFunc {
3442+
return disk(stats, nil, "")
3443+
},
3444+
},
3445+
} {
3446+
t.Run(test.description, func(t *testing.T) {
3447+
assert.Equal(t, 0, test.compFunc(statsFn)(pod1, pod2), "unexpected default result")
3448+
})
3449+
}
3450+
}

pkg/kubelet/eviction/memory_threshold_notifier_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"testing"
2727
"time"
2828

29+
"github.com/stretchr/testify/assert"
2930
"k8s.io/apimachinery/pkg/api/resource"
3031
statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
3132
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
@@ -151,6 +152,46 @@ func TestUpdateThreshold(t *testing.T) {
151152
}
152153
}
153154

155+
func TestUpdateThresholdWithInvalidSummary(t *testing.T) {
156+
testCases := []struct {
157+
description string
158+
summary *statsapi.Summary
159+
allocatableEvictionThreshold bool
160+
}{
161+
{
162+
description: "incomplete summary",
163+
summary: &statsapi.Summary{
164+
Node: statsapi.NodeStats{
165+
Memory: &statsapi.MemoryStats{},
166+
},
167+
},
168+
},
169+
{
170+
description: "system container not found in metrics",
171+
allocatableEvictionThreshold: true,
172+
summary: &statsapi.Summary{
173+
Node: statsapi.NodeStats{
174+
SystemContainers: []statsapi.ContainerStats{
175+
{
176+
Name: "invalid",
177+
},
178+
},
179+
Memory: &statsapi.MemoryStats{},
180+
},
181+
},
182+
},
183+
}
184+
for _, tc := range testCases {
185+
t.Run(tc.description, func(t *testing.T) {
186+
m := newTestMemoryThresholdNotifier(evictionapi.Threshold{}, nil, nil)
187+
if tc.allocatableEvictionThreshold {
188+
m.threshold.Signal = evictionapi.SignalAllocatableMemoryAvailable
189+
}
190+
assert.Error(t, m.UpdateThreshold(tc.summary))
191+
})
192+
}
193+
}
194+
154195
func TestStart(t *testing.T) {
155196
noResources := resource.MustParse("0")
156197
threshold := evictionapi.Threshold{

0 commit comments

Comments
 (0)