k8s.io/kubernetes@v1.29.3/pkg/kubelet/types/pod_update_test.go (about)

     1  /*
     2  Copyright 2014 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 types
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/kubernetes/pkg/apis/scheduling"
    27  )
    28  
    29  var (
    30  	systemPriority      = scheduling.SystemCriticalPriority
    31  	systemPriorityUpper = systemPriority + 1000
    32  )
    33  
    34  // getTestPod generates a new instance of an empty test Pod
    35  func getTestPod(annotations map[string]string, podPriority *int32, priorityClassName string) *v1.Pod {
    36  	pod := v1.Pod{
    37  		TypeMeta: metav1.TypeMeta{
    38  			Kind:       "Pod",
    39  			APIVersion: "v1",
    40  		},
    41  		ObjectMeta: metav1.ObjectMeta{
    42  			Name:      "foo",
    43  			Namespace: "default",
    44  		},
    45  	}
    46  	// Set pod Priority in Spec if exists
    47  	if podPriority != nil {
    48  		pod.Spec = v1.PodSpec{
    49  			Priority: podPriority,
    50  		}
    51  	}
    52  	pod.Spec.PriorityClassName = priorityClassName
    53  	// Set annotations if exists
    54  	if annotations != nil {
    55  		pod.Annotations = annotations
    56  	}
    57  	return &pod
    58  }
    59  
    60  func configSourceAnnotation(source string) map[string]string {
    61  	return map[string]string{ConfigSourceAnnotationKey: source}
    62  }
    63  
    64  func configMirrorAnnotation() map[string]string {
    65  	return map[string]string{ConfigMirrorAnnotationKey: "true"}
    66  }
    67  
    68  func TestGetValidatedSources(t *testing.T) {
    69  	tests := []struct {
    70  		name        string
    71  		sources     []string
    72  		errExpected bool
    73  		sourcesLen  int
    74  	}{
    75  		{
    76  			name:        "empty source",
    77  			sources:     []string{""},
    78  			errExpected: false,
    79  			sourcesLen:  0,
    80  		},
    81  		{
    82  			name:        "file and apiserver source",
    83  			sources:     []string{FileSource, ApiserverSource},
    84  			errExpected: false,
    85  			sourcesLen:  2,
    86  		},
    87  		{
    88  			name:        "all source",
    89  			sources:     []string{AllSource},
    90  			errExpected: false,
    91  			sourcesLen:  3,
    92  		},
    93  		{
    94  			name:        "unknown source",
    95  			sources:     []string{"unknown"},
    96  			errExpected: true,
    97  			sourcesLen:  0,
    98  		},
    99  	}
   100  
   101  	for _, test := range tests {
   102  		t.Run(test.name, func(t *testing.T) {
   103  			sources, err := GetValidatedSources(test.sources)
   104  			if test.errExpected {
   105  				assert.Error(t, err)
   106  			} else {
   107  				assert.NoError(t, err)
   108  			}
   109  			assert.Len(t, sources, test.sourcesLen)
   110  		})
   111  	}
   112  }
   113  
   114  func TestGetPodSource(t *testing.T) {
   115  	tests := []struct {
   116  		name        string
   117  		pod         *v1.Pod
   118  		expected    string
   119  		errExpected bool
   120  	}{
   121  		{
   122  			name:        "cannot get pod source",
   123  			pod:         getTestPod(nil, nil, ""),
   124  			expected:    "",
   125  			errExpected: true,
   126  		},
   127  		{
   128  			name:        "valid annotation returns the source",
   129  			pod:         getTestPod(configSourceAnnotation("host-ipc-sources"), nil, ""),
   130  			expected:    "host-ipc-sources",
   131  			errExpected: false,
   132  		},
   133  	}
   134  
   135  	for _, test := range tests {
   136  		t.Run(test.name, func(t *testing.T) {
   137  			source, err := GetPodSource(test.pod)
   138  			if test.errExpected {
   139  				assert.Error(t, err)
   140  			} else {
   141  				assert.NoError(t, err)
   142  			}
   143  			assert.Equal(t, test.expected, source)
   144  		})
   145  	}
   146  }
   147  
   148  func TestString(t *testing.T) {
   149  	tests := []struct {
   150  		sp       SyncPodType
   151  		expected string
   152  	}{
   153  		{
   154  			sp:       SyncPodCreate,
   155  			expected: "create",
   156  		},
   157  		{
   158  			sp:       SyncPodUpdate,
   159  			expected: "update",
   160  		},
   161  		{
   162  			sp:       SyncPodSync,
   163  			expected: "sync",
   164  		},
   165  		{
   166  			sp:       SyncPodKill,
   167  			expected: "kill",
   168  		},
   169  		{
   170  			sp:       50,
   171  			expected: "unknown",
   172  		},
   173  	}
   174  	for _, test := range tests {
   175  		t.Run(test.expected, func(t *testing.T) {
   176  			syncPodString := test.sp.String()
   177  			assert.Equal(t, test.expected, syncPodString)
   178  		})
   179  	}
   180  }
   181  
   182  func TestIsMirrorPod(t *testing.T) {
   183  	tests := []struct {
   184  		name     string
   185  		pod      *v1.Pod
   186  		expected bool
   187  	}{
   188  		{
   189  			name:     "mirror pod",
   190  			pod:      getTestPod(configMirrorAnnotation(), nil, ""),
   191  			expected: true,
   192  		},
   193  		{
   194  			name:     "not a mirror pod",
   195  			pod:      getTestPod(nil, nil, ""),
   196  			expected: false,
   197  		},
   198  	}
   199  	for _, test := range tests {
   200  		t.Run(test.name, func(t *testing.T) {
   201  			isMirrorPod := IsMirrorPod(test.pod)
   202  			assert.Equal(t, test.expected, isMirrorPod)
   203  		})
   204  	}
   205  }
   206  
   207  func TestIsStaticPod(t *testing.T) {
   208  	tests := []struct {
   209  		name     string
   210  		pod      *v1.Pod
   211  		expected bool
   212  	}{
   213  		{
   214  			name:     "static pod with file source",
   215  			pod:      getTestPod(configSourceAnnotation(FileSource), nil, ""),
   216  			expected: true,
   217  		},
   218  		{
   219  			name:     "static pod with http source",
   220  			pod:      getTestPod(configSourceAnnotation(HTTPSource), nil, ""),
   221  			expected: true,
   222  		},
   223  		{
   224  			name:     "static pod with api server source",
   225  			pod:      getTestPod(configSourceAnnotation(ApiserverSource), nil, ""),
   226  			expected: false,
   227  		},
   228  	}
   229  
   230  	for _, test := range tests {
   231  		t.Run(test.name, func(t *testing.T) {
   232  			isStaticPod := IsStaticPod(test.pod)
   233  			assert.Equal(t, test.expected, isStaticPod)
   234  		})
   235  	}
   236  }
   237  
   238  func TestIsCriticalPod(t *testing.T) {
   239  	tests := []struct {
   240  		name     string
   241  		pod      *v1.Pod
   242  		expected bool
   243  	}{
   244  		{
   245  			name:     "critical pod with file source",
   246  			pod:      getTestPod(configSourceAnnotation(FileSource), nil, ""),
   247  			expected: true,
   248  		},
   249  		{
   250  			name:     "critical pod with mirror annotation",
   251  			pod:      getTestPod(configMirrorAnnotation(), nil, ""),
   252  			expected: true,
   253  		},
   254  		{
   255  			name:     "critical pod using system priority",
   256  			pod:      getTestPod(nil, &systemPriority, ""),
   257  			expected: true,
   258  		},
   259  		{
   260  			name:     "critical pod using greater than system priority",
   261  			pod:      getTestPod(nil, &systemPriorityUpper, ""),
   262  			expected: true,
   263  		},
   264  		{
   265  			name:     "not a critical pod with api server annotation",
   266  			pod:      getTestPod(configSourceAnnotation(ApiserverSource), nil, ""),
   267  			expected: false,
   268  		},
   269  		{
   270  			name:     "not critical if not static, mirror or without a priority",
   271  			pod:      getTestPod(nil, nil, ""),
   272  			expected: false,
   273  		},
   274  	}
   275  	for _, test := range tests {
   276  		t.Run(test.name, func(t *testing.T) {
   277  			isCriticalPod := IsCriticalPod(test.pod)
   278  			assert.Equal(t, test.expected, isCriticalPod)
   279  		})
   280  	}
   281  }
   282  
   283  func TestPreemptable(t *testing.T) {
   284  	tests := []struct {
   285  		name      string
   286  		preemptor *v1.Pod
   287  		preemptee *v1.Pod
   288  		expected  bool
   289  	}{
   290  		{
   291  			name:      "a critical preemptor pod preempts a non critical pod",
   292  			preemptor: getTestPod(configSourceAnnotation(FileSource), nil, ""),
   293  			preemptee: getTestPod(nil, nil, ""),
   294  			expected:  true,
   295  		},
   296  		{
   297  			name:      "a preemptor pod with higher priority preempts a critical pod",
   298  			preemptor: getTestPod(configSourceAnnotation(FileSource), &systemPriorityUpper, ""),
   299  			preemptee: getTestPod(configSourceAnnotation(FileSource), &systemPriority, ""),
   300  			expected:  true,
   301  		},
   302  		{
   303  			name:      "a not critical pod with higher priority preempts a critical pod",
   304  			preemptor: getTestPod(configSourceAnnotation(ApiserverSource), &systemPriorityUpper, ""),
   305  			preemptee: getTestPod(configSourceAnnotation(FileSource), &systemPriority, ""),
   306  			expected:  true,
   307  		},
   308  		{
   309  			name:      "a critical pod with less priority do not preempts a critical pod",
   310  			preemptor: getTestPod(configSourceAnnotation(FileSource), &systemPriority, ""),
   311  			preemptee: getTestPod(configSourceAnnotation(FileSource), &systemPriorityUpper, ""),
   312  			expected:  false,
   313  		},
   314  		{
   315  			name:      "a critical pod without priority do not preempts a critical pod without priority",
   316  			preemptor: getTestPod(configSourceAnnotation(FileSource), nil, ""),
   317  			preemptee: getTestPod(configSourceAnnotation(FileSource), nil, ""),
   318  			expected:  false,
   319  		},
   320  		{
   321  			name:      "a critical pod with priority do not preempts a critical pod with the same priority",
   322  			preemptor: getTestPod(configSourceAnnotation(FileSource), &systemPriority, ""),
   323  			preemptee: getTestPod(configSourceAnnotation(FileSource), &systemPriority, ""),
   324  			expected:  false,
   325  		},
   326  	}
   327  	for _, test := range tests {
   328  		t.Run(test.name, func(t *testing.T) {
   329  			isPreemtable := Preemptable(test.preemptor, test.preemptee)
   330  			assert.Equal(t, test.expected, isPreemtable)
   331  		})
   332  	}
   333  }
   334  
   335  func TestIsCriticalPodBasedOnPriority(t *testing.T) {
   336  	tests := []struct {
   337  		priority int32
   338  		name     string
   339  		expected bool
   340  	}{
   341  		{
   342  			name:     "a system critical pod",
   343  			priority: systemPriority,
   344  			expected: true,
   345  		},
   346  		{
   347  			name:     "a non system critical pod",
   348  			priority: scheduling.HighestUserDefinablePriority,
   349  			expected: false,
   350  		},
   351  	}
   352  	for _, test := range tests {
   353  		t.Run(test.name, func(t *testing.T) {
   354  			actual := IsCriticalPodBasedOnPriority(test.priority)
   355  			if actual != test.expected {
   356  				t.Errorf("IsCriticalPodBased on priority should have returned %v for test %v but got %v", test.expected, test.name, actual)
   357  			}
   358  		})
   359  	}
   360  }
   361  
   362  func TestIsNodeCriticalPod(t *testing.T) {
   363  	tests := []struct {
   364  		name     string
   365  		pod      *v1.Pod
   366  		expected bool
   367  	}{
   368  		{
   369  			name:     "critical pod with file source and systemNodeCritical",
   370  			pod:      getTestPod(configSourceAnnotation(FileSource), nil, scheduling.SystemNodeCritical),
   371  			expected: true,
   372  		},
   373  		{
   374  			name:     "critical pod with mirror annotation and systemNodeCritical",
   375  			pod:      getTestPod(configMirrorAnnotation(), nil, scheduling.SystemNodeCritical),
   376  			expected: true,
   377  		},
   378  		{
   379  			name:     "critical pod using system priority and systemNodeCritical",
   380  			pod:      getTestPod(nil, &systemPriority, scheduling.SystemNodeCritical),
   381  			expected: true,
   382  		},
   383  		{
   384  			name:     "critical pod using greater than system priority and systemNodeCritical",
   385  			pod:      getTestPod(nil, &systemPriorityUpper, scheduling.SystemNodeCritical),
   386  			expected: true,
   387  		},
   388  		{
   389  			name:     "not a critical pod with api server annotation and systemNodeCritical",
   390  			pod:      getTestPod(configSourceAnnotation(ApiserverSource), nil, scheduling.SystemNodeCritical),
   391  			expected: false,
   392  		},
   393  		{
   394  			name:     "not critical if not static, mirror or without a priority and systemNodeCritical",
   395  			pod:      getTestPod(nil, nil, scheduling.SystemNodeCritical),
   396  			expected: false,
   397  		},
   398  		{
   399  			name:     "not critical if not static, mirror or without a priority",
   400  			pod:      getTestPod(nil, nil, ""),
   401  			expected: false,
   402  		},
   403  	}
   404  	for _, test := range tests {
   405  		t.Run(test.name, func(t *testing.T) {
   406  			isNodeCriticalPod := IsNodeCriticalPod(test.pod)
   407  			require.Equal(t, test.expected, isNodeCriticalPod)
   408  		})
   409  	}
   410  }