1
16
17 package qos
18
19 import (
20 "testing"
21
22 v1 "k8s.io/api/core/v1"
23 "k8s.io/apimachinery/pkg/api/resource"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/kubernetes/pkg/apis/core"
26 "k8s.io/kubernetes/pkg/apis/core/helper/qos"
27 corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
28 )
29
30 func TestComputePodQOS(t *testing.T) {
31 testCases := []struct {
32 pod *v1.Pod
33 expected v1.PodQOSClass
34 }{
35 {
36 pod: newPod("guaranteed", []v1.Container{
37 newContainer("guaranteed", getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
38 }),
39 expected: v1.PodQOSGuaranteed,
40 },
41 {
42 pod: newPod("guaranteed-guaranteed", []v1.Container{
43 newContainer("guaranteed", getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
44 newContainer("guaranteed", getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
45 }),
46 expected: v1.PodQOSGuaranteed,
47 },
48 {
49 pod: newPod("best-effort-best-effort", []v1.Container{
50 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
51 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
52 }),
53 expected: v1.PodQOSBestEffort,
54 },
55 {
56 pod: newPod("best-effort", []v1.Container{
57 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
58 }),
59 expected: v1.PodQOSBestEffort,
60 },
61 {
62 pod: newPod("best-effort-burstable", []v1.Container{
63 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
64 newContainer("burstable", getResourceList("1", ""), getResourceList("2", "")),
65 }),
66 expected: v1.PodQOSBurstable,
67 },
68 {
69 pod: newPod("best-effort-guaranteed", []v1.Container{
70 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
71 newContainer("guaranteed", getResourceList("10m", "100Mi"), getResourceList("10m", "100Mi")),
72 }),
73 expected: v1.PodQOSBurstable,
74 },
75 {
76 pod: newPod("burstable-cpu-guaranteed-memory", []v1.Container{
77 newContainer("burstable", getResourceList("", "100Mi"), getResourceList("", "100Mi")),
78 }),
79 expected: v1.PodQOSBurstable,
80 },
81 {
82 pod: newPod("burstable-no-limits", []v1.Container{
83 newContainer("burstable", getResourceList("100m", "100Mi"), getResourceList("", "")),
84 }),
85 expected: v1.PodQOSBurstable,
86 },
87 {
88 pod: newPod("burstable-guaranteed", []v1.Container{
89 newContainer("burstable", getResourceList("1", "100Mi"), getResourceList("2", "100Mi")),
90 newContainer("guaranteed", getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
91 }),
92 expected: v1.PodQOSBurstable,
93 },
94 {
95 pod: newPod("burstable-unbounded-but-requests-match-limits", []v1.Container{
96 newContainer("burstable", getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
97 newContainer("burstable-unbounded", getResourceList("100m", "100Mi"), getResourceList("", "")),
98 }),
99 expected: v1.PodQOSBurstable,
100 },
101 {
102 pod: newPod("burstable-1", []v1.Container{
103 newContainer("burstable", getResourceList("10m", "100Mi"), getResourceList("100m", "200Mi")),
104 }),
105 expected: v1.PodQOSBurstable,
106 },
107 {
108 pod: newPod("burstable-2", []v1.Container{
109 newContainer("burstable", getResourceList("0", "0"), getResourceList("100m", "200Mi")),
110 }),
111 expected: v1.PodQOSBurstable,
112 },
113 {
114 pod: newPod("best-effort-hugepages", []v1.Container{
115 newContainer("best-effort", addResource("hugepages-2Mi", "1Gi", getResourceList("0", "0")), addResource("hugepages-2Mi", "1Gi", getResourceList("0", "0"))),
116 }),
117 expected: v1.PodQOSBestEffort,
118 },
119 {
120 pod: newPodWithInitContainers("init-container",
121 []v1.Container{
122 newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
123 },
124 []v1.Container{
125 newContainer("burstable", getResourceList("10m", "100Mi"), getResourceList("100m", "200Mi")),
126 }),
127 expected: v1.PodQOSBurstable,
128 },
129 }
130 for id, testCase := range testCases {
131 if actual := ComputePodQOS(testCase.pod); testCase.expected != actual {
132 t.Errorf("[%d]: invalid qos pod %s, expected: %s, actual: %s", id, testCase.pod.Name, testCase.expected, actual)
133 }
134
135
136 pod := core.Pod{}
137 corev1.Convert_v1_Pod_To_core_Pod(testCase.pod, &pod, nil)
138
139 if actual := qos.ComputePodQOS(&pod); core.PodQOSClass(testCase.expected) != actual {
140 t.Errorf("[%d]: conversion invalid qos pod %s, expected: %s, actual: %s", id, testCase.pod.Name, testCase.expected, actual)
141 }
142 }
143 }
144
145 func getResourceList(cpu, memory string) v1.ResourceList {
146 res := v1.ResourceList{}
147 if cpu != "" {
148 res[v1.ResourceCPU] = resource.MustParse(cpu)
149 }
150 if memory != "" {
151 res[v1.ResourceMemory] = resource.MustParse(memory)
152 }
153 return res
154 }
155
156 func addResource(rName, value string, rl v1.ResourceList) v1.ResourceList {
157 rl[v1.ResourceName(rName)] = resource.MustParse(value)
158 return rl
159 }
160
161 func getResourceRequirements(requests, limits v1.ResourceList) v1.ResourceRequirements {
162 res := v1.ResourceRequirements{}
163 res.Requests = requests
164 res.Limits = limits
165 return res
166 }
167
168 func newContainer(name string, requests v1.ResourceList, limits v1.ResourceList) v1.Container {
169 return v1.Container{
170 Name: name,
171 Resources: getResourceRequirements(requests, limits),
172 }
173 }
174
175 func newPod(name string, containers []v1.Container) *v1.Pod {
176 return &v1.Pod{
177 ObjectMeta: metav1.ObjectMeta{
178 Name: name,
179 },
180 Spec: v1.PodSpec{
181 Containers: containers,
182 },
183 }
184 }
185
186 func newPodWithInitContainers(name string, containers []v1.Container, initContainers []v1.Container) *v1.Pod {
187 return &v1.Pod{
188 ObjectMeta: metav1.ObjectMeta{
189 Name: name,
190 },
191 Spec: v1.PodSpec{
192 Containers: containers,
193 InitContainers: initContainers,
194 },
195 }
196 }
197
View as plain text