volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/cdp/cdp_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 cdp
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  
    27  	"volcano.sh/apis/pkg/apis/scheduling/v1beta1"
    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  func makePod(labels map[string]string, annotations map[string]string, podScheduledTime time.Time) *v1.Pod {
    35  	annotations[v1beta1.KubeGroupNameAnnotationKey] = "test-group"
    36  	phase := v1.PodPending
    37  	conditions := []v1.PodCondition{}
    38  	if !podScheduledTime.IsZero() {
    39  		phase = v1.PodRunning
    40  		conditions = append(conditions, v1.PodCondition{
    41  			Type:               v1.PodScheduled,
    42  			LastTransitionTime: metav1.NewTime(podScheduledTime),
    43  			Status:             v1.ConditionTrue,
    44  		})
    45  	}
    46  	return &v1.Pod{
    47  		ObjectMeta: metav1.ObjectMeta{
    48  			Name:        "test-pod",
    49  			Namespace:   "default",
    50  			Labels:      labels,
    51  			Annotations: annotations,
    52  		},
    53  		Status: v1.PodStatus{
    54  			Phase:      phase,
    55  			Conditions: conditions,
    56  		},
    57  		Spec: v1.PodSpec{
    58  			Containers: []v1.Container{
    59  				{},
    60  			},
    61  		},
    62  	}
    63  
    64  }
    65  
    66  func Test_CooldownTimePlugin_podPreemptStableTime(t *testing.T) {
    67  	type args struct {
    68  		pod *v1.Pod
    69  	}
    70  	plugin := &CooldownProtectionPlugin{}
    71  	tests := []struct {
    72  		name        string
    73  		sp          *CooldownProtectionPlugin
    74  		args        args
    75  		wantEnabled bool
    76  		wantValue   time.Duration
    77  	}{
    78  		{
    79  			name: "normal",
    80  			sp:   plugin,
    81  			args: args{
    82  				pod: makePod(map[string]string{},
    83  					map[string]string{v1beta1.CooldownTime: "600s"},
    84  					time.Now().Add(time.Second*-100)),
    85  			},
    86  			wantEnabled: true,
    87  			wantValue:   time.Second * 600,
    88  		},
    89  		{
    90  			name: "not-enabled",
    91  			sp:   plugin,
    92  			args: args{
    93  				pod: makePod(map[string]string{},
    94  					map[string]string{v1beta1.CooldownTime: "600abcde"},
    95  					time.Now().Add(time.Second*-100)),
    96  			},
    97  			wantEnabled: false,
    98  			wantValue:   0,
    99  		},
   100  	}
   101  	for _, tt := range tests {
   102  		t.Run(tt.name, func(t *testing.T) {
   103  			sp := &CooldownProtectionPlugin{}
   104  			gotValue, gotEnabled := sp.podCooldownTime(tt.args.pod)
   105  			if gotEnabled != tt.wantEnabled {
   106  				t.Errorf("CooldownTimePlugin.podPreemptStableTime() gotEnabled = %v, want %v", gotEnabled, tt.wantEnabled)
   107  			}
   108  			if gotValue != tt.wantValue {
   109  				t.Errorf("CooldownTimePlugin.podPreemptStableTime() gotValue = %v, want %v", gotValue, tt.wantValue)
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  func TestPreemptableFn(t *testing.T) {
   116  	plugin := &CooldownProtectionPlugin{}
   117  	enabledPreemptable := true
   118  	pluginOption := conf.PluginOption{
   119  		Name:               PluginName,
   120  		EnabledPreemptable: &enabledPreemptable,
   121  	}
   122  	schedulerCache := &cache.SchedulerCache{}
   123  	ssn := framework.OpenSession(schedulerCache, []conf.Tier{
   124  		{
   125  			Plugins: []conf.PluginOption{pluginOption},
   126  		},
   127  	},
   128  		[]conf.Configuration{
   129  			{
   130  				Name: "preempt",
   131  			},
   132  		},
   133  	)
   134  
   135  	plugin.OnSessionOpen(ssn) // register preempt fn
   136  
   137  	// prepare preemptor and preemptees
   138  	// task1: should be filtered
   139  	task1 := api.NewTaskInfo(
   140  		makePod(map[string]string{v1beta1.PodPreemptable: "true"},
   141  			map[string]string{v1beta1.CooldownTime: "600s"},
   142  			time.Now().Add(time.Second*-100)),
   143  	)
   144  	// task2: invalid label, not enabled
   145  	task2 := api.NewTaskInfo(
   146  		makePod(map[string]string{v1beta1.PodPreemptable: "true"},
   147  			map[string]string{v1beta1.CooldownTime: "600abcde"},
   148  			time.Now().Add(time.Second*-100)),
   149  	)
   150  	// task3: after stable time, can be preempted
   151  	task3 := api.NewTaskInfo(
   152  		makePod(map[string]string{v1beta1.PodPreemptable: "true"},
   153  			map[string]string{v1beta1.CooldownTime: "600s"},
   154  			time.Now().Add(time.Second*-800)),
   155  	)
   156  	preemptees := []*api.TaskInfo{task1, task2, task3}
   157  	victims := ssn.Preemptable(&api.TaskInfo{}, preemptees)
   158  
   159  	expectVictims := []*api.TaskInfo{task2, task3}
   160  	if !reflect.DeepEqual(victims, expectVictims) {
   161  		t.Errorf("stable preempt test not equal! expect victims %v, actual %v", expectVictims, victims)
   162  	}
   163  }