k8s.io/kubernetes@v1.29.3/pkg/apis/core/v1/helper/qos/qos_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // Convert v1.Pod to core.Pod, and then check against `core.helper.ComputePodQOS`. 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 }