volcano.sh/volcano@v1.9.0/pkg/scheduler/actions/shuffle/shuffle_test.go (about)

     1  /*
     2   Copyright 2022 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 shuffle
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/agiledragon/gomonkey/v2"
    25  	"github.com/golang/mock/gomock"
    26  	v1 "k8s.io/api/core/v1"
    27  	schedulingv1 "k8s.io/api/scheduling/v1"
    28  	"k8s.io/client-go/tools/record"
    29  
    30  	schedulingv1beta1 "volcano.sh/apis/pkg/apis/scheduling/v1beta1"
    31  	"volcano.sh/volcano/pkg/scheduler/api"
    32  	"volcano.sh/volcano/pkg/scheduler/cache"
    33  	"volcano.sh/volcano/pkg/scheduler/conf"
    34  	"volcano.sh/volcano/pkg/scheduler/framework"
    35  	mock_framework "volcano.sh/volcano/pkg/scheduler/framework/mock_gen"
    36  	"volcano.sh/volcano/pkg/scheduler/util"
    37  )
    38  
    39  func TestShuffle(t *testing.T) {
    40  	var tmp *cache.SchedulerCache
    41  	patchUpdateQueueStatus := gomonkey.ApplyMethod(reflect.TypeOf(tmp), "UpdateQueueStatus", func(scCache *cache.SchedulerCache, queue *api.QueueInfo) error {
    42  		return nil
    43  	})
    44  	defer patchUpdateQueueStatus.Reset()
    45  
    46  	var highPriority int32
    47  	var lowPriority int32
    48  	highPriority = 100
    49  	lowPriority = 10
    50  
    51  	ctl := gomock.NewController(t)
    52  	fakePlugin := mock_framework.NewMockPlugin(ctl)
    53  	fakePlugin.EXPECT().Name().AnyTimes().Return("fake")
    54  	fakePlugin.EXPECT().OnSessionOpen(gomock.Any()).Return()
    55  	fakePlugin.EXPECT().OnSessionClose(gomock.Any()).Return()
    56  	fakePluginBuilder := func(arguments framework.Arguments) framework.Plugin {
    57  		return fakePlugin
    58  	}
    59  	framework.RegisterPluginBuilder("fake", fakePluginBuilder)
    60  
    61  	tests := []struct {
    62  		name      string
    63  		podGroups []*schedulingv1beta1.PodGroup
    64  		pods      []*v1.Pod
    65  		nodes     []*v1.Node
    66  		queues    []*schedulingv1beta1.Queue
    67  		expected  int
    68  	}{
    69  		{
    70  			name: "select pods with low priority and evict them",
    71  			nodes: []*v1.Node{
    72  				util.BuildNode("node1", api.BuildResourceList("4", "8Gi", []api.ScalarResource{{Name: "pods", Value: "10"}}...), make(map[string]string)),
    73  				util.BuildNode("node2", api.BuildResourceList("4", "8Gi", []api.ScalarResource{{Name: "pods", Value: "10"}}...), make(map[string]string)),
    74  			},
    75  			queues: []*schedulingv1beta1.Queue{
    76  				util.BuildQueue("default", 1, nil),
    77  			},
    78  			podGroups: []*schedulingv1beta1.PodGroup{
    79  				util.BuildPodGroup("pg1", "test", "default", 0, nil, schedulingv1beta1.PodGroupRunning),
    80  				util.BuildPodGroup("pg2", "test", "default", 0, nil, schedulingv1beta1.PodGroupRunning),
    81  				util.BuildPodGroup("pg3", "test", "default", 0, nil, schedulingv1beta1.PodGroupRunning),
    82  			},
    83  			pods: []*v1.Pod{
    84  				util.BuildPodWithPriority("test", "pod1-1", "node1", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg1", make(map[string]string), make(map[string]string), &lowPriority),
    85  				util.BuildPodWithPriority("test", "pod1-2", "node1", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg1", make(map[string]string), make(map[string]string), &highPriority),
    86  				util.BuildPodWithPriority("test", "pod1-3", "node1", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg1", make(map[string]string), make(map[string]string), &highPriority),
    87  				util.BuildPodWithPriority("test", "pod2-1", "node1", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg2", make(map[string]string), make(map[string]string), &lowPriority),
    88  				util.BuildPodWithPriority("test", "pod2-2", "node2", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg2", make(map[string]string), make(map[string]string), &highPriority),
    89  				util.BuildPodWithPriority("test", "pod3-1", "node2", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg3", make(map[string]string), make(map[string]string), &lowPriority),
    90  				util.BuildPodWithPriority("test", "pod3-2", "node2", v1.PodRunning, api.BuildResourceList("1", "2G"), "pg3", make(map[string]string), make(map[string]string), &highPriority),
    91  			},
    92  			expected: 3,
    93  		},
    94  	}
    95  	shuffle := New()
    96  
    97  	for i, test := range tests {
    98  		binder := &util.FakeBinder{
    99  			Binds:   map[string]string{},
   100  			Channel: make(chan string, 1),
   101  		}
   102  		evictor := &util.FakeEvictor{
   103  			Channel: make(chan string),
   104  		}
   105  		schedulerCache := &cache.SchedulerCache{
   106  			Nodes:           make(map[string]*api.NodeInfo),
   107  			Jobs:            make(map[api.JobID]*api.JobInfo),
   108  			Queues:          make(map[api.QueueID]*api.QueueInfo),
   109  			Binder:          binder,
   110  			Evictor:         evictor,
   111  			StatusUpdater:   &util.FakeStatusUpdater{},
   112  			VolumeBinder:    &util.FakeVolumeBinder{},
   113  			PriorityClasses: make(map[string]*schedulingv1.PriorityClass),
   114  
   115  			Recorder: record.NewFakeRecorder(100),
   116  		}
   117  		schedulerCache.PriorityClasses["high-priority"] = &schedulingv1.PriorityClass{
   118  			Value: highPriority,
   119  		}
   120  		schedulerCache.PriorityClasses["low-priority"] = &schedulingv1.PriorityClass{
   121  			Value: lowPriority,
   122  		}
   123  
   124  		for _, node := range test.nodes {
   125  			schedulerCache.AddOrUpdateNode(node)
   126  		}
   127  		for _, q := range test.queues {
   128  			schedulerCache.AddQueueV1beta1(q)
   129  		}
   130  		for _, ss := range test.podGroups {
   131  			schedulerCache.AddPodGroupV1beta1(ss)
   132  		}
   133  		for _, pod := range test.pods {
   134  			schedulerCache.AddPod(pod)
   135  		}
   136  
   137  		trueValue := true
   138  		ssn := framework.OpenSession(schedulerCache, []conf.Tier{
   139  			{
   140  				Plugins: []conf.PluginOption{
   141  					{
   142  						Name:          "fake",
   143  						EnabledVictim: &trueValue,
   144  					},
   145  				},
   146  			},
   147  		}, nil)
   148  		defer framework.CloseSession(ssn)
   149  
   150  		fakePluginVictimFns := func() []api.VictimTasksFn {
   151  			victimTasksFn := func(candidates []*api.TaskInfo) []*api.TaskInfo {
   152  				evicts := make([]*api.TaskInfo, 0)
   153  				for _, task := range candidates {
   154  					if task.Priority == lowPriority {
   155  						evicts = append(evicts, task)
   156  					}
   157  				}
   158  				return evicts
   159  			}
   160  
   161  			victimTasksFns := make([]api.VictimTasksFn, 0)
   162  			victimTasksFns = append(victimTasksFns, victimTasksFn)
   163  			return victimTasksFns
   164  		}
   165  		ssn.AddVictimTasksFns("fake", fakePluginVictimFns())
   166  
   167  		shuffle.Execute(ssn)
   168  		for {
   169  			select {
   170  			case <-evictor.Channel:
   171  			case <-time.After(2 * time.Second):
   172  				goto LOOP
   173  			}
   174  		}
   175  
   176  	LOOP:
   177  		if test.expected != len(evictor.Evicts()) {
   178  			t.Errorf("case %d (%s): expected: %v, got %v ", i, test.name, test.expected, len(evictor.Evicts()))
   179  		}
   180  	}
   181  }