volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/pdb/pdb_test.go (about)

     1  /*
     2  Copyright 2023 The Volcano 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 pdb
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	pdbPolicy "k8s.io/api/policy/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/client-go/informers"
    27  	"k8s.io/client-go/kubernetes/fake"
    28  	"volcano.sh/volcano/pkg/scheduler/api"
    29  	"volcano.sh/volcano/pkg/scheduler/cache"
    30  	"volcano.sh/volcano/pkg/scheduler/conf"
    31  	"volcano.sh/volcano/pkg/scheduler/framework"
    32  )
    33  
    34  const LabelName = "volcano.sh/job-name"
    35  
    36  func TestPreemptableAndReclaimableFn(t *testing.T) {
    37  	// 1. init task1 and task2
    38  	task1 := api.NewTaskInfo(makePod("test-pod1", map[string]string{LabelName: "job-1"}))
    39  	task2 := api.NewTaskInfo(makePod("test-pod2", map[string]string{LabelName: "job-1"}))
    40  	// 2. init tests
    41  	// (a. test without pdb
    42  	// (b. test with pdb, but no tasks can be evicted
    43  	// (c. test with pdb, but only test1 can be evicted
    44  	tests := []struct {
    45  		name             string
    46  		pdbs             []*pdbPolicy.PodDisruptionBudget
    47  		preemptees       []*api.TaskInfo
    48  		expectVictims    []*api.TaskInfo
    49  		expectVictimsMap map[*api.TaskInfo]bool
    50  	}{{
    51  		name:             "test without pdbs",
    52  		pdbs:             nil,
    53  		preemptees:       []*api.TaskInfo{task1, task2},
    54  		expectVictims:    []*api.TaskInfo{task1, task2},
    55  		expectVictimsMap: map[*api.TaskInfo]bool{task1: true, task2: true},
    56  	}, {
    57  		name: "test with pdbs(can evict 0 pod)",
    58  		pdbs: []*pdbPolicy.PodDisruptionBudget{
    59  			{
    60  				ObjectMeta: metav1.ObjectMeta{
    61  					Name:      "test-pdb",
    62  					Namespace: "default",
    63  				},
    64  				Spec:   pdbPolicy.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{LabelName: "job-1"}}},
    65  				Status: pdbPolicy.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
    66  			},
    67  		},
    68  		preemptees:       []*api.TaskInfo{task1, task2},
    69  		expectVictims:    nil,
    70  		expectVictimsMap: make(map[*api.TaskInfo]bool),
    71  	}, {
    72  		name: "test with pdbs(can evict 1 pod)",
    73  		pdbs: []*pdbPolicy.PodDisruptionBudget{
    74  			{
    75  				ObjectMeta: metav1.ObjectMeta{
    76  					Name:      "test-pdb",
    77  					Namespace: "default",
    78  				},
    79  				Spec:   pdbPolicy.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{LabelName: "job-1"}}},
    80  				Status: pdbPolicy.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
    81  			},
    82  		},
    83  		preemptees:       []*api.TaskInfo{task1, task2},
    84  		expectVictims:    []*api.TaskInfo{task1},
    85  		expectVictimsMap: map[*api.TaskInfo]bool{task1: true},
    86  	},
    87  	}
    88  
    89  	// 3. set the test plugin name and fns
    90  	enabled := true
    91  	pluginOption := conf.PluginOption{
    92  		Name:               PluginName,
    93  		EnabledPreemptable: &enabled,
    94  		EnabledReclaimable: &enabled,
    95  		EnabledVictim:      &enabled,
    96  	}
    97  
    98  	// 4. range every test
    99  	for _, test := range tests {
   100  
   101  		// (a. set the fake informerFactory and add pdbs to pdb informer
   102  		client := fake.NewSimpleClientset()
   103  		informerFactory := informers.NewSharedInformerFactory(client, 0)
   104  		informer := informerFactory.Policy().V1().PodDisruptionBudgets().Informer()
   105  		for _, pdb := range test.pdbs {
   106  			informer.GetStore().Add(pdb)
   107  		}
   108  
   109  		// (b. set the SchedulerCache
   110  		schedulerCache := &cache.SchedulerCache{}
   111  		schedulerCache.SetSharedInformerFactory(informerFactory)
   112  
   113  		// (c. set the Session with preempt, reclaim and shuffle action
   114  		ssn := framework.OpenSession(schedulerCache, []conf.Tier{
   115  			{
   116  				Plugins: []conf.PluginOption{pluginOption},
   117  			},
   118  		},
   119  			[]conf.Configuration{
   120  				{
   121  					Name: "preempt",
   122  				},
   123  				{
   124  					Name: "reclaim",
   125  				},
   126  				{
   127  					Name: "shuffle",
   128  				},
   129  			},
   130  		)
   131  
   132  		// (d. register actions
   133  		plugin := &pdbPlugin{}
   134  		plugin.OnSessionOpen(ssn) // register preempt fn
   135  
   136  		// (e. test the Preemptable in pdb plugin
   137  		victims := ssn.Preemptable(&api.TaskInfo{}, test.preemptees)
   138  		if !reflect.DeepEqual(test.expectVictims, victims) {
   139  			t.Errorf("Test of preemptable: test name: %s, expected: %v, got %v ", test.name, test.expectVictims, victims)
   140  		}
   141  
   142  		// (f. test the Reclaimable in pdb plugin
   143  		victims = ssn.Reclaimable(&api.TaskInfo{}, test.preemptees)
   144  		if !reflect.DeepEqual(test.expectVictims, victims) {
   145  			t.Errorf("Test of reclaimable: test name: %s, expected: %v, got %v ", test.name, test.expectVictims, victims)
   146  		}
   147  
   148  		// (g. test the VictimTasks in pdb plugin
   149  		victimsMap := ssn.VictimTasks(test.preemptees)
   150  		if !reflect.DeepEqual(test.expectVictimsMap, victimsMap) {
   151  			t.Errorf("Test of victimTasks: test name %s, expected: %v, got %v ", test.name, test.expectVictims, victims)
   152  		}
   153  	}
   154  }
   155  
   156  func makePod(name string, labels map[string]string) *v1.Pod {
   157  	return &v1.Pod{
   158  		ObjectMeta: metav1.ObjectMeta{
   159  			Name:      name,
   160  			Namespace: "default",
   161  			Labels:    labels,
   162  		},
   163  		Spec: v1.PodSpec{
   164  			Containers: []v1.Container{
   165  				{},
   166  			},
   167  		},
   168  	}
   169  }