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  }