...

Source file src/k8s.io/kubernetes/plugin/pkg/admission/runtimeclass/admission_test.go

Documentation: k8s.io/kubernetes/plugin/pkg/admission/runtimeclass

     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 runtimeclass
    18  
    19  import (
    20  	"context"
    21  	"strconv"
    22  	"testing"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  	nodev1 "k8s.io/api/node/v1"
    26  	"k8s.io/apimachinery/pkg/api/resource"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apiserver/pkg/admission"
    30  	"k8s.io/apiserver/pkg/authentication/user"
    31  	"k8s.io/client-go/informers"
    32  	"k8s.io/client-go/kubernetes"
    33  	"k8s.io/client-go/kubernetes/fake"
    34  	"k8s.io/kubernetes/pkg/apis/core"
    35  	"k8s.io/kubernetes/pkg/controller"
    36  
    37  	"github.com/stretchr/testify/assert"
    38  )
    39  
    40  func newOverheadValidPod(name string, numContainers int, resources core.ResourceRequirements, setOverhead bool) *core.Pod {
    41  	pod := &core.Pod{
    42  		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test"},
    43  		Spec:       core.PodSpec{},
    44  	}
    45  	pod.Spec.Containers = make([]core.Container, 0, numContainers)
    46  	for i := 0; i < numContainers; i++ {
    47  		pod.Spec.Containers = append(pod.Spec.Containers, core.Container{
    48  			Image:     "foo:V" + strconv.Itoa(i),
    49  			Resources: resources,
    50  			Name:      "foo-" + strconv.Itoa(i),
    51  		})
    52  	}
    53  
    54  	if setOverhead {
    55  		pod.Spec.Overhead = core.ResourceList{
    56  			core.ResourceName(core.ResourceCPU):    resource.MustParse("100m"),
    57  			core.ResourceName(core.ResourceMemory): resource.MustParse("1"),
    58  		}
    59  	}
    60  	return pod
    61  }
    62  
    63  func newSchedulingValidPod(name string, nodeSelector map[string]string, tolerations []core.Toleration) *core.Pod {
    64  	return &core.Pod{
    65  		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test"},
    66  		Spec: core.PodSpec{
    67  			NodeSelector: nodeSelector,
    68  			Tolerations:  tolerations,
    69  		},
    70  	}
    71  }
    72  
    73  func getGuaranteedRequirements() core.ResourceRequirements {
    74  	resources := core.ResourceList{
    75  		core.ResourceName(core.ResourceCPU):    resource.MustParse("1"),
    76  		core.ResourceName(core.ResourceMemory): resource.MustParse("10"),
    77  	}
    78  
    79  	return core.ResourceRequirements{Limits: resources, Requests: resources}
    80  }
    81  
    82  func TestSetOverhead(t *testing.T) {
    83  	tests := []struct {
    84  		name         string
    85  		runtimeClass *nodev1.RuntimeClass
    86  		pod          *core.Pod
    87  		expectError  bool
    88  		expectedPod  *core.Pod
    89  	}{
    90  		{
    91  			name: "overhead, no container requirements",
    92  			runtimeClass: &nodev1.RuntimeClass{
    93  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
    94  				Handler:    "bar",
    95  				Overhead: &nodev1.Overhead{
    96  					PodFixed: corev1.ResourceList{
    97  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
    98  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
    99  					},
   100  				},
   101  			},
   102  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, false),
   103  			expectError: false,
   104  			expectedPod: newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, true),
   105  		},
   106  		{
   107  			name: "overhead, guaranteed pod",
   108  			runtimeClass: &nodev1.RuntimeClass{
   109  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   110  				Handler:    "bar",
   111  				Overhead: &nodev1.Overhead{
   112  					PodFixed: corev1.ResourceList{
   113  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
   114  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
   115  					},
   116  				},
   117  			},
   118  			pod:         newOverheadValidPod("guaranteed", 1, getGuaranteedRequirements(), false),
   119  			expectError: false,
   120  			expectedPod: newOverheadValidPod("guaranteed", 1, core.ResourceRequirements{}, true),
   121  		},
   122  		{
   123  			name: "overhead, pod with differing overhead already set",
   124  			runtimeClass: &nodev1.RuntimeClass{
   125  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   126  				Handler:    "bar",
   127  				Overhead: &nodev1.Overhead{
   128  					PodFixed: corev1.ResourceList{
   129  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("10"),
   130  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
   131  					},
   132  				},
   133  			},
   134  			pod:         newOverheadValidPod("empty-requiremennts-overhead", 1, core.ResourceRequirements{}, true),
   135  			expectError: true,
   136  			expectedPod: nil,
   137  		},
   138  		{
   139  			name: "overhead, pod with same overhead already set",
   140  			runtimeClass: &nodev1.RuntimeClass{
   141  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   142  				Handler:    "bar",
   143  				Overhead: &nodev1.Overhead{
   144  					PodFixed: corev1.ResourceList{
   145  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
   146  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
   147  					},
   148  				},
   149  			},
   150  			pod:         newOverheadValidPod("empty-requiremennts-overhead", 1, core.ResourceRequirements{}, true),
   151  			expectError: false,
   152  			expectedPod: nil,
   153  		},
   154  	}
   155  
   156  	for _, tc := range tests {
   157  		t.Run(tc.name, func(t *testing.T) {
   158  
   159  			attrs := admission.NewAttributesRecord(tc.pod, nil, core.Kind("Pod").WithVersion("version"), tc.pod.Namespace, tc.pod.Name, core.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, &user.DefaultInfo{})
   160  
   161  			errs := setOverhead(attrs, tc.pod, tc.runtimeClass)
   162  			if tc.expectError {
   163  				assert.NotEmpty(t, errs)
   164  			} else {
   165  				assert.Empty(t, errs)
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func TestSetScheduling(t *testing.T) {
   172  	tests := []struct {
   173  		name         string
   174  		runtimeClass *nodev1.RuntimeClass
   175  		pod          *core.Pod
   176  		expectError  bool
   177  		expectedPod  *core.Pod
   178  	}{
   179  		{
   180  			name: "scheduling, nil scheduling",
   181  			runtimeClass: &nodev1.RuntimeClass{
   182  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   183  				Handler:    "bar",
   184  				Scheduling: nil,
   185  			},
   186  			pod:         newSchedulingValidPod("pod-with-conflict-node-selector", map[string]string{"foo": "bar"}, []core.Toleration{}),
   187  			expectError: false,
   188  			expectedPod: newSchedulingValidPod("pod-with-conflict-node-selector", map[string]string{"foo": "bar"}, []core.Toleration{}),
   189  		},
   190  		{
   191  			name: "scheduling, conflict node selector",
   192  			runtimeClass: &nodev1.RuntimeClass{
   193  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   194  				Handler:    "bar",
   195  				Scheduling: &nodev1.Scheduling{
   196  					NodeSelector: map[string]string{
   197  						"foo": "conflict",
   198  					},
   199  				},
   200  			},
   201  			pod:         newSchedulingValidPod("pod-with-conflict-node-selector", map[string]string{"foo": "bar"}, []core.Toleration{}),
   202  			expectError: true,
   203  		},
   204  		{
   205  			name: "scheduling, nil node selector",
   206  			runtimeClass: &nodev1.RuntimeClass{
   207  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   208  				Handler:    "bar",
   209  				Scheduling: &nodev1.Scheduling{
   210  					NodeSelector: map[string]string{
   211  						"foo": "bar",
   212  					},
   213  				},
   214  			},
   215  			pod:         newSchedulingValidPod("pod-with-conflict-node-selector", nil, nil),
   216  			expectError: false,
   217  			expectedPod: newSchedulingValidPod("pod-with-conflict-node-selector", map[string]string{"foo": "bar"}, nil),
   218  		},
   219  		{
   220  			name: "scheduling, node selector with the same key value",
   221  			runtimeClass: &nodev1.RuntimeClass{
   222  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   223  				Handler:    "bar",
   224  				Scheduling: &nodev1.Scheduling{
   225  					NodeSelector: map[string]string{
   226  						"foo": "bar",
   227  					},
   228  				},
   229  			},
   230  			pod:         newSchedulingValidPod("pod-with-same-key-value-node-selector", map[string]string{"foo": "bar"}, nil),
   231  			expectError: false,
   232  			expectedPod: newSchedulingValidPod("pod-with-same-key-value-node-selector", map[string]string{"foo": "bar"}, nil),
   233  		},
   234  		{
   235  			name: "scheduling, node selector with different key value",
   236  			runtimeClass: &nodev1.RuntimeClass{
   237  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   238  				Handler:    "bar",
   239  				Scheduling: &nodev1.Scheduling{
   240  					NodeSelector: map[string]string{
   241  						"foo":  "bar",
   242  						"fizz": "buzz",
   243  					},
   244  				},
   245  			},
   246  			pod:         newSchedulingValidPod("pod-with-different-key-value-node-selector", map[string]string{"foo": "bar"}, nil),
   247  			expectError: false,
   248  			expectedPod: newSchedulingValidPod("pod-with-different-key-value-node-selector", map[string]string{"foo": "bar", "fizz": "buzz"}, nil),
   249  		},
   250  		{
   251  			name: "scheduling, multiple tolerations",
   252  			runtimeClass: &nodev1.RuntimeClass{
   253  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   254  				Handler:    "bar",
   255  				Scheduling: &nodev1.Scheduling{
   256  					Tolerations: []corev1.Toleration{
   257  						{
   258  							Key:      "foo",
   259  							Operator: corev1.TolerationOpEqual,
   260  							Value:    "bar",
   261  							Effect:   corev1.TaintEffectNoSchedule,
   262  						},
   263  						{
   264  							Key:      "fizz",
   265  							Operator: corev1.TolerationOpEqual,
   266  							Value:    "buzz",
   267  							Effect:   corev1.TaintEffectNoSchedule,
   268  						},
   269  					},
   270  				},
   271  			},
   272  			pod: newSchedulingValidPod("pod-with-tolerations", map[string]string{"foo": "bar"},
   273  				[]core.Toleration{
   274  					{
   275  						Key:      "foo",
   276  						Operator: core.TolerationOpEqual,
   277  						Value:    "bar",
   278  						Effect:   core.TaintEffectNoSchedule,
   279  					},
   280  				}),
   281  			expectError: false,
   282  			expectedPod: newSchedulingValidPod("pod-with-tolerations", map[string]string{"foo": "bar"},
   283  				[]core.Toleration{
   284  					{
   285  						Key:      "foo",
   286  						Operator: core.TolerationOpEqual,
   287  						Value:    "bar",
   288  						Effect:   core.TaintEffectNoSchedule,
   289  					},
   290  					{
   291  						Key:      "fizz",
   292  						Operator: core.TolerationOpEqual,
   293  						Value:    "buzz",
   294  						Effect:   core.TaintEffectNoSchedule,
   295  					},
   296  				}),
   297  		},
   298  	}
   299  
   300  	for _, tc := range tests {
   301  		t.Run(tc.name, func(t *testing.T) {
   302  			attrs := admission.NewAttributesRecord(tc.pod, nil, core.Kind("Pod").WithVersion("version"), tc.pod.Namespace, tc.pod.Name, core.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, &user.DefaultInfo{})
   303  
   304  			errs := setScheduling(attrs, tc.pod, tc.runtimeClass)
   305  			if tc.expectError {
   306  				assert.NotEmpty(t, errs)
   307  			} else {
   308  				assert.Equal(t, tc.expectedPod, tc.pod)
   309  				assert.Empty(t, errs)
   310  			}
   311  		})
   312  	}
   313  }
   314  
   315  func NewObjectInterfacesForTest() admission.ObjectInterfaces {
   316  	scheme := runtime.NewScheme()
   317  	corev1.AddToScheme(scheme)
   318  	return admission.NewObjectInterfacesFromScheme(scheme)
   319  }
   320  
   321  func newRuntimeClassForTest(
   322  	addLister bool,
   323  	listerObject *nodev1.RuntimeClass,
   324  	addClient bool,
   325  	clientObject *nodev1.RuntimeClass) *RuntimeClass {
   326  	runtimeClass := NewRuntimeClass()
   327  
   328  	if addLister {
   329  		informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
   330  		runtimeClass.SetExternalKubeInformerFactory(informerFactory)
   331  		if listerObject != nil {
   332  			informerFactory.Node().V1().RuntimeClasses().Informer().GetStore().Add(listerObject)
   333  		}
   334  	}
   335  
   336  	if addClient {
   337  		var client kubernetes.Interface
   338  		if clientObject != nil {
   339  			client = fake.NewSimpleClientset(clientObject)
   340  		} else {
   341  			client = fake.NewSimpleClientset()
   342  		}
   343  		runtimeClass.SetExternalKubeClientSet(client)
   344  	}
   345  
   346  	return runtimeClass
   347  }
   348  
   349  func TestValidateInitialization(t *testing.T) {
   350  	tests := []struct {
   351  		name         string
   352  		expectError  bool
   353  		runtimeClass *RuntimeClass
   354  	}{
   355  		{
   356  			name:         "runtimeClass enabled, success",
   357  			expectError:  false,
   358  			runtimeClass: newRuntimeClassForTest(true, nil, true, nil),
   359  		},
   360  		{
   361  			name:         "runtimeClass enabled, no lister",
   362  			expectError:  true,
   363  			runtimeClass: newRuntimeClassForTest(false, nil, true, nil),
   364  		},
   365  		{
   366  			name:         "runtimeClass enabled, no client",
   367  			expectError:  true,
   368  			runtimeClass: newRuntimeClassForTest(true, nil, false, nil),
   369  		},
   370  	}
   371  
   372  	for _, tc := range tests {
   373  		t.Run(tc.name, func(t *testing.T) {
   374  			err := tc.runtimeClass.ValidateInitialization()
   375  			if tc.expectError {
   376  				assert.NotEmpty(t, err)
   377  			} else {
   378  				assert.Empty(t, err)
   379  			}
   380  		})
   381  	}
   382  }
   383  
   384  func TestAdmit(t *testing.T) {
   385  	runtimeClassName := "runtimeClassName"
   386  
   387  	rc := &nodev1.RuntimeClass{
   388  		ObjectMeta: metav1.ObjectMeta{Name: runtimeClassName},
   389  	}
   390  
   391  	pod := core.Pod{
   392  		ObjectMeta: metav1.ObjectMeta{Name: "podname"},
   393  		Spec: core.PodSpec{
   394  			RuntimeClassName: &runtimeClassName,
   395  		},
   396  	}
   397  
   398  	attributes := admission.NewAttributesRecord(&pod,
   399  		nil,
   400  		core.Kind("kind").WithVersion("version"),
   401  		"",
   402  		"",
   403  		core.Resource("pods").WithVersion("version"),
   404  		"",
   405  		admission.Create,
   406  		nil,
   407  		false,
   408  		nil)
   409  
   410  	tests := []struct {
   411  		name         string
   412  		expectError  bool
   413  		runtimeClass *RuntimeClass
   414  	}{
   415  		{
   416  			name:         "runtimeClass found by lister",
   417  			expectError:  false,
   418  			runtimeClass: newRuntimeClassForTest(true, rc, true, nil),
   419  		},
   420  		{
   421  			name:         "runtimeClass found by client",
   422  			expectError:  false,
   423  			runtimeClass: newRuntimeClassForTest(true, nil, true, rc),
   424  		},
   425  		{
   426  			name:         "runtimeClass not found by lister nor client",
   427  			expectError:  true,
   428  			runtimeClass: newRuntimeClassForTest(true, nil, true, nil),
   429  		},
   430  	}
   431  
   432  	for _, tc := range tests {
   433  		t.Run(tc.name, func(t *testing.T) {
   434  			err := tc.runtimeClass.Admit(context.TODO(), attributes, nil)
   435  			if tc.expectError {
   436  				assert.NotEmpty(t, err)
   437  			} else {
   438  				assert.Empty(t, err)
   439  			}
   440  		})
   441  	}
   442  }
   443  
   444  func TestValidate(t *testing.T) {
   445  	tests := []struct {
   446  		name         string
   447  		runtimeClass *nodev1.RuntimeClass
   448  		pod          *core.Pod
   449  		expectError  bool
   450  	}{
   451  		{
   452  			name: "No Overhead in RunntimeClass, Overhead set in pod",
   453  			runtimeClass: &nodev1.RuntimeClass{
   454  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   455  				Handler:    "bar",
   456  			},
   457  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, getGuaranteedRequirements(), true),
   458  			expectError: true,
   459  		},
   460  		{
   461  			name: "Non-matching Overheads",
   462  			runtimeClass: &nodev1.RuntimeClass{
   463  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   464  				Handler:    "bar",
   465  				Overhead: &nodev1.Overhead{
   466  					PodFixed: corev1.ResourceList{
   467  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("10"),
   468  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
   469  					},
   470  				},
   471  			},
   472  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, true),
   473  			expectError: true,
   474  		},
   475  		{
   476  			name: "Matching Overheads",
   477  			runtimeClass: &nodev1.RuntimeClass{
   478  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   479  				Handler:    "bar",
   480  				Overhead: &nodev1.Overhead{
   481  					PodFixed: corev1.ResourceList{
   482  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
   483  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
   484  					},
   485  				},
   486  			},
   487  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, false),
   488  			expectError: false,
   489  		},
   490  	}
   491  	rt := NewRuntimeClass()
   492  	o := NewObjectInterfacesForTest()
   493  	for _, tc := range tests {
   494  		t.Run(tc.name, func(t *testing.T) {
   495  
   496  			attrs := admission.NewAttributesRecord(tc.pod, nil, core.Kind("Pod").WithVersion("version"), tc.pod.Namespace, tc.pod.Name, core.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, &user.DefaultInfo{})
   497  
   498  			errs := rt.Validate(context.TODO(), attrs, o)
   499  			if tc.expectError {
   500  				assert.NotEmpty(t, errs)
   501  			} else {
   502  				assert.Empty(t, errs)
   503  			}
   504  		})
   505  	}
   506  }
   507  
   508  func TestValidateOverhead(t *testing.T) {
   509  	tests := []struct {
   510  		name         string
   511  		runtimeClass *nodev1.RuntimeClass
   512  		pod          *core.Pod
   513  		expectError  bool
   514  	}{
   515  		{
   516  			name: "Overhead part of RuntimeClass, no Overhead defined in pod",
   517  			runtimeClass: &nodev1.RuntimeClass{
   518  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   519  				Handler:    "bar",
   520  				Overhead: &nodev1.Overhead{
   521  					PodFixed: corev1.ResourceList{
   522  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
   523  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
   524  					},
   525  				},
   526  			},
   527  			pod:         newOverheadValidPod("no-requirements", 1, core.ResourceRequirements{}, false),
   528  			expectError: true,
   529  		},
   530  		{
   531  			name: "No Overhead in RunntimeClass, Overhead set in pod",
   532  			runtimeClass: &nodev1.RuntimeClass{
   533  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   534  				Handler:    "bar",
   535  			},
   536  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, getGuaranteedRequirements(), true),
   537  			expectError: true,
   538  		},
   539  		{
   540  			name:         "No RunntimeClass, Overhead set in pod",
   541  			runtimeClass: nil,
   542  			pod:          newOverheadValidPod("no-resource-req-no-overhead", 1, getGuaranteedRequirements(), true),
   543  			expectError:  true,
   544  		},
   545  		{
   546  			name: "Non-matching Overheads",
   547  			runtimeClass: &nodev1.RuntimeClass{
   548  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   549  				Handler:    "bar",
   550  				Overhead: &nodev1.Overhead{
   551  					PodFixed: corev1.ResourceList{
   552  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("10"),
   553  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
   554  					},
   555  				},
   556  			},
   557  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, true),
   558  			expectError: true,
   559  		},
   560  		{
   561  			name: "Matching Overheads",
   562  			runtimeClass: &nodev1.RuntimeClass{
   563  				ObjectMeta: metav1.ObjectMeta{Name: "foo"},
   564  				Handler:    "bar",
   565  				Overhead: &nodev1.Overhead{
   566  					PodFixed: corev1.ResourceList{
   567  						corev1.ResourceName(corev1.ResourceCPU):    resource.MustParse("100m"),
   568  						corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
   569  					},
   570  				},
   571  			},
   572  			pod:         newOverheadValidPod("no-resource-req-no-overhead", 1, core.ResourceRequirements{}, true),
   573  			expectError: false,
   574  		},
   575  	}
   576  
   577  	for _, tc := range tests {
   578  		t.Run(tc.name, func(t *testing.T) {
   579  			attrs := admission.NewAttributesRecord(tc.pod, nil, core.Kind("Pod").WithVersion("version"), tc.pod.Namespace, tc.pod.Name, core.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, &user.DefaultInfo{})
   580  
   581  			errs := validateOverhead(attrs, tc.pod, tc.runtimeClass)
   582  			if tc.expectError {
   583  				assert.NotEmpty(t, errs)
   584  			} else {
   585  				assert.Empty(t, errs)
   586  			}
   587  		})
   588  	}
   589  }
   590  

View as plain text