volcano.sh/volcano@v1.9.0/pkg/scheduler/api/pod_info_test.go (about) 1 /* 2 Copyright 2019 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 api 18 19 import ( 20 "reflect" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 v1 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/api/resource" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 28 "volcano.sh/volcano/pkg/scheduler/api/devices/nvidia/gpushare" 29 ) 30 31 func TestGetPodResourceRequest(t *testing.T) { 32 tests := []struct { 33 name string 34 pod *v1.Pod 35 expectedResource *Resource 36 }{ 37 { 38 name: "get resource for pod without init containers", 39 pod: &v1.Pod{ 40 Spec: v1.PodSpec{ 41 Containers: []v1.Container{ 42 { 43 Resources: v1.ResourceRequirements{ 44 Requests: BuildResourceList("1000m", "1G"), 45 }, 46 }, 47 { 48 Resources: v1.ResourceRequirements{ 49 Requests: BuildResourceList("2000m", "1G"), 50 }, 51 }, 52 }, 53 }, 54 }, 55 expectedResource: buildResource("3000m", "2G", map[string]string{"pods": "1"}, 0), 56 }, 57 { 58 name: "get resource for pod with init containers", 59 pod: &v1.Pod{ 60 Spec: v1.PodSpec{ 61 InitContainers: []v1.Container{ 62 { 63 Resources: v1.ResourceRequirements{ 64 Requests: BuildResourceList("2000m", "5G"), 65 }, 66 }, 67 { 68 Resources: v1.ResourceRequirements{ 69 Requests: BuildResourceList("2000m", "1G"), 70 }, 71 }, 72 }, 73 Containers: []v1.Container{ 74 { 75 Resources: v1.ResourceRequirements{ 76 Requests: BuildResourceList("1000m", "1G"), 77 }, 78 }, 79 { 80 Resources: v1.ResourceRequirements{ 81 Requests: BuildResourceList("2000m", "1G"), 82 }, 83 }, 84 }, 85 }, 86 }, 87 expectedResource: buildResource("3000m", "5G", map[string]string{"pods": "1"}, 0), 88 }, 89 } 90 91 for i, test := range tests { 92 req := GetPodResourceRequest(test.pod) 93 if !reflect.DeepEqual(req, test.expectedResource) { 94 t.Errorf("case %d(%s) failed: \n expected %v, \n got: %v \n", 95 i, test.name, test.expectedResource, req) 96 } 97 } 98 } 99 100 func TestGetPodResourceWithoutInitContainers(t *testing.T) { 101 tests := []struct { 102 name string 103 pod *v1.Pod 104 expectedResource *Resource 105 }{ 106 { 107 name: "get resource for pod without init containers", 108 pod: &v1.Pod{ 109 Spec: v1.PodSpec{ 110 Containers: []v1.Container{ 111 { 112 Resources: v1.ResourceRequirements{ 113 Requests: BuildResourceList("1000m", "1G"), 114 }, 115 }, 116 { 117 Resources: v1.ResourceRequirements{ 118 Requests: BuildResourceList("2000m", "1G"), 119 }, 120 }, 121 }, 122 }, 123 }, 124 expectedResource: NewResource(BuildResourceList("3000m", "2G")), 125 }, 126 { 127 name: "get resource for pod with init containers", 128 pod: &v1.Pod{ 129 Spec: v1.PodSpec{ 130 InitContainers: []v1.Container{ 131 { 132 Resources: v1.ResourceRequirements{ 133 Requests: BuildResourceList("2000m", "5G"), 134 }, 135 }, 136 { 137 Resources: v1.ResourceRequirements{ 138 Requests: BuildResourceList("2000m", "1G"), 139 }, 140 }, 141 }, 142 Containers: []v1.Container{ 143 { 144 Resources: v1.ResourceRequirements{ 145 Requests: BuildResourceList("1000m", "1G"), 146 }, 147 }, 148 { 149 Resources: v1.ResourceRequirements{ 150 Requests: BuildResourceList("2000m", "1G"), 151 }, 152 }, 153 }, 154 }, 155 }, 156 expectedResource: NewResource(BuildResourceList("3000m", "2G")), 157 }, 158 { 159 name: "get resource for pod with overhead", 160 pod: &v1.Pod{ 161 Spec: v1.PodSpec{ 162 Containers: []v1.Container{ 163 { 164 Resources: v1.ResourceRequirements{ 165 Requests: BuildResourceList("1000m", "1G"), 166 }, 167 }, 168 { 169 Resources: v1.ResourceRequirements{ 170 Requests: BuildResourceList("2000m", "1G"), 171 }, 172 }, 173 }, 174 Overhead: v1.ResourceList{ 175 v1.ResourceCPU: resource.MustParse("500m"), 176 v1.ResourceMemory: resource.MustParse("1G"), 177 }, 178 }, 179 }, 180 expectedResource: NewResource(BuildResourceList("3500m", "3G")), 181 }, 182 } 183 184 for i, test := range tests { 185 req := GetPodResourceWithoutInitContainers(test.pod) 186 if !reflect.DeepEqual(req, test.expectedResource) { 187 t.Errorf("case %d(%s) failed: \n expected %v, \n got: %v \n", 188 i, test.name, test.expectedResource, req) 189 } 190 } 191 } 192 193 func TestGetGPUIndex(t *testing.T) { 194 testCases := []struct { 195 name string 196 pod *v1.Pod 197 want []int 198 }{ 199 { 200 name: "pod without GPUIndex annotation", 201 pod: &v1.Pod{ 202 ObjectMeta: metav1.ObjectMeta{ 203 Annotations: nil, 204 }, 205 }, 206 want: nil, 207 }, 208 { 209 name: "pod with empty GPUIndex annotation", 210 pod: &v1.Pod{ 211 ObjectMeta: metav1.ObjectMeta{ 212 Annotations: map[string]string{GPUIndex: ""}, 213 }, 214 }, 215 want: nil, 216 }, 217 { 218 name: "pod with single GPUIndex annotation", 219 pod: &v1.Pod{ 220 ObjectMeta: metav1.ObjectMeta{ 221 Annotations: map[string]string{GPUIndex: "0"}, 222 }, 223 }, 224 want: []int{0}, 225 }, 226 { 227 name: "pod with multiple GPUIndexes annotation", 228 pod: &v1.Pod{ 229 ObjectMeta: metav1.ObjectMeta{ 230 Annotations: map[string]string{GPUIndex: "0,1,3"}, 231 }, 232 }, 233 want: []int{0, 1, 3}, 234 }, 235 } 236 237 for _, tc := range testCases { 238 t.Run(tc.name, func(t *testing.T) { 239 got := gpushare.GetGPUIndex(tc.pod) 240 if diff := cmp.Diff(tc.want, got); diff != "" { 241 t.Errorf("Unexpected result (-want +got):\n%s", diff) 242 } 243 }) 244 } 245 }