@@ -29,7 +29,14 @@ import (
29
29
"k8s.io/apimachinery/pkg/runtime"
30
30
"k8s.io/apiserver/pkg/admission"
31
31
"k8s.io/apiserver/pkg/authentication/user"
32
+ "k8s.io/client-go/informers"
33
+ "k8s.io/client-go/kubernetes"
34
+ "k8s.io/client-go/kubernetes/fake"
35
+ "k8s.io/component-base/featuregate"
32
36
"k8s.io/kubernetes/pkg/apis/core"
37
+ api "k8s.io/kubernetes/pkg/apis/core"
38
+ "k8s.io/kubernetes/pkg/controller"
39
+ "k8s.io/kubernetes/pkg/features"
33
40
34
41
"github.com/stretchr/testify/assert"
35
42
)
@@ -315,6 +322,150 @@ func NewObjectInterfacesForTest() admission.ObjectInterfaces {
315
322
return admission .NewObjectInterfacesFromScheme (scheme )
316
323
}
317
324
325
+ func newRuntimeClassForTest (runtimeClassEnabled bool ,
326
+ featureInspection bool ,
327
+ addLister bool ,
328
+ listerObject * v1beta1.RuntimeClass ,
329
+ addClient bool ,
330
+ clientObject * v1beta1.RuntimeClass ) * RuntimeClass {
331
+ runtimeClass := NewRuntimeClass ()
332
+
333
+ if featureInspection {
334
+ relevantFeatures := map [featuregate.Feature ]featuregate.FeatureSpec {
335
+ features .RuntimeClass : {Default : runtimeClassEnabled },
336
+ features .PodOverhead : {Default : false },
337
+ }
338
+ fg := featuregate .NewFeatureGate ()
339
+ fg .Add (relevantFeatures )
340
+ runtimeClass .InspectFeatureGates (fg )
341
+ }
342
+
343
+ if addLister {
344
+ informerFactory := informers .NewSharedInformerFactory (nil , controller .NoResyncPeriodFunc ())
345
+ runtimeClass .SetExternalKubeInformerFactory (informerFactory )
346
+ if listerObject != nil {
347
+ informerFactory .Node ().V1beta1 ().RuntimeClasses ().Informer ().GetStore ().Add (listerObject )
348
+ }
349
+ }
350
+
351
+ if addClient {
352
+ var client kubernetes.Interface
353
+ if clientObject != nil {
354
+ client = fake .NewSimpleClientset (clientObject )
355
+ } else {
356
+ client = fake .NewSimpleClientset ()
357
+ }
358
+ runtimeClass .SetExternalKubeClientSet (client )
359
+ }
360
+
361
+ return runtimeClass
362
+ }
363
+
364
+ func TestValidateInitialization (t * testing.T ) {
365
+ tests := []struct {
366
+ name string
367
+ expectError bool
368
+ runtimeClass * RuntimeClass
369
+ }{
370
+ {
371
+ name : "runtimeClass disabled, success" ,
372
+ expectError : false ,
373
+ runtimeClass : newRuntimeClassForTest (false , true , true , nil , true , nil ),
374
+ },
375
+ {
376
+ name : "runtimeClass enabled, success" ,
377
+ expectError : false ,
378
+ runtimeClass : newRuntimeClassForTest (true , true , true , nil , true , nil ),
379
+ },
380
+ {
381
+ name : "runtimeClass enabled, no feature inspection" ,
382
+ expectError : true ,
383
+ runtimeClass : newRuntimeClassForTest (true , false , true , nil , true , nil ),
384
+ },
385
+ {
386
+ name : "runtimeClass enabled, no lister" ,
387
+ expectError : true ,
388
+ runtimeClass : newRuntimeClassForTest (true , true , false , nil , true , nil ),
389
+ },
390
+ {
391
+ name : "runtimeClass enabled, no client" ,
392
+ expectError : true ,
393
+ runtimeClass : newRuntimeClassForTest (true , true , true , nil , false , nil ),
394
+ },
395
+ }
396
+
397
+ for _ , tc := range tests {
398
+ t .Run (tc .name , func (t * testing.T ) {
399
+ err := tc .runtimeClass .ValidateInitialization ()
400
+ if tc .expectError {
401
+ assert .NotEmpty (t , err )
402
+ } else {
403
+ assert .Empty (t , err )
404
+ }
405
+ })
406
+ }
407
+ }
408
+
409
+ func TestAdmit (t * testing.T ) {
410
+ runtimeClassName := "runtimeClassName"
411
+
412
+ rc := & v1beta1.RuntimeClass {
413
+ ObjectMeta : metav1.ObjectMeta {Name : runtimeClassName },
414
+ }
415
+
416
+ pod := api.Pod {
417
+ ObjectMeta : metav1.ObjectMeta {Name : "podname" },
418
+ Spec : api.PodSpec {
419
+ RuntimeClassName : & runtimeClassName ,
420
+ },
421
+ }
422
+
423
+ attributes := admission .NewAttributesRecord (& pod ,
424
+ nil ,
425
+ api .Kind ("kind" ).WithVersion ("version" ),
426
+ "" ,
427
+ "" ,
428
+ api .Resource ("pods" ).WithVersion ("version" ),
429
+ "" ,
430
+ admission .Create ,
431
+ nil ,
432
+ false ,
433
+ nil )
434
+
435
+ tests := []struct {
436
+ name string
437
+ expectError bool
438
+ runtimeClass * RuntimeClass
439
+ }{
440
+ {
441
+ name : "runtimeClass found by lister" ,
442
+ expectError : false ,
443
+ runtimeClass : newRuntimeClassForTest (true , true , true , rc , true , nil ),
444
+ },
445
+ {
446
+ name : "runtimeClass found by client" ,
447
+ expectError : false ,
448
+ runtimeClass : newRuntimeClassForTest (true , true , true , nil , true , rc ),
449
+ },
450
+ {
451
+ name : "runtimeClass not found by lister nor client" ,
452
+ expectError : true ,
453
+ runtimeClass : newRuntimeClassForTest (true , true , true , nil , true , nil ),
454
+ },
455
+ }
456
+
457
+ for _ , tc := range tests {
458
+ t .Run (tc .name , func (t * testing.T ) {
459
+ err := tc .runtimeClass .Admit (context .TODO (), attributes , nil )
460
+ if tc .expectError {
461
+ assert .NotEmpty (t , err )
462
+ } else {
463
+ assert .Empty (t , err )
464
+ }
465
+ })
466
+ }
467
+ }
468
+
318
469
func TestValidate (t * testing.T ) {
319
470
tests := []struct {
320
471
name string
0 commit comments