2019-07-29 11:45:01 -04:00
/ *
Copyright 2019 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2020-06-19 05:05:45 -04:00
package runtime
2019-07-29 11:45:01 -04:00
import (
2019-08-28 07:12:02 -04:00
"context"
2020-09-10 11:37:44 -04:00
"errors"
2019-09-09 01:13:15 -04:00
"fmt"
2019-09-26 21:15:32 -04:00
"strings"
2019-07-29 11:45:01 -04:00
"testing"
2019-10-04 10:25:17 -04:00
"time"
2019-07-29 11:45:01 -04:00
2020-04-30 18:11:37 -04:00
"github.com/google/go-cmp/cmp"
2024-09-18 01:55:59 -04:00
2019-08-28 07:12:02 -04:00
v1 "k8s.io/api/core/v1"
2019-08-19 16:08:14 -04:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2019-07-29 11:45:01 -04:00
"k8s.io/apimachinery/pkg/runtime"
2019-11-05 09:04:44 -05:00
"k8s.io/apimachinery/pkg/types"
2021-01-29 01:29:10 -05:00
"k8s.io/apimachinery/pkg/util/sets"
2024-07-22 07:53:08 -04:00
"k8s.io/client-go/informers"
clientsetfake "k8s.io/client-go/kubernetes/fake"
2021-01-29 23:15:22 -05:00
"k8s.io/component-base/metrics/testutil"
2023-05-15 06:36:17 -04:00
"k8s.io/klog/v2/ktesting"
2025-05-21 11:21:27 -04:00
fwk "k8s.io/kube-scheduler/framework"
2019-07-29 11:45:01 -04:00
"k8s.io/kubernetes/pkg/scheduler/apis/config"
2025-03-11 06:08:25 -04:00
"k8s.io/kubernetes/pkg/scheduler/backend/cache"
2024-08-25 00:10:29 -04:00
internalqueue "k8s.io/kubernetes/pkg/scheduler/backend/queue"
2020-10-09 10:41:44 -04:00
"k8s.io/kubernetes/pkg/scheduler/framework"
2019-08-28 07:12:02 -04:00
"k8s.io/kubernetes/pkg/scheduler/metrics"
2023-09-11 10:40:18 -04:00
"k8s.io/utils/ptr"
2019-07-29 11:45:01 -04:00
)
const (
2022-11-07 17:02:22 -05:00
preEnqueuePlugin = "preEnqueue-plugin"
2020-01-15 15:26:22 -05:00
queueSortPlugin = "no-op-queue-sort-plugin"
2019-10-01 11:59:48 -04:00
scoreWithNormalizePlugin1 = "score-with-normalize-plugin-1"
scoreWithNormalizePlugin2 = "score-with-normalize-plugin-2"
scorePlugin1 = "score-plugin-1"
2023-11-29 01:07:27 -05:00
scorePlugin2 = "score-plugin-2"
2019-10-01 11:59:48 -04:00
pluginNotImplementingScore = "plugin-not-implementing-score"
preFilterPluginName = "prefilter-plugin"
preFilterWithExtensionsPluginName = "prefilter-with-extensions-plugin"
2019-09-26 21:15:32 -04:00
duplicatePluginName = "duplicate-plugin"
2019-10-04 10:25:17 -04:00
testPlugin = "test-plugin"
2019-11-05 09:04:44 -05:00
permitPlugin = "permit-plugin"
2020-01-15 11:26:35 -05:00
bindPlugin = "bind-plugin"
2023-12-27 10:18:29 -05:00
testCloseErrorPlugin = "test-close-error-plugin"
2020-06-17 17:49:30 -04:00
2022-09-16 16:18:12 -04:00
testProfileName = "test-profile"
testPercentageOfNodesToScore = 35
nodeName = "testNode"
2022-09-09 11:31:23 -04:00
injectReason = "injected status"
injectFilterReason = "injected filter status"
2019-07-29 11:45:01 -04:00
)
2024-09-25 02:16:31 -04:00
func init ( ) {
metrics . Register ( )
}
2019-08-19 16:08:14 -04:00
// TestScoreWithNormalizePlugin implements ScoreWithNormalizePlugin interface.
// TestScorePlugin only implements ScorePlugin interface.
2025-07-24 07:48:07 -04:00
var _ fwk . ScorePlugin = & TestScoreWithNormalizePlugin { }
var _ fwk . ScorePlugin = & TestScorePlugin { }
2019-07-29 11:45:01 -04:00
2025-01-27 05:01:57 -05:00
var statusCmpOpts = [ ] cmp . Option {
2025-06-03 18:59:50 -04:00
cmp . Comparer ( func ( s1 * fwk . Status , s2 * fwk . Status ) bool {
2023-01-03 01:33:58 -05:00
if s1 == nil || s2 == nil {
return s1 . IsSuccess ( ) && s2 . IsSuccess ( )
}
2025-06-03 18:59:50 -04:00
if s1 . Code ( ) == fwk . Error {
2025-01-27 05:01:57 -05:00
return s1 . AsError ( ) . Error ( ) == s2 . AsError ( ) . Error ( )
}
2023-10-25 08:01:07 -04:00
return s1 . Code ( ) == s2 . Code ( ) && s1 . Plugin ( ) == s2 . Plugin ( ) && s1 . Message ( ) == s2 . Message ( )
2023-01-03 01:33:58 -05:00
} ) ,
}
2025-07-24 07:48:07 -04:00
func newScoreWithNormalizePlugin1 ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-09 01:13:15 -04:00
var inj injectedResult
if err := DecodeInto ( injArgs , & inj ) ; err != nil {
return nil , err
}
return & TestScoreWithNormalizePlugin { scoreWithNormalizePlugin1 , inj } , nil
2019-07-29 11:45:01 -04:00
}
2019-09-09 01:13:15 -04:00
2025-07-24 07:48:07 -04:00
func newScoreWithNormalizePlugin2 ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-09 01:13:15 -04:00
var inj injectedResult
if err := DecodeInto ( injArgs , & inj ) ; err != nil {
return nil , err
}
return & TestScoreWithNormalizePlugin { scoreWithNormalizePlugin2 , inj } , nil
2019-07-29 11:45:01 -04:00
}
2019-09-09 01:13:15 -04:00
2025-07-24 07:48:07 -04:00
func newScorePlugin1 ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-09 01:13:15 -04:00
var inj injectedResult
if err := DecodeInto ( injArgs , & inj ) ; err != nil {
return nil , err
}
return & TestScorePlugin { scorePlugin1 , inj } , nil
2019-07-29 11:45:01 -04:00
}
2019-09-09 01:13:15 -04:00
2025-07-24 07:48:07 -04:00
func newScorePlugin2 ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2023-11-29 01:07:27 -05:00
var inj injectedResult
if err := DecodeInto ( injArgs , & inj ) ; err != nil {
return nil , err
}
return & TestScorePlugin { scorePlugin2 , inj } , nil
}
2025-07-24 07:48:07 -04:00
func newPluginNotImplementingScore ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-09 01:13:15 -04:00
return & PluginNotImplementingScore { } , nil
2019-07-29 11:45:01 -04:00
}
2019-08-19 16:08:14 -04:00
type TestScoreWithNormalizePlugin struct {
name string
inj injectedResult
2019-07-29 11:45:01 -04:00
}
2019-08-19 16:08:14 -04:00
func ( pl * TestScoreWithNormalizePlugin ) Name ( ) string {
return pl . name
2019-07-29 11:45:01 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestScoreWithNormalizePlugin ) NormalizeScore ( ctx context . Context , state fwk . CycleState , pod * v1 . Pod , scores fwk . NodeScoreList ) * fwk . Status {
2019-08-19 16:08:14 -04:00
return injectNormalizeRes ( pl . inj , scores )
2019-07-29 11:45:01 -04:00
}
2025-06-11 05:56:18 -04:00
func ( pl * TestScoreWithNormalizePlugin ) Score ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeInfo fwk . NodeInfo ) ( int64 , * fwk . Status ) {
2019-08-19 16:08:14 -04:00
return setScoreRes ( pl . inj )
2019-07-29 11:45:01 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestScoreWithNormalizePlugin ) ScoreExtensions ( ) fwk . ScoreExtensions {
2019-10-01 11:59:48 -04:00
return pl
}
2019-08-19 16:08:14 -04:00
// TestScorePlugin only implements ScorePlugin interface.
type TestScorePlugin struct {
name string
inj injectedResult
2019-07-29 11:45:01 -04:00
}
2019-08-19 16:08:14 -04:00
func ( pl * TestScorePlugin ) Name ( ) string {
return pl . name
2019-07-29 11:45:01 -04:00
}
2025-06-11 05:56:18 -04:00
func ( pl * TestScorePlugin ) PreScore ( ctx context . Context , state fwk . CycleState , pod * v1 . Pod , nodes [ ] fwk . NodeInfo ) * fwk . Status {
2025-06-03 18:59:50 -04:00
return fwk . NewStatus ( fwk . Code ( pl . inj . PreScoreStatus ) , injectReason )
2021-10-11 13:47:23 -04:00
}
2025-06-11 05:56:18 -04:00
func ( pl * TestScorePlugin ) Score ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeInfo fwk . NodeInfo ) ( int64 , * fwk . Status ) {
2019-08-19 16:08:14 -04:00
return setScoreRes ( pl . inj )
2019-07-29 11:45:01 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestScorePlugin ) ScoreExtensions ( ) fwk . ScoreExtensions {
2019-09-23 23:44:50 -04:00
return nil
}
2019-07-29 11:45:01 -04:00
// PluginNotImplementingScore doesn't implement the ScorePlugin interface.
type PluginNotImplementingScore struct { }
func ( pl * PluginNotImplementingScore ) Name ( ) string {
return pluginNotImplementingScore
}
2025-07-24 07:48:07 -04:00
func newTestPlugin ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2021-03-29 04:34:10 -04:00
return & TestPlugin { name : testPlugin } , nil
}
2019-10-04 10:25:17 -04:00
// TestPlugin implements all Plugin interfaces.
type TestPlugin struct {
name string
inj injectedResult
}
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) AddPod ( ctx context . Context , state fwk . CycleState , podToSchedule * v1 . Pod , podInfoToAdd fwk . PodInfo , nodeInfo fwk . NodeInfo ) * fwk . Status {
2025-06-03 18:59:50 -04:00
return fwk . NewStatus ( fwk . Code ( pl . inj . PreFilterAddPodStatus ) , injectReason )
2019-10-29 10:54:02 -04:00
}
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) RemovePod ( ctx context . Context , state fwk . CycleState , podToSchedule * v1 . Pod , podInfoToRemove fwk . PodInfo , nodeInfo fwk . NodeInfo ) * fwk . Status {
2025-06-03 18:59:50 -04:00
return fwk . NewStatus ( fwk . Code ( pl . inj . PreFilterRemovePodStatus ) , injectReason )
2019-10-29 10:54:02 -04:00
}
2019-10-04 10:25:17 -04:00
func ( pl * TestPlugin ) Name ( ) string {
return pl . name
}
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) Less ( fwk . QueuedPodInfo , fwk . QueuedPodInfo ) bool {
2020-04-30 18:11:37 -04:00
return false
}
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) Score ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeInfo fwk . NodeInfo ) ( int64 , * fwk . Status ) {
2025-06-03 18:59:50 -04:00
return 0 , fwk . NewStatus ( fwk . Code ( pl . inj . ScoreStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPlugin ) ScoreExtensions ( ) fwk . ScoreExtensions {
2019-10-04 10:25:17 -04:00
return nil
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPlugin ) PreFilter ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodes [ ] fwk . NodeInfo ) ( * fwk . PreFilterResult , * fwk . Status ) {
2025-06-03 18:59:50 -04:00
return pl . inj . PreFilterResult , fwk . NewStatus ( fwk . Code ( pl . inj . PreFilterStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-07-24 07:48:07 -04:00
func ( pl * TestPlugin ) PreFilterExtensions ( ) fwk . PreFilterExtensions {
2020-04-30 18:11:37 -04:00
return pl
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) Filter ( ctx context . Context , state fwk . CycleState , pod * v1 . Pod , nodeInfo fwk . NodeInfo ) * fwk . Status {
2025-06-03 18:59:50 -04:00
return fwk . NewStatus ( fwk . Code ( pl . inj . FilterStatus ) , injectFilterReason )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-07-24 07:48:07 -04:00
func ( pl * TestPlugin ) PostFilter ( _ context . Context , _ fwk . CycleState , _ * v1 . Pod , _ fwk . NodeToStatusReader ) ( * fwk . PostFilterResult , * fwk . Status ) {
2025-06-03 18:59:50 -04:00
return nil , fwk . NewStatus ( fwk . Code ( pl . inj . PostFilterStatus ) , injectReason )
2020-06-05 16:02:45 -04:00
}
2025-06-11 05:56:18 -04:00
func ( pl * TestPlugin ) PreScore ( ctx context . Context , state fwk . CycleState , pod * v1 . Pod , nodes [ ] fwk . NodeInfo ) * fwk . Status {
2025-06-03 18:59:50 -04:00
return fwk . NewStatus ( fwk . Code ( pl . inj . PreScoreStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-06-03 18:59:50 -04:00
func ( pl * TestPlugin ) Reserve ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) * fwk . Status {
return fwk . NewStatus ( fwk . Code ( pl . inj . ReserveStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-05-21 11:21:27 -04:00
func ( pl * TestPlugin ) Unreserve ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) {
2020-06-15 17:52:54 -04:00
}
2025-12-04 14:01:19 -05:00
func ( pl * TestPlugin ) PreBindPreFlight ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) ( * fwk . PreBindPreFlightResult , * fwk . Status ) {
return & fwk . PreBindPreFlightResult { AllowParallel : false } , fwk . NewStatus ( fwk . Code ( pl . inj . PreBindPreFlightStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-07-17 03:30:10 -04:00
func ( pl * TestPlugin ) PreBind ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) * fwk . Status {
return fwk . NewStatus ( fwk . Code ( pl . inj . PreBindStatus ) , injectReason )
2025-07-05 20:14:21 -04:00
}
2025-05-21 11:21:27 -04:00
func ( pl * TestPlugin ) PostBind ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) {
2020-06-19 05:05:45 -04:00
}
2019-08-28 07:12:02 -04:00
2025-06-03 18:59:50 -04:00
func ( pl * TestPlugin ) Permit ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) ( * fwk . Status , time . Duration ) {
return fwk . NewStatus ( fwk . Code ( pl . inj . PermitStatus ) , injectReason ) , time . Duration ( 0 )
2019-10-04 10:25:17 -04:00
}
2019-08-28 07:12:02 -04:00
2025-06-03 18:59:50 -04:00
func ( pl * TestPlugin ) Bind ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) * fwk . Status {
return fwk . NewStatus ( fwk . Code ( pl . inj . BindStatus ) , injectReason )
2019-10-04 10:25:17 -04:00
}
2025-07-24 07:48:07 -04:00
func newTestCloseErrorPlugin ( _ context . Context , injArgs runtime . Object , f fwk . Handle ) ( fwk . Plugin , error ) {
2023-12-27 10:18:29 -05:00
return & TestCloseErrorPlugin { name : testCloseErrorPlugin } , nil
}
// TestCloseErrorPlugin implements for Close test.
type TestCloseErrorPlugin struct {
name string
}
func ( pl * TestCloseErrorPlugin ) Name ( ) string {
return pl . name
}
var errClose = errors . New ( "close err" )
func ( pl * TestCloseErrorPlugin ) Close ( ) error {
return errClose
}
2019-09-24 12:39:27 -04:00
// TestPreFilterPlugin only implements PreFilterPlugin interface.
type TestPreFilterPlugin struct {
PreFilterCalled int
}
func ( pl * TestPreFilterPlugin ) Name ( ) string {
return preFilterPluginName
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPreFilterPlugin ) PreFilter ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodes [ ] fwk . NodeInfo ) ( * fwk . PreFilterResult , * fwk . Status ) {
2019-09-24 12:39:27 -04:00
pl . PreFilterCalled ++
2022-03-10 17:48:33 -05:00
return nil , nil
2019-09-24 12:39:27 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPreFilterPlugin ) PreFilterExtensions ( ) fwk . PreFilterExtensions {
2019-09-24 12:39:27 -04:00
return nil
}
2019-10-01 11:59:48 -04:00
// TestPreFilterWithExtensionsPlugin implements Add/Remove interfaces.
type TestPreFilterWithExtensionsPlugin struct {
2019-09-24 12:39:27 -04:00
PreFilterCalled int
AddCalled int
RemoveCalled int
}
2019-10-01 11:59:48 -04:00
func ( pl * TestPreFilterWithExtensionsPlugin ) Name ( ) string {
return preFilterWithExtensionsPluginName
2019-09-24 12:39:27 -04:00
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPreFilterWithExtensionsPlugin ) PreFilter ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodes [ ] fwk . NodeInfo ) ( * fwk . PreFilterResult , * fwk . Status ) {
2019-09-24 12:39:27 -04:00
pl . PreFilterCalled ++
2022-03-10 17:48:33 -05:00
return nil , nil
2019-09-24 12:39:27 -04:00
}
2025-05-21 11:21:27 -04:00
func ( pl * TestPreFilterWithExtensionsPlugin ) AddPod ( ctx context . Context , state fwk . CycleState , podToSchedule * v1 . Pod ,
2025-06-11 05:56:18 -04:00
podInfoToAdd fwk . PodInfo , nodeInfo fwk . NodeInfo ) * fwk . Status {
2019-09-24 12:39:27 -04:00
pl . AddCalled ++
return nil
}
2025-05-21 11:21:27 -04:00
func ( pl * TestPreFilterWithExtensionsPlugin ) RemovePod ( ctx context . Context , state fwk . CycleState , podToSchedule * v1 . Pod ,
2025-06-11 05:56:18 -04:00
podInfoToRemove fwk . PodInfo , nodeInfo fwk . NodeInfo ) * fwk . Status {
2019-09-24 12:39:27 -04:00
pl . RemoveCalled ++
return nil
}
2025-07-24 07:48:07 -04:00
func ( pl * TestPreFilterWithExtensionsPlugin ) PreFilterExtensions ( ) fwk . PreFilterExtensions {
2019-09-24 12:39:27 -04:00
return pl
}
2019-09-26 21:15:32 -04:00
type TestDuplicatePlugin struct {
}
func ( dp * TestDuplicatePlugin ) Name ( ) string {
return duplicatePluginName
}
2025-07-24 07:48:07 -04:00
func ( dp * TestDuplicatePlugin ) PreFilter ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodes [ ] fwk . NodeInfo ) ( * fwk . PreFilterResult , * fwk . Status ) {
2022-03-10 17:48:33 -05:00
return nil , nil
2019-09-26 21:15:32 -04:00
}
2025-07-24 07:48:07 -04:00
func ( dp * TestDuplicatePlugin ) PreFilterExtensions ( ) fwk . PreFilterExtensions {
2019-09-26 21:15:32 -04:00
return nil
}
2025-07-24 07:48:07 -04:00
var _ fwk . PreFilterPlugin = & TestDuplicatePlugin { }
2019-09-26 21:15:32 -04:00
2025-07-24 07:48:07 -04:00
func newDuplicatePlugin ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-26 21:15:32 -04:00
return & TestDuplicatePlugin { } , nil
}
2019-11-05 09:04:44 -05:00
// TestPermitPlugin only implements PermitPlugin interface.
type TestPermitPlugin struct {
PreFilterCalled int
}
func ( pp * TestPermitPlugin ) Name ( ) string {
return permitPlugin
}
2025-06-03 18:59:50 -04:00
func ( pp * TestPermitPlugin ) Permit ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) ( * fwk . Status , time . Duration ) {
return fwk . NewStatus ( fwk . Wait ) , 10 * time . Second
2019-11-05 09:04:44 -05:00
}
2025-07-24 07:48:07 -04:00
var _ fwk . PreEnqueuePlugin = & TestPreEnqueuePlugin { }
2022-11-07 17:02:22 -05:00
type TestPreEnqueuePlugin struct { }
func ( pl * TestPreEnqueuePlugin ) Name ( ) string {
return preEnqueuePlugin
}
2025-06-03 18:59:50 -04:00
func ( pl * TestPreEnqueuePlugin ) PreEnqueue ( ctx context . Context , p * v1 . Pod ) * fwk . Status {
2022-11-07 17:02:22 -05:00
return nil
}
2025-07-24 07:48:07 -04:00
var _ fwk . QueueSortPlugin = & TestQueueSortPlugin { }
2020-01-15 15:26:22 -05:00
2025-07-24 07:48:07 -04:00
func newQueueSortPlugin ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-01-15 15:26:22 -05:00
return & TestQueueSortPlugin { } , nil
}
// TestQueueSortPlugin is a no-op implementation for QueueSort extension point.
type TestQueueSortPlugin struct { }
func ( pl * TestQueueSortPlugin ) Name ( ) string {
return queueSortPlugin
}
2025-06-11 05:56:18 -04:00
func ( pl * TestQueueSortPlugin ) Less ( _ , _ fwk . QueuedPodInfo ) bool {
2020-01-15 15:26:22 -05:00
return false
}
2025-07-24 07:48:07 -04:00
var _ fwk . BindPlugin = & TestBindPlugin { }
2020-01-15 11:26:35 -05:00
2025-07-24 07:48:07 -04:00
func newBindPlugin ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-01-15 11:26:35 -05:00
return & TestBindPlugin { } , nil
}
// TestBindPlugin is a no-op implementation for Bind extension point.
type TestBindPlugin struct { }
func ( t TestBindPlugin ) Name ( ) string {
return bindPlugin
}
2025-06-03 18:59:50 -04:00
func ( t TestBindPlugin ) Bind ( ctx context . Context , state fwk . CycleState , p * v1 . Pod , nodeName string ) * fwk . Status {
2020-01-15 11:26:35 -05:00
return nil
}
2023-11-29 01:07:27 -05:00
// nolint:errcheck // Ignore the error returned by Register as before
2020-01-15 15:26:22 -05:00
var registry = func ( ) Registry {
2019-09-09 01:13:15 -04:00
r := make ( Registry )
r . Register ( scoreWithNormalizePlugin1 , newScoreWithNormalizePlugin1 )
r . Register ( scoreWithNormalizePlugin2 , newScoreWithNormalizePlugin2 )
r . Register ( scorePlugin1 , newScorePlugin1 )
2023-11-29 01:07:27 -05:00
r . Register ( scorePlugin2 , newScorePlugin2 )
2019-09-09 01:13:15 -04:00
r . Register ( pluginNotImplementingScore , newPluginNotImplementingScore )
2019-09-26 21:15:32 -04:00
r . Register ( duplicatePluginName , newDuplicatePlugin )
2021-03-29 04:34:10 -04:00
r . Register ( testPlugin , newTestPlugin )
2021-12-14 23:00:25 -05:00
r . Register ( queueSortPlugin , newQueueSortPlugin )
r . Register ( bindPlugin , newBindPlugin )
2023-12-27 10:18:29 -05:00
r . Register ( testCloseErrorPlugin , newTestCloseErrorPlugin )
2019-09-09 01:13:15 -04:00
return r
} ( )
2019-07-29 11:45:01 -04:00
2019-08-19 16:08:14 -04:00
var defaultWeights = map [ string ] int32 {
scoreWithNormalizePlugin1 : 1 ,
scoreWithNormalizePlugin2 : 2 ,
scorePlugin1 : 1 ,
2019-07-29 11:45:01 -04:00
}
2025-05-21 11:21:27 -04:00
var state = framework . NewCycleState ( )
2019-07-29 11:45:01 -04:00
// Pod is only used for logging errors.
var pod = & v1 . Pod { }
2020-12-19 11:18:40 -05:00
var node = & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : nodeName ,
} ,
}
var lowPriority , highPriority = int32 ( 0 ) , int32 ( 1000 )
var lowPriorityPod = & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { UID : "low" } ,
Spec : v1 . PodSpec { Priority : & lowPriority } ,
}
var highPriorityPod = & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { UID : "high" } ,
Spec : v1 . PodSpec { Priority : & highPriority } ,
}
2019-08-19 16:08:14 -04:00
var nodes = [ ] * v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "node1" } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "node2" } } ,
}
2019-07-29 11:45:01 -04:00
2021-01-26 00:48:58 -05:00
var (
2022-09-09 11:31:23 -04:00
errInjectedStatus = errors . New ( injectReason )
errInjectedFilterStatus = errors . New ( injectFilterReason )
2021-01-26 00:48:58 -05:00
)
2020-09-24 09:10:42 -04:00
2023-05-15 06:36:17 -04:00
func newFrameworkWithQueueSortAndBind ( ctx context . Context , r Registry , profile config . KubeSchedulerProfile , opts ... Option ) ( framework . Framework , error ) {
2020-01-15 15:26:22 -05:00
if _ , ok := r [ queueSortPlugin ] ; ! ok {
r [ queueSortPlugin ] = newQueueSortPlugin
}
2020-01-15 11:26:35 -05:00
if _ , ok := r [ bindPlugin ] ; ! ok {
r [ bindPlugin ] = newBindPlugin
}
2021-06-10 08:45:49 -04:00
if len ( profile . Plugins . QueueSort . Enabled ) == 0 {
profile . Plugins . QueueSort . Enabled = append ( profile . Plugins . QueueSort . Enabled , config . Plugin { Name : queueSortPlugin } )
2020-01-15 11:26:35 -05:00
}
2021-06-10 08:45:49 -04:00
if len ( profile . Plugins . Bind . Enabled ) == 0 {
profile . Plugins . Bind . Enabled = append ( profile . Plugins . Bind . Enabled , config . Plugin { Name : bindPlugin } )
2020-01-15 11:26:35 -05:00
}
2023-05-15 06:36:17 -04:00
return NewFramework ( ctx , r , & profile , opts ... )
2020-01-15 15:26:22 -05:00
}
2019-07-29 11:45:01 -04:00
func TestInitFrameworkWithScorePlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins * config . Plugins
// If initErr is true, we expect framework initialization to fail.
initErr bool
} {
{
2019-08-19 16:08:14 -04:00
name : "enabled Score plugin doesn't exist in registry" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( "notExist" ) ,
2019-07-29 11:45:01 -04:00
initErr : true ,
} ,
{
2019-08-19 16:08:14 -04:00
name : "enabled Score plugin doesn't extend the ScorePlugin interface" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( pluginNotImplementingScore ) ,
2019-07-29 11:45:01 -04:00
initErr : true ,
} ,
{
name : "Score plugins are nil" ,
2021-02-10 10:45:59 -05:00
plugins : & config . Plugins { } ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "enabled Score plugin list is empty" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( ) ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "enabled plugin only implements ScorePlugin interface" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "enabled plugin implements ScoreWithNormalizePlugin interface" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scoreWithNormalizePlugin1 ) ,
2019-07-29 11:45:01 -04:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : tt . plugins }
2023-05-15 06:36:17 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
_ , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2019-07-29 11:45:01 -04:00
if tt . initErr && err == nil {
t . Fatal ( "Framework initialization should fail" )
}
if ! tt . initErr && err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
} )
}
}
2020-03-05 13:52:40 -05:00
func TestNewFrameworkErrors ( t * testing . T ) {
tests := [ ] struct {
name string
plugins * config . Plugins
pluginCfg [ ] config . PluginConfig
wantErr string
} {
{
name : "duplicate plugin name" ,
plugins : & config . Plugins {
2021-02-10 10:45:59 -05:00
PreFilter : config . PluginSet {
2020-03-05 13:52:40 -05:00
Enabled : [ ] config . Plugin {
{ Name : duplicatePluginName , Weight : 1 } ,
{ Name : duplicatePluginName , Weight : 1 } ,
} ,
} ,
} ,
pluginCfg : [ ] config . PluginConfig {
{ Name : duplicatePluginName } ,
} ,
wantErr : "already registered" ,
} ,
{
name : "duplicate plugin config" ,
plugins : & config . Plugins {
2021-02-10 10:45:59 -05:00
PreFilter : config . PluginSet {
2020-03-05 13:52:40 -05:00
Enabled : [ ] config . Plugin {
{ Name : duplicatePluginName , Weight : 1 } ,
} ,
} ,
} ,
pluginCfg : [ ] config . PluginConfig {
{ Name : duplicatePluginName } ,
{ Name : duplicatePluginName } ,
} ,
wantErr : "repeated config for plugin" ,
2019-09-26 21:15:32 -04:00
} ,
}
2020-03-05 13:52:40 -05:00
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
2023-05-15 06:36:17 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
2021-03-03 16:44:25 -05:00
profile := & config . KubeSchedulerProfile {
Plugins : tc . plugins ,
PluginConfig : tc . pluginCfg ,
}
2023-05-15 06:36:17 -04:00
_ , err := NewFramework ( ctx , registry , profile )
2020-03-05 13:52:40 -05:00
if err == nil || ! strings . Contains ( err . Error ( ) , tc . wantErr ) {
t . Errorf ( "Unexpected error, got %v, expect: %s" , err , tc . wantErr )
}
} )
2019-09-26 21:15:32 -04:00
}
}
2021-10-11 13:47:23 -04:00
func TestNewFrameworkMultiPointExpansion ( t * testing . T ) {
tests := [ ] struct {
name string
plugins * config . Plugins
wantPlugins * config . Plugins
wantErr string
} {
{
name : "plugin expansion" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin , Weight : 5 } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin , Weight : 5 } } } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "disable MultiPoint plugin at some extension points" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
} ,
} ,
PreScore : config . PluginSet {
Disabled : [ ] config . Plugin {
{ Name : testPlugin } ,
} ,
} ,
Score : config . PluginSet {
Disabled : [ ] config . Plugin {
{ Name : testPlugin } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "Multiple MultiPoint plugins" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin , Weight : 1 } ,
{ Name : scorePlugin1 , Weight : 1 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "disable MultiPoint extension" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
PreScore : config . PluginSet {
Disabled : [ ] config . Plugin {
{ Name : "*" } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin , Weight : 1 } ,
{ Name : scorePlugin1 , Weight : 1 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "Reorder MultiPoint plugins (specified extension takes precedence)" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scoreWithNormalizePlugin1 } ,
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
Score : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 } ,
{ Name : testPlugin } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 1 } ,
{ Name : testPlugin , Weight : 1 } ,
{ Name : scoreWithNormalizePlugin1 , Weight : 1 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
2022-03-21 12:30:41 -04:00
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "Reorder MultiPoint plugins (specified extension only takes precedence when it exists in MultiPoint)" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
Score : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scoreWithNormalizePlugin1 } ,
{ Name : scorePlugin1 } ,
{ Name : testPlugin } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 1 } ,
{ Name : testPlugin , Weight : 1 } ,
2021-10-11 13:47:23 -04:00
{ Name : scoreWithNormalizePlugin1 , Weight : 1 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "Override MultiPoint plugins weights" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
Score : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 5 } ,
{ Name : testPlugin , Weight : 3 } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 5 } ,
{ Name : testPlugin , Weight : 3 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
{
name : "disable and enable MultiPoint plugins with '*'" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : queueSortPlugin } ,
{ Name : bindPlugin } ,
{ Name : scorePlugin1 } ,
} ,
Disabled : [ ] config . Plugin {
{ Name : "*" } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : queueSortPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 1 } ,
} } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : bindPlugin } } } ,
} ,
} ,
{
name : "disable and enable MultiPoint plugin by name" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : bindPlugin } ,
{ Name : queueSortPlugin } ,
{ Name : scorePlugin1 } ,
} ,
Disabled : [ ] config . Plugin {
{ Name : scorePlugin1 } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : queueSortPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 1 } ,
} } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : bindPlugin } } } ,
} ,
} ,
{
name : "Expect 'already registered' error" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : testPlugin } ,
} ,
} ,
} ,
wantErr : "already registered" ,
} ,
2023-11-29 01:07:27 -05:00
{
name : "Override MultiPoint plugins weights and avoid a plugin being loaded multiple times" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} ,
} ,
Score : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 5 } ,
{ Name : scorePlugin2 , Weight : 5 } ,
{ Name : testPlugin , Weight : 3 } ,
} ,
} ,
} ,
wantPlugins : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Filter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreScore : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : testPlugin } ,
{ Name : scorePlugin1 } ,
} } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 5 } ,
{ Name : testPlugin , Weight : 3 } ,
{ Name : scorePlugin2 , Weight : 5 } ,
} } ,
Reserve : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PreBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
PostBind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin } } } ,
} ,
} ,
2021-10-11 13:47:23 -04:00
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
2023-05-15 06:36:17 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
fw , err := NewFramework ( ctx , registry , & config . KubeSchedulerProfile { Plugins : tc . plugins } )
2024-07-03 02:18:25 -04:00
defer func ( ) {
if fw != nil {
_ = fw . Close ( )
}
} ( )
2021-12-14 23:00:25 -05:00
if err != nil {
if tc . wantErr == "" || ! strings . Contains ( err . Error ( ) , tc . wantErr ) {
t . Fatalf ( "Unexpected error, got %v, expect: %s" , err , tc . wantErr )
}
} else {
if tc . wantErr != "" {
t . Fatalf ( "Unexpected error, got %v, expect: %s" , err , tc . wantErr )
}
2021-10-11 13:47:23 -04:00
}
if tc . wantErr == "" {
if diff := cmp . Diff ( tc . wantPlugins , fw . ListPlugins ( ) ) ; diff != "" {
2025-01-27 05:01:57 -05:00
t . Fatalf ( "Unexpected eventToPlugin map (-want,+got):\n%s" , diff )
2021-10-11 13:47:23 -04:00
}
}
} )
}
}
2022-11-07 17:02:22 -05:00
func TestPreEnqueuePlugins ( t * testing . T ) {
tests := [ ] struct {
name string
2025-07-24 07:48:07 -04:00
plugins [ ] fwk . Plugin
want [ ] fwk . PreEnqueuePlugin
2022-11-07 17:02:22 -05:00
} {
{
name : "no PreEnqueuePlugin registered" ,
} ,
{
name : "one PreEnqueuePlugin registered" ,
2025-07-24 07:48:07 -04:00
plugins : [ ] fwk . Plugin {
2022-11-07 17:02:22 -05:00
& TestPreEnqueuePlugin { } ,
} ,
2025-07-24 07:48:07 -04:00
want : [ ] fwk . PreEnqueuePlugin {
2022-11-07 17:02:22 -05:00
& TestPreEnqueuePlugin { } ,
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2022-11-07 17:02:22 -05:00
registry := Registry { }
cfgPls := & config . Plugins { }
for _ , pl := range tt . plugins {
// register all plugins
tmpPl := pl
if err := registry . Register ( pl . Name ( ) ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2022-11-07 17:02:22 -05:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "fail to register preEnqueue plugin (%s)" , pl . Name ( ) )
}
// append plugins to filter pluginset
cfgPls . PreEnqueue . Enabled = append (
cfgPls . PreEnqueue . Enabled ,
config . Plugin { Name : pl . Name ( ) } ,
)
}
profile := config . KubeSchedulerProfile { Plugins : cfgPls }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-11-07 17:02:22 -05:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2022-11-07 17:02:22 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2022-11-07 17:02:22 -05:00
got := f . PreEnqueuePlugins ( )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . want , got ) ; diff != "" {
t . Errorf ( "Unexpected PreEnqueuePlugins(): (-want,+got):\n%s" , diff )
2022-11-07 17:02:22 -05:00
}
} )
}
}
2023-02-13 17:53:29 -05:00
func TestRunPreScorePlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
wantSkippedPlugins sets . Set [ string ]
2025-06-03 18:59:50 -04:00
wantStatusCode fwk . Code
2023-02-13 17:53:29 -05:00
} {
{
name : "all PreScorePlugins returned success" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "success2" ,
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "one PreScore plugin returned success, but another PreScore plugin returned non-success" ,
plugins : [ ] * TestPlugin {
{
name : "success" ,
} ,
{
name : "error" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Error ) } ,
2023-02-13 17:53:29 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "one PreScore plugin returned skip, but another PreScore plugin returned non-success" ,
plugins : [ ] * TestPlugin {
{
name : "skip" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "error" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Error ) } ,
2023-02-13 17:53:29 -05:00
} ,
} ,
2023-08-23 07:03:45 -04:00
wantSkippedPlugins : sets . New ( "skip" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "all PreScore plugins returned skip" ,
plugins : [ ] * TestPlugin {
{
name : "skip1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "skip2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "skip3" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
} ,
wantSkippedPlugins : sets . New ( "skip1" , "skip2" , "skip3" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "some PreScore plugins returned skip" ,
plugins : [ ] * TestPlugin {
{
name : "skip1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "success1" ,
} ,
{
name : "skip2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreScoreStatus : int ( fwk . Skip ) } ,
2023-02-13 17:53:29 -05:00
} ,
{
name : "success2" ,
} ,
} ,
wantSkippedPlugins : sets . New ( "skip1" , "skip2" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-02-13 17:53:29 -05:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
r := make ( Registry )
enabled := make ( [ ] config . Plugin , len ( tt . plugins ) )
for i , p := range tt . plugins {
p := p
enabled [ i ] . Name = p . name
2025-07-24 07:48:07 -04:00
if err := r . Register ( p . name , func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2023-02-13 17:53:29 -05:00
return p , nil
2023-09-05 23:55:33 -04:00
} ) ; err != nil {
t . Fatalf ( "fail to register PreScorePlugins plugin (%s)" , p . Name ( ) )
}
2023-02-13 17:53:29 -05:00
}
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2023-02-13 17:53:29 -05:00
defer cancel ( )
f , err := newFrameworkWithQueueSortAndBind (
2023-05-15 06:36:17 -04:00
ctx ,
2023-02-13 17:53:29 -05:00
r ,
config . KubeSchedulerProfile { Plugins : & config . Plugins { PreScore : config . PluginSet { Enabled : enabled } } } ,
)
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-02-13 17:53:29 -05:00
state := framework . NewCycleState ( )
status := f . RunPreScorePlugins ( ctx , state , nil , nil )
if status . Code ( ) != tt . wantStatusCode {
t . Errorf ( "wrong status code. got: %v, want: %v" , status , tt . wantStatusCode )
}
2025-05-21 11:21:27 -04:00
skipped := state . GetSkipScorePlugins ( )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantSkippedPlugins , skipped ) ; diff != "" {
t . Errorf ( "wrong skip score plugins (-want, +got):\n%s" , diff )
2023-02-13 17:53:29 -05:00
}
} )
}
}
2019-08-19 16:08:14 -04:00
func TestRunScorePlugins ( t * testing . T ) {
2019-07-29 11:45:01 -04:00
tests := [ ] struct {
2023-02-13 17:53:29 -05:00
name string
registry Registry
plugins * config . Plugins
pluginConfigs [ ] config . PluginConfig
2025-07-24 07:48:07 -04:00
want [ ] fwk . NodePluginScores
2023-02-13 17:53:29 -05:00
skippedPlugins sets . Set [ string ]
2019-08-19 16:08:14 -04:00
// If err is true, we expect RunScorePlugin to fail.
2019-07-29 11:45:01 -04:00
err bool
} {
{
2019-08-19 16:08:14 -04:00
name : "no Score plugins" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( ) ,
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2022-03-03 12:00:00 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2022-03-03 12:00:00 -05:00
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2022-03-03 12:00:00 -05:00
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "single Score plugin" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-09-09 01:13:15 -04:00
Raw : [ ] byte ( ` { "scoreRes": 1 } ` ) ,
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-08-19 16:08:14 -04:00
// scorePlugin1 Score returns 1, weight=1, so want=1.
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2022-03-03 12:00:00 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
} ,
TotalScore : 1 ,
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
} ,
TotalScore : 1 ,
} ,
2019-07-29 11:45:01 -04:00
} ,
} ,
{
2019-08-19 16:08:14 -04:00
name : "single ScoreWithNormalize plugin" ,
2021-12-16 13:54:58 -05:00
// registry: registry,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scoreWithNormalizePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-09-09 01:13:15 -04:00
Raw : [ ] byte ( ` { "scoreRes": 10, "normalizeRes": 5 } ` ) ,
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-08-19 16:08:14 -04:00
// scoreWithNormalizePlugin1 Score returns 10, but NormalizeScore overrides to 5, weight=1, so want=5
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2022-03-03 12:00:00 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scoreWithNormalizePlugin1 ,
Score : 5 ,
} ,
} ,
TotalScore : 5 ,
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scoreWithNormalizePlugin1 ,
Score : 5 ,
} ,
} ,
TotalScore : 5 ,
} ,
2019-07-29 11:45:01 -04:00
} ,
} ,
{
2022-03-03 12:00:00 -05:00
name : "3 Score plugins, 2 NormalizeScore plugins" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 , scoreWithNormalizePlugin1 , scoreWithNormalizePlugin2 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-09-09 01:13:15 -04:00
Raw : [ ] byte ( ` { "scoreRes": 1 } ` ) ,
} ,
} ,
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-09-09 01:13:15 -04:00
Raw : [ ] byte ( ` { "scoreRes": 3, "normalizeRes": 4} ` ) ,
} ,
} ,
{
Name : scoreWithNormalizePlugin2 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-09-09 01:13:15 -04:00
Raw : [ ] byte ( ` { "scoreRes": 4, "normalizeRes": 5} ` ) ,
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-08-19 16:08:14 -04:00
// scorePlugin1 Score returns 1, weight =1, so want=1.
// scoreWithNormalizePlugin1 Score returns 3, but NormalizeScore overrides to 4, weight=1, so want=4.
// scoreWithNormalizePlugin2 Score returns 4, but NormalizeScore overrides to 5, weight=2, so want=10.
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2022-03-03 12:00:00 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
{
Name : scoreWithNormalizePlugin1 ,
Score : 4 ,
} ,
{
Name : scoreWithNormalizePlugin2 ,
Score : 10 ,
} ,
} ,
TotalScore : 15 ,
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
{
Name : scoreWithNormalizePlugin1 ,
Score : 4 ,
} ,
{
Name : scoreWithNormalizePlugin2 ,
Score : 10 ,
} ,
} ,
TotalScore : 15 ,
} ,
2019-07-29 11:45:01 -04:00
} ,
} ,
{
2019-08-19 16:08:14 -04:00
name : "score fails" ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-10-04 10:25:17 -04:00
Raw : [ ] byte ( ` { "scoreStatus": 1 } ` ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 , scoreWithNormalizePlugin1 ) ,
2019-08-19 16:08:14 -04:00
err : true ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "normalize fails" ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2019-10-04 10:25:17 -04:00
Raw : [ ] byte ( ` { "normalizeStatus": 1 } ` ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 , scoreWithNormalizePlugin1 ) ,
2019-08-19 16:08:14 -04:00
err : true ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "Score plugin return score greater than MaxNodeScore" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2025-07-24 07:48:07 -04:00
Raw : [ ] byte ( fmt . Sprintf ( ` { "scoreRes": %d } ` , fwk . MaxNodeScore + 1 ) ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
2019-08-19 16:08:14 -04:00
err : true ,
2019-07-29 11:45:01 -04:00
} ,
{
2019-08-19 16:08:14 -04:00
name : "Score plugin return score less than MinNodeScore" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2025-07-24 07:48:07 -04:00
Raw : [ ] byte ( fmt . Sprintf ( ` { "scoreRes": %d } ` , fwk . MinNodeScore - 1 ) ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-07-29 11:45:01 -04:00
} ,
err : true ,
} ,
2019-08-09 05:03:55 -04:00
{
2019-08-19 16:08:14 -04:00
name : "ScoreWithNormalize plugin return score greater than MaxNodeScore" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scoreWithNormalizePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2025-07-24 07:48:07 -04:00
Raw : [ ] byte ( fmt . Sprintf ( ` { "normalizeRes": %d } ` , fwk . MaxNodeScore + 1 ) ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-08-09 05:03:55 -04:00
} ,
err : true ,
} ,
{
2019-08-19 16:08:14 -04:00
name : "ScoreWithNormalize plugin return score less than MinNodeScore" ,
2019-10-04 10:25:17 -04:00
plugins : buildScoreConfigDefaultWeights ( scoreWithNormalizePlugin1 ) ,
2019-09-09 01:13:15 -04:00
pluginConfigs : [ ] config . PluginConfig {
{
Name : scoreWithNormalizePlugin1 ,
2020-04-08 13:47:52 -04:00
Args : & runtime . Unknown {
2025-07-24 07:48:07 -04:00
Raw : [ ] byte ( fmt . Sprintf ( ` { "normalizeRes": %d } ` , fwk . MinNodeScore - 1 ) ) ,
2019-09-09 01:13:15 -04:00
} ,
} ,
2019-08-09 05:03:55 -04:00
} ,
err : true ,
} ,
2021-12-14 23:00:25 -05:00
{
name : "single Score plugin with MultiPointExpansion" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 } ,
} ,
} ,
Score : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : scorePlugin1 , Weight : 3 } ,
} ,
} ,
} ,
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
Args : & runtime . Unknown {
Raw : [ ] byte ( ` { "scoreRes": 1 } ` ) ,
} ,
} ,
} ,
// scorePlugin1 Score returns 1, weight=3, so want=3.
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2022-03-03 12:00:00 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 3 ,
} ,
} ,
TotalScore : 3 ,
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2022-03-03 12:00:00 -05:00
{
Name : scorePlugin1 ,
Score : 3 ,
} ,
} ,
TotalScore : 3 ,
} ,
2021-12-14 23:00:25 -05:00
} ,
} ,
2023-02-13 17:53:29 -05:00
{
name : "one success plugin, one skip plugin" ,
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 , scoreWithNormalizePlugin1 ) ,
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
Args : & runtime . Unknown {
Raw : [ ] byte ( ` { "scoreRes": 1 } ` ) ,
} ,
} ,
{
Name : scoreWithNormalizePlugin1 ,
Args : & runtime . Unknown {
Raw : [ ] byte ( ` { "scoreStatus": 1 } ` ) , // To make sure this plugin isn't called, set error as an injected result.
} ,
} ,
} ,
skippedPlugins : sets . New ( scoreWithNormalizePlugin1 ) ,
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2023-02-13 17:53:29 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2023-02-13 17:53:29 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
} ,
TotalScore : 1 ,
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore {
2023-02-13 17:53:29 -05:00
{
Name : scorePlugin1 ,
Score : 1 ,
} ,
} ,
TotalScore : 1 ,
} ,
} ,
} ,
{
name : "all plugins are skipped in prescore" ,
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
pluginConfigs : [ ] config . PluginConfig {
{
Name : scorePlugin1 ,
Args : & runtime . Unknown {
Raw : [ ] byte ( ` { "scoreStatus": 1 } ` ) , // To make sure this plugin isn't called, set error as an injected result.
} ,
} ,
} ,
skippedPlugins : sets . New ( scorePlugin1 ) ,
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2023-02-13 17:53:29 -05:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2023-02-13 17:53:29 -05:00
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2023-02-13 17:53:29 -05:00
} ,
} ,
} ,
2023-10-31 04:02:16 -04:00
{
name : "skipped prescore plugin number greater than the number of score plugins" ,
plugins : buildScoreConfigDefaultWeights ( scorePlugin1 ) ,
pluginConfigs : nil ,
skippedPlugins : sets . New ( scorePlugin1 , "score-plugin-unknown" ) ,
2025-07-24 07:48:07 -04:00
want : [ ] fwk . NodePluginScores {
2023-10-31 04:02:16 -04:00
{
Name : "node1" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2023-10-31 04:02:16 -04:00
} ,
{
Name : "node2" ,
2025-07-24 07:48:07 -04:00
Scores : [ ] fwk . PluginScore { } ,
2023-10-31 04:02:16 -04:00
} ,
} ,
} ,
2019-07-29 11:45:01 -04:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2019-09-09 01:13:15 -04:00
// Inject the results via Args in PluginConfig.
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile {
Plugins : tt . plugins ,
PluginConfig : tt . pluginConfigs ,
}
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2019-07-29 11:45:01 -04:00
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2019-07-29 11:45:01 -04:00
2023-02-13 17:53:29 -05:00
state := framework . NewCycleState ( )
2025-05-21 11:21:27 -04:00
state . SetSkipScorePlugins ( tt . skippedPlugins )
2023-11-18 05:21:58 -05:00
res , status := f . RunScorePlugins ( ctx , state , pod , BuildNodeInfos ( nodes ) )
2019-07-29 11:45:01 -04:00
if tt . err {
if status . IsSuccess ( ) {
2019-10-04 10:25:17 -04:00
t . Errorf ( "Expected status to be non-success. got: %v" , status . Code ( ) . String ( ) )
2019-07-29 11:45:01 -04:00
}
2019-08-19 16:08:14 -04:00
return
}
if ! status . IsSuccess ( ) {
t . Errorf ( "Expected status to be success." )
}
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . want , res ) ; diff != "" {
t . Errorf ( "Score map after RunScorePlugin (-want,+got):\n%s" , diff )
2019-07-29 11:45:01 -04:00
}
} )
}
}
2019-08-19 16:08:14 -04:00
2019-09-24 12:39:27 -04:00
func TestPreFilterPlugins ( t * testing . T ) {
preFilter1 := & TestPreFilterPlugin { }
2019-10-01 11:59:48 -04:00
preFilter2 := & TestPreFilterWithExtensionsPlugin { }
2019-09-24 12:39:27 -04:00
r := make ( Registry )
r . Register ( preFilterPluginName ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-24 12:39:27 -04:00
return preFilter1 , nil
} )
2019-10-01 11:59:48 -04:00
r . Register ( preFilterWithExtensionsPluginName ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2019-09-24 12:39:27 -04:00
return preFilter2 , nil
} )
2021-02-10 10:45:59 -05:00
plugins := & config . Plugins { PreFilter : config . PluginSet { Enabled : [ ] config . Plugin { { Name : preFilterWithExtensionsPluginName } , { Name : preFilterPluginName } } } }
2019-09-24 12:39:27 -04:00
t . Run ( "TestPreFilterPlugin" , func ( t * testing . T ) {
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : plugins }
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2025-03-11 06:08:25 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , r , profile , WithSnapshotSharedLister ( cache . NewEmptySnapshot ( ) ) )
2019-09-24 12:39:27 -04:00
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-01-05 12:48:46 -05:00
state := framework . NewCycleState ( )
f . RunPreFilterPlugins ( ctx , state , nil )
f . RunPreFilterExtensionAddPod ( ctx , state , nil , nil , nil )
f . RunPreFilterExtensionRemovePod ( ctx , state , nil , nil , nil )
2019-09-24 12:39:27 -04:00
if preFilter1 . PreFilterCalled != 1 {
t . Errorf ( "preFilter1 called %v, expected: 1" , preFilter1 . PreFilterCalled )
}
if preFilter2 . PreFilterCalled != 1 {
t . Errorf ( "preFilter2 called %v, expected: 1" , preFilter2 . PreFilterCalled )
}
if preFilter2 . AddCalled != 1 {
t . Errorf ( "AddPod called %v, expected: 1" , preFilter2 . AddCalled )
}
if preFilter2 . RemoveCalled != 1 {
t . Errorf ( "AddPod called %v, expected: 1" , preFilter2 . RemoveCalled )
}
} )
}
2023-01-05 12:48:46 -05:00
func TestRunPreFilterPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
2025-07-24 07:48:07 -04:00
wantPreFilterResult * fwk . PreFilterResult
2023-01-05 12:48:46 -05:00
wantSkippedPlugins sets . Set [ string ]
2025-06-03 18:59:50 -04:00
wantStatusCode fwk . Code
2023-01-05 12:48:46 -05:00
} {
{
name : "all PreFilter returned success" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "success2" ,
} ,
} ,
wantPreFilterResult : nil ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one PreFilter plugin returned success, but another PreFilter plugin returned non-success" ,
plugins : [ ] * TestPlugin {
{
name : "success" ,
} ,
{
name : "error" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
wantPreFilterResult : nil ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one PreFilter plugin returned skip, but another PreFilter plugin returned non-success" ,
plugins : [ ] * TestPlugin {
{
name : "skip" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "error" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
2023-08-05 20:39:01 -04:00
wantSkippedPlugins : sets . New ( "skip" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "all PreFilter plugins returned skip" ,
plugins : [ ] * TestPlugin {
{
name : "skip1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "skip2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "skip3" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
wantPreFilterResult : nil ,
wantSkippedPlugins : sets . New ( "skip1" , "skip2" , "skip3" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "some PreFilter plugins returned skip" ,
plugins : [ ] * TestPlugin {
{
name : "skip1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "success1" ,
} ,
{
name : "skip2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "success2" ,
} ,
} ,
wantPreFilterResult : nil ,
wantSkippedPlugins : sets . New ( "skip1" , "skip2" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
2023-08-05 21:39:18 -04:00
{
name : "one PreFilter plugin returned Unschedulable, but another PreFilter plugin should be executed" ,
plugins : [ ] * TestPlugin {
{
name : "unschedulable" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Unschedulable ) } ,
2023-08-05 21:39:18 -04:00
} ,
{
// to make sure this plugin is executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name : "skip" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-08-05 21:39:18 -04:00
} ,
} ,
wantPreFilterResult : nil ,
wantSkippedPlugins : sets . New ( "skip" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Unschedulable ,
2023-08-05 21:39:18 -04:00
} ,
{
name : "one PreFilter plugin returned UnschedulableAndUnresolvable, and all other plugins aren't executed" ,
plugins : [ ] * TestPlugin {
{
name : "unresolvable" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2023-08-05 21:39:18 -04:00
} ,
{
// to make sure this plugin is not executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name : "skip" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-08-05 21:39:18 -04:00
} ,
} ,
wantPreFilterResult : nil ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . UnschedulableAndUnresolvable ,
2023-08-05 21:39:18 -04:00
} ,
{
2023-12-31 01:52:31 -05:00
name : "all nodes are filtered out by prefilter result, but other plugins aren't executed because we consider all nodes are filtered out by UnschedulableAndUnresolvable" ,
2023-08-05 21:39:18 -04:00
plugins : [ ] * TestPlugin {
{
name : "reject-all-nodes" ,
2025-07-24 07:48:07 -04:00
inj : injectedResult { PreFilterResult : & fwk . PreFilterResult { NodeNames : sets . New [ string ] ( ) } } ,
2023-08-05 21:39:18 -04:00
} ,
{
// to make sure this plugin is not executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name : "skip" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterStatus : int ( fwk . Skip ) } ,
2023-08-05 21:39:18 -04:00
} ,
} ,
2025-07-24 07:48:07 -04:00
wantPreFilterResult : & fwk . PreFilterResult { NodeNames : sets . New [ string ] ( ) } ,
2023-12-31 01:52:31 -05:00
wantSkippedPlugins : sets . New [ string ] ( ) , // "skip" plugin isn't executed.
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . UnschedulableAndUnresolvable ,
2023-08-05 21:39:18 -04:00
} ,
2022-08-25 07:21:28 -04:00
}
2023-01-05 12:48:46 -05:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
r := make ( Registry )
enabled := make ( [ ] config . Plugin , len ( tt . plugins ) )
for i , p := range tt . plugins {
p := p
enabled [ i ] . Name = p . name
2025-07-24 07:48:07 -04:00
if err := r . Register ( p . name , func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2023-01-05 12:48:46 -05:00
return p , nil
2023-09-05 23:55:33 -04:00
} ) ; err != nil {
t . Fatalf ( "fail to register PreFilter plugin (%s)" , p . Name ( ) )
}
2023-01-05 12:48:46 -05:00
}
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2023-01-05 12:48:46 -05:00
defer cancel ( )
f , err := newFrameworkWithQueueSortAndBind (
2023-05-15 06:36:17 -04:00
ctx ,
2023-01-05 12:48:46 -05:00
r ,
config . KubeSchedulerProfile { Plugins : & config . Plugins { PreFilter : config . PluginSet { Enabled : enabled } } } ,
2025-03-11 06:08:25 -04:00
WithSnapshotSharedLister ( cache . NewEmptySnapshot ( ) ) ,
2023-01-05 12:48:46 -05:00
)
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-01-05 12:48:46 -05:00
state := framework . NewCycleState ( )
2024-07-01 21:26:58 -04:00
result , status , _ := f . RunPreFilterPlugins ( ctx , state , nil )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantPreFilterResult , result ) ; diff != "" {
t . Errorf ( "wrong status (-want,+got):\n%s" , diff )
2023-01-05 12:48:46 -05:00
}
if status . Code ( ) != tt . wantStatusCode {
t . Errorf ( "wrong status code. got: %v, want: %v" , status , tt . wantStatusCode )
}
2025-05-21 11:21:27 -04:00
skipped := state . GetSkipFilterPlugins ( )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantSkippedPlugins , skipped ) ; diff != "" {
t . Errorf ( "wrong skip filter plugins (-want,+got):\n%s" , diff )
2023-01-05 12:48:46 -05:00
}
2022-11-09 06:55:33 -05:00
} )
2023-01-05 12:48:46 -05:00
}
}
2022-08-25 07:21:28 -04:00
2023-01-05 12:48:46 -05:00
func TestRunPreFilterExtensionRemovePod ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
skippedPluginNames sets . Set [ string ]
2025-06-03 18:59:50 -04:00
wantStatusCode fwk . Code
2023-01-05 12:48:46 -05:00
} {
{
name : "no plugins are skipped and all RemovePod() returned success" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "success2" ,
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one RemovePod() returned error" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "error1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterRemovePodStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one RemovePod() is skipped" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "skipped" ,
// To confirm it's skipped, return error so that this test case will fail when it isn't skipped.
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterRemovePodStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
skippedPluginNames : sets . New ( "skipped" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
r := make ( Registry )
enabled := make ( [ ] config . Plugin , len ( tt . plugins ) )
for i , p := range tt . plugins {
p := p
enabled [ i ] . Name = p . name
2025-07-24 07:48:07 -04:00
if err := r . Register ( p . name , func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2023-01-05 12:48:46 -05:00
return p , nil
2023-09-05 23:55:33 -04:00
} ) ; err != nil {
t . Fatalf ( "fail to register PreFilterExtension plugin (%s)" , p . Name ( ) )
}
2023-01-05 12:48:46 -05:00
}
2022-08-25 07:21:28 -04:00
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2023-01-05 12:48:46 -05:00
defer cancel ( )
2022-08-25 07:21:28 -04:00
2023-01-05 12:48:46 -05:00
f , err := newFrameworkWithQueueSortAndBind (
2023-05-15 06:36:17 -04:00
ctx ,
2023-01-05 12:48:46 -05:00
r ,
config . KubeSchedulerProfile { Plugins : & config . Plugins { PreFilter : config . PluginSet { Enabled : enabled } } } ,
)
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-01-05 12:48:46 -05:00
state := framework . NewCycleState ( )
2025-05-21 11:21:27 -04:00
state . SetSkipFilterPlugins ( tt . skippedPluginNames )
2023-01-05 12:48:46 -05:00
status := f . RunPreFilterExtensionRemovePod ( ctx , state , nil , nil , nil )
if status . Code ( ) != tt . wantStatusCode {
t . Errorf ( "wrong status code. got: %v, want: %v" , status , tt . wantStatusCode )
}
} )
2022-11-09 06:55:33 -05:00
}
2023-01-05 12:48:46 -05:00
}
func TestRunPreFilterExtensionAddPod ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
skippedPluginNames sets . Set [ string ]
2025-06-03 18:59:50 -04:00
wantStatusCode fwk . Code
2023-01-05 12:48:46 -05:00
} {
{
name : "no plugins are skipped and all AddPod() returned success" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "success2" ,
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one AddPod() returned error" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "error1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterAddPodStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Error ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "one AddPod() is skipped" ,
plugins : [ ] * TestPlugin {
{
name : "success1" ,
} ,
{
name : "skipped" ,
// To confirm it's skipped, return error so that this test case will fail when it isn't skipped.
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreFilterAddPodStatus : int ( fwk . Error ) } ,
2023-01-05 12:48:46 -05:00
} ,
} ,
skippedPluginNames : sets . New ( "skipped" ) ,
2025-06-03 18:59:50 -04:00
wantStatusCode : fwk . Success ,
2023-01-05 12:48:46 -05:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
r := make ( Registry )
enabled := make ( [ ] config . Plugin , len ( tt . plugins ) )
for i , p := range tt . plugins {
p := p
enabled [ i ] . Name = p . name
2025-07-24 07:48:07 -04:00
if err := r . Register ( p . name , func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2023-01-05 12:48:46 -05:00
return p , nil
2023-09-05 23:55:33 -04:00
} ) ; err != nil {
t . Fatalf ( "fail to register PreFilterExtension plugin (%s)" , p . Name ( ) )
}
2023-01-05 12:48:46 -05:00
}
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2023-01-05 12:48:46 -05:00
defer cancel ( )
f , err := newFrameworkWithQueueSortAndBind (
2023-05-15 06:36:17 -04:00
ctx ,
2023-01-05 12:48:46 -05:00
r ,
config . KubeSchedulerProfile { Plugins : & config . Plugins { PreFilter : config . PluginSet { Enabled : enabled } } } ,
)
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-01-05 12:48:46 -05:00
state := framework . NewCycleState ( )
2025-05-21 11:21:27 -04:00
state . SetSkipFilterPlugins ( tt . skippedPluginNames )
2025-06-11 05:56:18 -04:00
ni := framework . NewNodeInfo ( )
status := f . RunPreFilterExtensionAddPod ( ctx , state , nil , nil , ni )
2023-01-05 12:48:46 -05:00
if status . Code ( ) != tt . wantStatusCode {
t . Errorf ( "wrong status code. got: %v, want: %v" , status , tt . wantStatusCode )
}
} )
2022-08-25 07:21:28 -04:00
}
}
2019-11-13 03:17:11 -05:00
func TestFilterPlugins ( t * testing . T ) {
tests := [ ] struct {
2023-01-05 12:48:46 -05:00
name string
plugins [ ] * TestPlugin
skippedPlugins sets . Set [ string ]
2025-06-03 18:59:50 -04:00
wantStatus * fwk . Status
2019-11-13 03:17:11 -05:00
} {
{
name : "SuccessFilter" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2023-01-03 01:33:58 -05:00
wantStatus : nil ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "ErrorFilter" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running "TestPlugin" filter plugin: %w ` , errInjectedFilterStatus ) ) . WithPlugin ( "TestPlugin" ) ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "UnschedulableFilter" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Unschedulable ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectFilterReason ) . WithPlugin ( "TestPlugin" ) ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "UnschedulableAndUnresolvableFilter" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
FilterStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectFilterReason ) . WithPlugin ( "TestPlugin" ) ,
2019-11-13 03:17:11 -05:00
} ,
2022-03-24 07:56:10 -04:00
// following tests cover multiple-plugins scenarios
2019-11-13 03:17:11 -05:00
{
name : "ErrorAndErrorFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running "TestPlugin1" filter plugin: %w ` , errInjectedFilterStatus ) ) . WithPlugin ( "TestPlugin1" ) ,
2019-11-13 03:17:11 -05:00
} ,
2022-12-15 15:00:55 -05:00
{
name : "UnschedulableAndUnschedulableFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Unschedulable ) } ,
2022-12-15 15:00:55 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Unschedulable ) } ,
2022-12-15 15:00:55 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectFilterReason ) . WithPlugin ( "TestPlugin1" ) ,
2023-01-03 01:33:58 -05:00
} ,
{
name : "UnschedulableAndUnschedulableAndUnresolvableFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2023-01-03 01:33:58 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Unschedulable ) } ,
2023-01-03 01:33:58 -05:00
} ,
2022-12-15 15:00:55 -05:00
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectFilterReason ) . WithPlugin ( "TestPlugin1" ) ,
2022-12-15 15:00:55 -05:00
} ,
2019-11-13 03:17:11 -05:00
{
name : "SuccessAndSuccessFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2023-01-03 01:33:58 -05:00
wantStatus : nil ,
2019-11-13 03:17:11 -05:00
} ,
2023-01-05 12:48:46 -05:00
{
name : "SuccessAndSkipFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2023-01-05 12:48:46 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } , // To make sure this plugins isn't called, set error as an injected result.
2023-01-05 12:48:46 -05:00
} ,
} ,
wantStatus : nil ,
skippedPlugins : sets . New ( "TestPlugin2" ) ,
} ,
2019-11-13 03:17:11 -05:00
{
name : "ErrorAndSuccessFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running "TestPlugin1" filter plugin: %w ` , errInjectedFilterStatus ) ) . WithPlugin ( "TestPlugin1" ) ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "SuccessAndErrorFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Error ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running "TestPlugin2" filter plugin: %w ` , errInjectedFilterStatus ) ) . WithPlugin ( "TestPlugin2" ) ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "SuccessAndUnschedulableFilters" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Success ) } ,
2019-11-13 03:17:11 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { FilterStatus : int ( fwk . Unschedulable ) } ,
2019-11-13 03:17:11 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectFilterReason ) . WithPlugin ( "TestPlugin2" ) ,
2019-12-20 16:50:17 -05:00
} ,
2019-11-13 03:17:11 -05:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2019-11-13 03:17:11 -05:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
cfgPls := & config . Plugins { }
2019-11-13 03:17:11 -05:00
for _ , pl := range tt . plugins {
// register all plugins
tmpPl := pl
if err := registry . Register ( pl . name ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2019-11-13 03:17:11 -05:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "fail to register filter plugin (%s)" , pl . name )
}
// append plugins to filter pluginset
cfgPls . Filter . Enabled = append (
cfgPls . Filter . Enabled ,
config . Plugin { Name : pl . name } )
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : cfgPls }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-01-03 01:33:58 -05:00
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2019-11-13 03:17:11 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2023-01-05 12:48:46 -05:00
state := framework . NewCycleState ( )
2025-05-21 11:21:27 -04:00
state . SetSkipFilterPlugins ( tt . skippedPlugins )
2023-01-05 12:48:46 -05:00
gotStatus := f . RunFilterPlugins ( ctx , state , pod , nil )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantStatus , gotStatus , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Unexpected status: (-want,+got):\n%s" , diff )
2019-11-13 03:17:11 -05:00
}
} )
}
}
2020-06-05 16:02:45 -04:00
func TestPostFilterPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
2025-06-03 18:59:50 -04:00
wantStatus * fwk . Status
2020-06-05 16:02:45 -04:00
} {
{
name : "a single plugin makes a Pod schedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Success ) } ,
2020-06-05 16:02:45 -04:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Success , injectReason ) ,
2020-06-05 16:02:45 -04:00
} ,
{
name : "plugin1 failed to make a Pod schedulable, followed by plugin2 which makes the Pod schedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Unschedulable ) } ,
2020-06-05 16:02:45 -04:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Success ) } ,
2020-06-05 16:02:45 -04:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Success , injectReason ) ,
2020-06-05 16:02:45 -04:00
} ,
{
name : "plugin1 makes a Pod schedulable, followed by plugin2 which cannot make the Pod schedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Success ) } ,
2020-06-05 16:02:45 -04:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Unschedulable ) } ,
2020-06-05 16:02:45 -04:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Success , injectReason ) ,
2020-06-05 16:02:45 -04:00
} ,
2023-01-05 03:59:19 -05:00
{
name : "plugin1 failed to make a Pod schedulable, followed by plugin2 which makes the Pod schedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Error ) } ,
2023-01-05 03:59:19 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Success ) } ,
2023-01-05 03:59:19 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( errors . New ( injectReason ) ) . WithPlugin ( "TestPlugin1" ) ,
2023-01-05 03:59:19 -05:00
} ,
{
name : "plugin1 failed to make a Pod schedulable, followed by plugin2 which makes the Pod unresolvable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Unschedulable ) } ,
2023-01-05 03:59:19 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2023-01-05 03:59:19 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectReason ) . WithPlugin ( "TestPlugin2" ) ,
2023-01-05 03:59:19 -05:00
} ,
{
name : "both plugins failed to make a Pod schedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Unschedulable ) } ,
2023-01-05 03:59:19 -05:00
} ,
{
name : "TestPlugin2" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PostFilterStatus : int ( fwk . Unschedulable ) } ,
2023-01-05 03:59:19 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , [ ] string { injectReason , injectReason } ... ) . WithPlugin ( "TestPlugin1" ) ,
2023-01-05 03:59:19 -05:00
} ,
2020-06-05 16:02:45 -04:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2020-06-05 16:02:45 -04:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
cfgPls := & config . Plugins { }
2020-06-05 16:02:45 -04:00
for _ , pl := range tt . plugins {
// register all plugins
tmpPl := pl
if err := registry . Register ( pl . name ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-06-05 16:02:45 -04:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "fail to register postFilter plugin (%s)" , pl . name )
}
// append plugins to filter pluginset
cfgPls . PostFilter . Enabled = append (
cfgPls . PostFilter . Enabled ,
config . Plugin { Name : pl . name } ,
)
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : cfgPls }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2020-06-05 16:02:45 -04:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2025-05-21 11:21:27 -04:00
_ , gotStatus := f . RunPostFilterPlugins ( ctx , state , pod , nil )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantStatus , gotStatus , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Unexpected status (-want,+got):\n%s" , diff )
2020-06-05 16:02:45 -04:00
}
} )
}
}
2020-12-19 11:18:40 -05:00
func TestFilterPluginsWithNominatedPods ( t * testing . T ) {
tests := [ ] struct {
name string
preFilterPlugin * TestPlugin
filterPlugin * TestPlugin
pod * v1 . Pod
nominatedPod * v1 . Pod
node * v1 . Node
nodeInfo * framework . NodeInfo
2025-06-03 18:59:50 -04:00
wantStatus * fwk . Status
2020-12-19 11:18:40 -05:00
} {
{
name : "node has no nominated pod" ,
preFilterPlugin : nil ,
filterPlugin : nil ,
pod : lowPriorityPod ,
nominatedPod : nil ,
node : node ,
nodeInfo : framework . NewNodeInfo ( pod ) ,
wantStatus : nil ,
} ,
{
name : "node has a high-priority nominated pod and all filters succeed" ,
preFilterPlugin : & TestPlugin {
name : "TestPlugin1" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
PreFilterAddPodStatus : int ( fwk . Success ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
filterPlugin : & TestPlugin {
name : "TestPlugin2" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
FilterStatus : int ( fwk . Success ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
pod : lowPriorityPod ,
nominatedPod : highPriorityPod ,
node : node ,
nodeInfo : framework . NewNodeInfo ( pod ) ,
wantStatus : nil ,
} ,
{
name : "node has a high-priority nominated pod and pre filters fail" ,
preFilterPlugin : & TestPlugin {
name : "TestPlugin1" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
PreFilterAddPodStatus : int ( fwk . Error ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
filterPlugin : nil ,
pod : lowPriorityPod ,
nominatedPod : highPriorityPod ,
node : node ,
nodeInfo : framework . NewNodeInfo ( pod ) ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running AddPod on PreFilter plugin "TestPlugin1": %w ` , errInjectedStatus ) ) ,
2020-12-19 11:18:40 -05:00
} ,
{
name : "node has a high-priority nominated pod and filters fail" ,
preFilterPlugin : & TestPlugin {
name : "TestPlugin1" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
PreFilterAddPodStatus : int ( fwk . Success ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
filterPlugin : & TestPlugin {
name : "TestPlugin2" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
FilterStatus : int ( fwk . Error ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
pod : lowPriorityPod ,
nominatedPod : highPriorityPod ,
node : node ,
nodeInfo : framework . NewNodeInfo ( pod ) ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running "TestPlugin2" filter plugin: %w ` , errInjectedFilterStatus ) ) . WithPlugin ( "TestPlugin2" ) ,
2020-12-19 11:18:40 -05:00
} ,
{
name : "node has a low-priority nominated pod and pre filters return unschedulable" ,
preFilterPlugin : & TestPlugin {
name : "TestPlugin1" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
PreFilterAddPodStatus : int ( fwk . Unschedulable ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
filterPlugin : & TestPlugin {
name : "TestPlugin2" ,
inj : injectedResult {
2025-06-03 18:59:50 -04:00
FilterStatus : int ( fwk . Success ) ,
2020-12-19 11:18:40 -05:00
} ,
} ,
pod : highPriorityPod ,
nominatedPod : lowPriorityPod ,
node : node ,
nodeInfo : framework . NewNodeInfo ( pod ) ,
wantStatus : nil ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
logger , ctx := ktesting . NewTestContext ( t )
2020-12-19 11:18:40 -05:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
cfgPls := & config . Plugins { }
2020-12-19 11:18:40 -05:00
if tt . preFilterPlugin != nil {
if err := registry . Register ( tt . preFilterPlugin . name ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-12-19 11:18:40 -05:00
return tt . preFilterPlugin , nil
} ) ; err != nil {
t . Fatalf ( "fail to register preFilter plugin (%s)" , tt . preFilterPlugin . name )
}
cfgPls . PreFilter . Enabled = append (
cfgPls . PreFilter . Enabled ,
config . Plugin { Name : tt . preFilterPlugin . name } ,
)
}
if tt . filterPlugin != nil {
if err := registry . Register ( tt . filterPlugin . name ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-12-19 11:18:40 -05:00
return tt . filterPlugin , nil
} ) ; err != nil {
t . Fatalf ( "fail to register filter plugin (%s)" , tt . filterPlugin . name )
}
cfgPls . Filter . Enabled = append (
cfgPls . Filter . Enabled ,
config . Plugin { Name : tt . filterPlugin . name } ,
)
}
2024-07-22 07:53:08 -04:00
informerFactory := informers . NewSharedInformerFactory ( clientsetfake . NewClientset ( ) , 0 )
podInformer := informerFactory . Core ( ) . V1 ( ) . Pods ( ) . Informer ( )
err := podInformer . GetStore ( ) . Add ( tt . pod )
if err != nil {
t . Fatalf ( "Error adding pod to podInformer: %s" , err )
}
if tt . nominatedPod != nil {
err = podInformer . GetStore ( ) . Add ( tt . nominatedPod )
if err != nil {
t . Fatalf ( "Error adding nominated pod to podInformer: %s" , err )
}
}
podNominator := internalqueue . NewSchedulingQueue ( nil , informerFactory )
2020-12-19 11:18:40 -05:00
if tt . nominatedPod != nil {
2021-12-16 13:54:58 -05:00
podNominator . AddNominatedPod (
2023-03-22 07:48:04 -04:00
logger ,
2022-10-12 10:11:04 -04:00
mustNewPodInfo ( t , tt . nominatedPod ) ,
2025-07-24 07:48:07 -04:00
& fwk . NominatingInfo { NominatingMode : fwk . ModeOverride , NominatedNodeName : nodeName } )
2020-12-19 11:18:40 -05:00
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : cfgPls }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile , WithPodNominator ( podNominator ) )
2020-12-19 11:18:40 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2020-12-19 11:18:40 -05:00
tt . nodeInfo . SetNode ( tt . node )
2025-05-21 11:21:27 -04:00
gotStatus := f . RunFilterPluginsWithNominatedPods ( ctx , state , tt . pod , tt . nodeInfo )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantStatus , gotStatus , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Unexpected status: (-want,+got):\n%s" , diff )
2020-12-19 11:18:40 -05:00
}
} )
}
}
2020-01-21 18:36:12 -05:00
func TestPreBindPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
2025-06-03 18:59:50 -04:00
wantStatus * fwk . Status
2020-01-21 18:36:12 -05:00
} {
{
name : "NoPreBindPlugin" ,
plugins : [ ] * TestPlugin { } ,
wantStatus : nil ,
} ,
{
name : "SuccessPreBindPlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
wantStatus : nil ,
} ,
{
2022-08-25 07:02:07 -04:00
name : "UnschedulablePreBindPlugin" ,
2020-01-21 18:36:12 -05:00
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Unschedulable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "ErrorPreBindPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running PreBind plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "UnschedulablePreBindPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "SuccessErrorPreBindPlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running PreBind plugin "TestPlugin 1": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "ErrorSuccessPreBindPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running PreBind plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "SuccessSuccessPreBindPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
wantStatus : nil ,
} ,
{
name : "ErrorAndErrorPlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running PreBind plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "UnschedulableAndSuccessPreBindPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Unschedulable ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PreBindStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2020-01-21 18:36:12 -05:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
configPlugins := & config . Plugins { }
2020-01-21 18:36:12 -05:00
for _ , pl := range tt . plugins {
tmpPl := pl
2025-07-24 07:48:07 -04:00
if err := registry . Register ( pl . name , func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-01-21 18:36:12 -05:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "Unable to register pre bind plugins: %s" , pl . name )
}
configPlugins . PreBind . Enabled = append (
configPlugins . PreBind . Enabled ,
config . Plugin { Name : pl . name } ,
)
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : configPlugins }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2020-01-21 18:36:12 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2020-01-21 18:36:12 -05:00
2025-05-21 11:21:27 -04:00
status := f . RunPreBindPlugins ( ctx , state , pod , "" )
2020-01-21 18:36:12 -05:00
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantStatus , status , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Wrong status code (-want,+got):\n%s" , diff )
2020-01-21 18:36:12 -05:00
}
} )
}
}
2025-12-04 14:01:19 -05:00
func TestGetPreBindPluginGroups ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] fwk . PreBindPlugin
skippedPlugins sets . Set [ string ]
parallelPlugins sets . Set [ string ]
expectedGroups [ ] [ ] string
} {
{
name : "No plugins" ,
plugins : [ ] fwk . PreBindPlugin { } ,
expectedGroups : nil ,
} ,
{
name : "Single plugin, not skipped, not parallel" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
} ,
expectedGroups : [ ] [ ] string { { "p1" } } ,
} ,
{
name : "Single plugin, skipped" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
} ,
skippedPlugins : sets . New ( "p1" ) ,
expectedGroups : nil ,
} ,
{
name : "Single plugin, parallel" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
} ,
parallelPlugins : sets . New ( "p1" ) ,
expectedGroups : [ ] [ ] string { { "p1" } } ,
} ,
{
name : "Single plugin, parallel & skipped" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
} ,
parallelPlugins : sets . New ( "p1" ) ,
skippedPlugins : sets . New ( "p1" ) ,
expectedGroups : nil ,
} ,
{
name : "Multiple plugins, consecutive serial" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
& TestPlugin { name : "p2" } ,
} ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p2" } ,
} ,
} ,
{
name : "Multiple plugins, consecutive parallel" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } ,
& TestPlugin { name : "p2" } ,
} ,
parallelPlugins : sets . New ( "p1" , "p2" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" , "p2" } ,
} ,
} ,
{
name : "Multiple plugins, mixed parallel and serial" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // serial
& TestPlugin { name : "p2" } , // parallel
& TestPlugin { name : "p3" } , // parallel
& TestPlugin { name : "p4" } , // serial
} ,
parallelPlugins : sets . New ( "p2" , "p3" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p2" , "p3" } ,
{ "p4" } ,
} ,
} ,
{
name : "Parallel plugins separated by serial" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // parallel
& TestPlugin { name : "p2" } , // serial
& TestPlugin { name : "p3" } , // parallel
} ,
parallelPlugins : sets . New ( "p1" , "p3" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p2" } ,
{ "p3" } ,
} ,
} ,
{
name : "Skipped plugins" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // serial
& TestPlugin { name : "p2" } , // serial & skipped
& TestPlugin { name : "p3" } , // serial
} ,
skippedPlugins : sets . New ( "p2" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p3" } ,
} ,
} ,
{
name : "Parallel plugins with one skipped in between" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // parallel
& TestPlugin { name : "p2" } , // parallel & skipped
& TestPlugin { name : "p3" } , // parallel
} ,
parallelPlugins : sets . New ( "p1" , "p2" , "p3" ) ,
skippedPlugins : sets . New ( "p2" ) ,
expectedGroups : [ ] [ ] string { { "p1" , "p3" } } ,
} ,
{
name : "Parallel plugins with one serial & skipped in between" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // parallel
& TestPlugin { name : "p2" } , // serial & skipped
& TestPlugin { name : "p3" } , // parallel
} ,
parallelPlugins : sets . New ( "p1" , "p3" ) ,
skippedPlugins : sets . New ( "p2" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p3" } ,
} ,
} ,
{
name : "Complex mix" ,
plugins : [ ] fwk . PreBindPlugin {
& TestPlugin { name : "p1" } , // serial
& TestPlugin { name : "p2" } , // parallel
& TestPlugin { name : "p3" } , // serial & skipped
& TestPlugin { name : "p4" } , // parallel
& TestPlugin { name : "p5" } , // parallel & skipped
& TestPlugin { name : "p6" } , // parallel
& TestPlugin { name : "p7" } , // serial
& TestPlugin { name : "p8" } , // serial
} ,
parallelPlugins : sets . New ( "p2" , "p4" , "p5" , "p6" ) ,
skippedPlugins : sets . New ( "p3" , "p5" ) ,
expectedGroups : [ ] [ ] string {
{ "p1" } ,
{ "p2" } ,
{ "p4" , "p6" } ,
{ "p7" } ,
{ "p8" } ,
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
f := & frameworkImpl {
preBindPlugins : tt . plugins ,
}
state := framework . NewCycleState ( )
groups := f . getPreBindPluginGroups ( state , tt . skippedPlugins , tt . parallelPlugins )
var gotGroups [ ] [ ] string
for _ , g := range groups {
var groupNames [ ] string
for _ , p := range g {
groupNames = append ( groupNames , p . Name ( ) )
}
gotGroups = append ( gotGroups , groupNames )
}
if diff := cmp . Diff ( tt . expectedGroups , gotGroups ) ; diff != "" {
t . Errorf ( "getPreBindPluginGroups() mismatch (-want +got):\n%s" , diff )
}
} )
}
}
2025-07-17 03:30:10 -04:00
func TestPreBindPreFlightPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
wantStatus * fwk . Status
} {
{
name : "Skip when there's no PreBind Plugin" ,
plugins : [ ] * TestPlugin { } ,
wantStatus : fwk . NewStatus ( fwk . Skip ) ,
} ,
{
name : "Success when PreBindPreFlight returns Success" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Skip ) } ,
} ,
{
name : "TestPlugin2" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Success ) } ,
} ,
} ,
wantStatus : nil ,
} ,
{
name : "Skip when all PreBindPreFlight returns Skip" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Skip ) } ,
} ,
{
name : "TestPlugin2" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Skip ) } ,
} ,
} ,
wantStatus : fwk . NewStatus ( fwk . Skip ) ,
} ,
{
name : "Error when PreBindPreFlight returns Error" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin1" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Skip ) } ,
} ,
{
name : "TestPlugin2" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Error ) } ,
} ,
} ,
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running PreBindPreFlight "TestPlugin2": %w ` , errInjectedStatus ) ) ,
} ,
{
name : "Error when PreBindPreFlight returns Unschedulable" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
inj : injectedResult { PreBindPreFlightStatus : int ( fwk . Unschedulable ) } ,
} ,
} ,
wantStatus : fwk . NewStatus ( fwk . Error , "PreBindPreFlight TestPlugin returned \"Unschedulable\", which is unsupported. It is supposed to return Success, Skip, or Error status" ) ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
_ , ctx := ktesting . NewTestContext ( t )
registry := Registry { }
configPlugins := & config . Plugins { }
for _ , pl := range tt . plugins {
tmpPl := pl
2025-07-24 07:48:07 -04:00
if err := registry . Register ( pl . name , func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2025-07-17 03:30:10 -04:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "Unable to register pre bind plugins: %s" , pl . name )
}
configPlugins . PreBind . Enabled = append (
configPlugins . PreBind . Enabled ,
config . Plugin { Name : pl . name } ,
)
}
profile := config . KubeSchedulerProfile { Plugins : configPlugins }
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
defer func ( ) {
_ = f . Close ( )
} ( )
status := f . RunPreBindPreFlights ( ctx , state , pod , "" )
if diff := cmp . Diff ( tt . wantStatus , status , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Wrong status code (-want,+got):\n%s" , diff )
}
} )
}
}
2020-01-21 18:36:12 -05:00
func TestReservePlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
2025-06-03 18:59:50 -04:00
wantStatus * fwk . Status
2020-01-21 18:36:12 -05:00
} {
{
name : "NoReservePlugin" ,
plugins : [ ] * TestPlugin { } ,
wantStatus : nil ,
} ,
{
name : "SuccessReservePlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
wantStatus : nil ,
} ,
{
2022-08-25 07:02:07 -04:00
name : "UnschedulableReservePlugin" ,
2020-01-21 18:36:12 -05:00
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Unschedulable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "ErrorReservePlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running Reserve plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "UnschedulableReservePlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "SuccessSuccessReservePlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
wantStatus : nil ,
} ,
{
name : "ErrorErrorReservePlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running Reserve plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "SuccessErrorReservePlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running Reserve plugin "TestPlugin 1": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "ErrorSuccessReservePlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . AsStatus ( fmt . Errorf ( ` running Reserve plugin "TestPlugin": %w ` , errInjectedStatus ) ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "UnschedulableAndSuccessReservePlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Unschedulable ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { ReserveStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . NewStatus ( fwk . Unschedulable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2020-01-21 18:36:12 -05:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
configPlugins := & config . Plugins { }
2020-01-21 18:36:12 -05:00
for _ , pl := range tt . plugins {
tmpPl := pl
2025-07-24 07:48:07 -04:00
if err := registry . Register ( pl . name , func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2020-01-21 18:36:12 -05:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "Unable to register pre bind plugins: %s" , pl . name )
}
configPlugins . Reserve . Enabled = append (
configPlugins . Reserve . Enabled ,
config . Plugin { Name : pl . name } ,
)
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : configPlugins }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2023-05-15 06:36:17 -04:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2020-01-21 18:36:12 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2025-05-21 11:21:27 -04:00
status := f . RunReservePluginsReserve ( ctx , state , pod , "" )
2020-01-21 18:36:12 -05:00
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . wantStatus , status , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Wrong status code (-want,+got):\n%s" , diff )
2020-01-21 18:36:12 -05:00
}
} )
}
}
func TestPermitPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins [ ] * TestPlugin
2025-06-03 18:59:50 -04:00
want * fwk . Status
2020-01-21 18:36:12 -05:00
} {
{
name : "NilPermitPlugin" ,
plugins : [ ] * TestPlugin { } ,
want : nil ,
} ,
{
name : "SuccessPermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
want : nil ,
} ,
{
name : "UnschedulablePermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Unschedulable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
want : fwk . NewStatus ( fwk . Unschedulable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "ErrorPermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
want : fwk . AsStatus ( fmt . Errorf ( ` running Permit plugin "TestPlugin": %w ` , errInjectedStatus ) ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "UnschedulableAndUnresolvablePermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . UnschedulableAndUnresolvable ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
want : fwk . NewStatus ( fwk . UnschedulableAndUnresolvable , injectReason ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "WaitPermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Wait ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
want : fwk . NewStatus ( fwk . Wait , ` one or more plugins asked to wait and no plugin rejected pod "" ` ) ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "SuccessSuccessPermitPlugin" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Success ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
want : nil ,
} ,
{
name : "ErrorAndErrorPlugins" ,
plugins : [ ] * TestPlugin {
{
name : "TestPlugin" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "TestPlugin 1" ,
2025-06-03 18:59:50 -04:00
inj : injectedResult { PermitStatus : int ( fwk . Error ) } ,
2020-01-21 18:36:12 -05:00
} ,
} ,
2025-06-03 18:59:50 -04:00
want : fwk . AsStatus ( fmt . Errorf ( ` running Permit plugin "TestPlugin": %w ` , errInjectedStatus ) ) . WithPlugin ( "TestPlugin" ) ,
2020-01-21 18:36:12 -05:00
} ,
}
for _ , tt := range tests {
2021-01-13 19:39:55 -05:00
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2021-01-13 19:39:55 -05:00
registry := Registry { }
2021-02-10 10:45:59 -05:00
configPlugins := & config . Plugins { }
2020-01-21 18:36:12 -05:00
2021-01-13 19:39:55 -05:00
for _ , pl := range tt . plugins {
tmpPl := pl
2025-07-24 07:48:07 -04:00
if err := registry . Register ( pl . name , func ( _ context . Context , _ runtime . Object , _ fwk . Handle ) ( fwk . Plugin , error ) {
2021-01-13 19:39:55 -05:00
return tmpPl , nil
} ) ; err != nil {
t . Fatalf ( "Unable to register Permit plugin: %s" , pl . name )
}
2020-01-21 18:36:12 -05:00
2021-01-13 19:39:55 -05:00
configPlugins . Permit . Enabled = append (
configPlugins . Permit . Enabled ,
config . Plugin { Name : pl . name } ,
)
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : configPlugins }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2024-01-24 08:21:21 -05:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile ,
WithWaitingPods ( NewWaitingPodsMap ( ) ) ,
)
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2021-01-13 19:39:55 -05:00
if err != nil {
t . Fatalf ( "fail to create framework: %s" , err )
}
2020-01-21 18:36:12 -05:00
2025-05-21 11:21:27 -04:00
status := f . RunPermitPlugins ( ctx , state , pod , "" )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . want , status , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Wrong status code (-want,+got):\n%s" , diff )
2021-01-13 19:39:55 -05:00
}
} )
2020-01-21 18:36:12 -05:00
}
}
2021-02-22 03:38:13 -05:00
// withMetricsRecorder set metricsRecorder for the scheduling frameworkImpl.
2023-02-04 07:03:01 -05:00
func withMetricsRecorder ( recorder * metrics . MetricAsyncRecorder ) Option {
2021-02-22 03:38:13 -05:00
return func ( o * frameworkOptions ) {
o . metricsRecorder = recorder
}
}
2019-10-04 10:25:17 -04:00
func TestRecordingMetrics ( t * testing . T ) {
2020-06-19 05:05:45 -04:00
state . SetRecordPluginMetrics ( true )
2019-10-04 10:25:17 -04:00
tests := [ ] struct {
name string
2024-09-09 17:59:24 -04:00
action func ( ctx context . Context , f framework . Framework )
2019-10-04 10:25:17 -04:00
inject injectedResult
wantExtensionPoint string
2025-06-03 18:59:50 -04:00
wantStatus fwk . Code
2019-10-04 10:25:17 -04:00
} {
{
name : "PreFilter - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreFilterPlugins ( ctx , state , pod ) } ,
2019-10-29 10:54:02 -04:00
wantExtensionPoint : "PreFilter" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-29 10:54:02 -04:00
} ,
2019-10-04 10:25:17 -04:00
{
2020-02-02 05:07:01 -05:00
name : "PreScore - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreScorePlugins ( ctx , state , pod , nil ) } ,
2020-02-02 05:07:01 -05:00
wantExtensionPoint : "PreScore" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
2023-11-18 05:21:58 -05:00
name : "Score - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) {
f . RunScorePlugins ( ctx , state , pod , BuildNodeInfos ( nodes ) )
2023-11-18 05:21:58 -05:00
} ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Score" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Reserve - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunReservePluginsReserve ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Reserve" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Unreserve - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunReservePluginsUnreserve ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Unreserve" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "PreBind - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreBindPlugins ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "PreBind" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Bind - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunBindPlugins ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Bind" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "PostBind - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPostBindPlugins ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "PostBind" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Permit - Success" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPermitPlugins ( ctx , state , pod , "" ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Permit" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Success ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "PreFilter - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreFilterPlugins ( ctx , state , pod ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PreFilterStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "PreFilter" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
2020-02-02 05:07:01 -05:00
name : "PreScore - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreScorePlugins ( ctx , state , pod , nil ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PreScoreStatus : int ( fwk . Error ) } ,
2020-02-02 05:07:01 -05:00
wantExtensionPoint : "PreScore" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
2023-11-18 05:21:58 -05:00
name : "Score - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) {
f . RunScorePlugins ( ctx , state , pod , BuildNodeInfos ( nodes ) )
2023-11-18 05:21:58 -05:00
} ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { ScoreStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Score" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Reserve - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunReservePluginsReserve ( ctx , state , pod , "" ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { ReserveStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Reserve" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "PreBind - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPreBindPlugins ( ctx , state , pod , "" ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PreBindStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "PreBind" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Bind - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunBindPlugins ( ctx , state , pod , "" ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { BindStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Bind" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
{
name : "Permit - Error" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPermitPlugins ( ctx , state , pod , "" ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PermitStatus : int ( fwk . Error ) } ,
2019-10-04 10:25:17 -04:00
wantExtensionPoint : "Permit" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Error ,
2019-10-04 10:25:17 -04:00
} ,
2020-02-15 19:28:43 -05:00
{
name : "Permit - Wait" ,
2024-09-09 17:59:24 -04:00
action : func ( ctx context . Context , f framework . Framework ) { f . RunPermitPlugins ( ctx , state , pod , "" ) } ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PermitStatus : int ( fwk . Wait ) } ,
2020-02-15 19:28:43 -05:00
wantExtensionPoint : "Permit" ,
2025-06-03 18:59:50 -04:00
wantStatus : fwk . Wait ,
2020-02-15 19:28:43 -05:00
} ,
2019-10-04 10:25:17 -04:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-08-17 19:45:32 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
2019-10-29 10:54:02 -04:00
metrics . FrameworkExtensionPointDuration . Reset ( )
metrics . PluginExecutionDuration . Reset ( )
2019-10-04 10:25:17 -04:00
plugin := & TestPlugin { name : testPlugin , inj : tt . inject }
r := make ( Registry )
r . Register ( testPlugin ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2019-10-04 10:25:17 -04:00
return plugin , nil
} )
2021-02-10 10:45:59 -05:00
pluginSet := config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin , Weight : 1 } } }
2019-10-04 10:25:17 -04:00
plugins := & config . Plugins {
2020-02-02 05:07:01 -05:00
Score : pluginSet ,
PreFilter : pluginSet ,
Filter : pluginSet ,
PreScore : pluginSet ,
Reserve : pluginSet ,
Permit : pluginSet ,
PreBind : pluginSet ,
Bind : pluginSet ,
PostBind : pluginSet ,
2019-10-04 10:25:17 -04:00
}
2022-05-20 12:02:41 -04:00
2023-05-15 06:36:17 -04:00
recorder := metrics . NewMetricsAsyncRecorder ( 100 , time . Nanosecond , ctx . Done ( ) )
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile {
2023-09-11 10:40:18 -04:00
PercentageOfNodesToScore : ptr . To [ int32 ] ( testPercentageOfNodesToScore ) ,
2022-09-16 16:18:12 -04:00
SchedulerName : testProfileName ,
Plugins : plugins ,
2021-03-03 16:44:25 -05:00
}
2024-01-24 08:21:21 -05:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , r , profile ,
withMetricsRecorder ( recorder ) ,
WithWaitingPods ( NewWaitingPodsMap ( ) ) ,
2025-03-11 06:08:25 -04:00
WithSnapshotSharedLister ( cache . NewEmptySnapshot ( ) ) ,
2024-01-24 08:21:21 -05:00
)
2019-10-04 10:25:17 -04:00
if err != nil {
2023-05-15 06:36:17 -04:00
cancel ( )
2019-10-04 10:25:17 -04:00
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2019-10-04 10:25:17 -04:00
2024-09-09 17:59:24 -04:00
tt . action ( ctx , f )
2019-10-04 10:25:17 -04:00
2019-10-29 10:54:02 -04:00
// Stop the goroutine which records metrics and ensure it's stopped.
2023-05-15 06:36:17 -04:00
cancel ( )
2023-02-04 07:03:01 -05:00
<- recorder . IsStoppedCh
2019-10-29 10:54:02 -04:00
// Try to clean up the metrics buffer again in case it's not empty.
2023-02-04 07:03:01 -05:00
recorder . FlushMetrics ( )
2019-10-29 10:54:02 -04:00
2019-10-16 10:15:54 -04:00
collectAndCompareFrameworkMetrics ( t , tt . wantExtensionPoint , tt . wantStatus )
2019-10-29 10:54:02 -04:00
collectAndComparePluginMetrics ( t , tt . wantExtensionPoint , testPlugin , tt . wantStatus )
2019-10-16 10:15:54 -04:00
} )
}
}
2020-01-15 11:26:35 -05:00
func TestRunBindPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
2025-06-03 18:59:50 -04:00
injects [ ] fwk . Code
wantStatus fwk . Code
2020-01-15 11:26:35 -05:00
} {
{
name : "simple success" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Success } ,
wantStatus : fwk . Success ,
2020-01-15 11:26:35 -05:00
} ,
{
name : "error on second" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Skip , fwk . Error , fwk . Success } ,
wantStatus : fwk . Error ,
2020-01-15 11:26:35 -05:00
} ,
{
name : "all skip" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Skip , fwk . Skip , fwk . Skip } ,
wantStatus : fwk . Skip ,
2020-01-15 11:26:35 -05:00
} ,
{
name : "error on third, but not reached" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Skip , fwk . Success , fwk . Error } ,
wantStatus : fwk . Success ,
2020-01-15 11:26:35 -05:00
} ,
2020-01-21 18:36:12 -05:00
{
name : "no bind plugin, returns default binder" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { } ,
wantStatus : fwk . Success ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "invalid status" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Unschedulable } ,
wantStatus : fwk . Unschedulable ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "simple error" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Error } ,
wantStatus : fwk . Error ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "success on second, returns success" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Skip , fwk . Success } ,
wantStatus : fwk . Success ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "invalid status, returns error" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Skip , fwk . UnschedulableAndUnresolvable } ,
wantStatus : fwk . UnschedulableAndUnresolvable ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "error after success status, returns success" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Success , fwk . Error } ,
wantStatus : fwk . Success ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "success before invalid status, returns success" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Success , fwk . Error } ,
wantStatus : fwk . Success ,
2020-01-21 18:36:12 -05:00
} ,
{
name : "success after error status, returns error" ,
2025-06-03 18:59:50 -04:00
injects : [ ] fwk . Code { fwk . Error , fwk . Success } ,
wantStatus : fwk . Error ,
2020-01-21 18:36:12 -05:00
} ,
2020-01-15 11:26:35 -05:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
metrics . FrameworkExtensionPointDuration . Reset ( )
metrics . PluginExecutionDuration . Reset ( )
2021-02-10 10:45:59 -05:00
pluginSet := config . PluginSet { }
2020-01-15 11:26:35 -05:00
r := make ( Registry )
for i , inj := range tt . injects {
name := fmt . Sprintf ( "bind-%d" , i )
plugin := & TestPlugin { name : name , inj : injectedResult { BindStatus : int ( inj ) } }
r . Register ( name ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2020-01-15 11:26:35 -05:00
return plugin , nil
} )
pluginSet . Enabled = append ( pluginSet . Enabled , config . Plugin { Name : name } )
}
plugins := & config . Plugins { Bind : pluginSet }
2023-05-15 06:36:17 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
recorder := metrics . NewMetricsAsyncRecorder ( 100 , time . Nanosecond , ctx . Done ( ) )
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile {
2022-09-16 16:18:12 -04:00
SchedulerName : testProfileName ,
2023-09-11 10:40:18 -04:00
PercentageOfNodesToScore : ptr . To [ int32 ] ( testPercentageOfNodesToScore ) ,
2022-09-16 16:18:12 -04:00
Plugins : plugins ,
2021-03-03 16:44:25 -05:00
}
2023-05-15 06:36:17 -04:00
fwk , err := newFrameworkWithQueueSortAndBind ( ctx , r , profile , withMetricsRecorder ( recorder ) )
2020-01-15 11:26:35 -05:00
if err != nil {
2023-05-15 06:36:17 -04:00
cancel ( )
2020-01-15 11:26:35 -05:00
t . Fatal ( err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = fwk . Close ( )
} ( )
2020-01-15 11:26:35 -05:00
2024-09-09 17:59:24 -04:00
st := fwk . RunBindPlugins ( ctx , state , pod , "" )
2020-01-15 11:26:35 -05:00
if st . Code ( ) != tt . wantStatus {
t . Errorf ( "got status code %s, want %s" , st . Code ( ) , tt . wantStatus )
}
// Stop the goroutine which records metrics and ensure it's stopped.
2023-05-15 06:36:17 -04:00
cancel ( )
2023-02-04 07:03:01 -05:00
<- recorder . IsStoppedCh
2020-01-15 11:26:35 -05:00
// Try to clean up the metrics buffer again in case it's not empty.
2023-02-04 07:03:01 -05:00
recorder . FlushMetrics ( )
2020-01-15 11:26:35 -05:00
collectAndCompareFrameworkMetrics ( t , "Bind" , tt . wantStatus )
} )
}
}
2020-02-15 19:28:43 -05:00
func TestPermitWaitDurationMetric ( t * testing . T ) {
2019-10-16 10:15:54 -04:00
tests := [ ] struct {
name string
inject injectedResult
wantRes string
} {
{
2020-02-15 19:28:43 -05:00
name : "WaitOnPermit - No Wait" ,
2019-10-16 10:15:54 -04:00
} ,
{
2020-02-15 19:28:43 -05:00
name : "WaitOnPermit - Wait Timeout" ,
2025-06-03 18:59:50 -04:00
inject : injectedResult { PermitStatus : int ( fwk . Wait ) } ,
2019-10-16 10:15:54 -04:00
wantRes : "Unschedulable" ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2019-10-29 10:54:02 -04:00
metrics . PermitWaitDuration . Reset ( )
2019-10-16 10:15:54 -04:00
plugin := & TestPlugin { name : testPlugin , inj : tt . inject }
r := make ( Registry )
2020-01-15 11:26:35 -05:00
err := r . Register ( testPlugin ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2019-10-16 10:15:54 -04:00
return plugin , nil
} )
2020-01-15 11:26:35 -05:00
if err != nil {
t . Fatal ( err )
}
2019-10-16 10:15:54 -04:00
plugins := & config . Plugins {
2021-02-10 10:45:59 -05:00
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : testPlugin , Weight : 1 } } } ,
2019-10-16 10:15:54 -04:00
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : plugins }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2024-01-24 08:21:21 -05:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , r , profile ,
WithWaitingPods ( NewWaitingPodsMap ( ) ) ,
)
2019-10-16 10:15:54 -04:00
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2019-10-16 10:15:54 -04:00
2025-05-21 11:21:27 -04:00
f . RunPermitPlugins ( ctx , state , pod , "" )
2022-08-05 12:05:22 -04:00
f . WaitOnPermit ( ctx , pod )
2019-10-16 10:15:54 -04:00
collectAndComparePermitWaitDuration ( t , tt . wantRes )
2019-10-04 10:25:17 -04:00
} )
}
}
2020-02-15 19:28:43 -05:00
func TestWaitOnPermit ( t * testing . T ) {
2019-11-05 09:04:44 -05:00
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "pod" ,
UID : types . UID ( "pod" ) ,
} ,
}
2020-02-15 19:28:43 -05:00
tests := [ ] struct {
2021-01-13 19:39:55 -05:00
name string
action func ( f framework . Framework )
2025-06-03 18:59:50 -04:00
want * fwk . Status
2020-02-15 19:28:43 -05:00
} {
{
name : "Reject Waiting Pod" ,
2020-10-09 10:41:44 -04:00
action : func ( f framework . Framework ) {
2021-01-13 19:39:55 -05:00
f . GetWaitingPod ( pod . UID ) . Reject ( permitPlugin , "reject message" )
2020-02-15 19:28:43 -05:00
} ,
2025-06-03 18:59:50 -04:00
want : fwk . NewStatus ( fwk . Unschedulable , "reject message" ) . WithPlugin ( permitPlugin ) ,
2020-02-15 19:28:43 -05:00
} ,
{
name : "Allow Waiting Pod" ,
2020-10-09 10:41:44 -04:00
action : func ( f framework . Framework ) {
2020-02-15 19:28:43 -05:00
f . GetWaitingPod ( pod . UID ) . Allow ( permitPlugin )
} ,
2021-01-13 19:39:55 -05:00
want : nil ,
2020-02-15 19:28:43 -05:00
} ,
2019-11-05 09:04:44 -05:00
}
2020-02-15 19:28:43 -05:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2024-09-09 17:59:24 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2020-02-15 19:28:43 -05:00
testPermitPlugin := & TestPermitPlugin { }
r := make ( Registry )
r . Register ( permitPlugin ,
2025-07-24 07:48:07 -04:00
func ( _ context . Context , _ runtime . Object , fh fwk . Handle ) ( fwk . Plugin , error ) {
2020-02-15 19:28:43 -05:00
return testPermitPlugin , nil
} )
plugins := & config . Plugins {
2021-02-10 10:45:59 -05:00
Permit : config . PluginSet { Enabled : [ ] config . Plugin { { Name : permitPlugin , Weight : 1 } } } ,
2020-02-15 19:28:43 -05:00
}
2021-03-03 16:44:25 -05:00
profile := config . KubeSchedulerProfile { Plugins : plugins }
2024-09-09 17:59:24 -04:00
ctx , cancel := context . WithCancel ( ctx )
2022-08-05 12:05:22 -04:00
defer cancel ( )
2024-01-24 08:21:21 -05:00
f , err := newFrameworkWithQueueSortAndBind ( ctx , r , profile ,
WithWaitingPods ( NewWaitingPodsMap ( ) ) ,
)
2020-02-15 19:28:43 -05:00
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
2019-11-05 09:04:44 -05:00
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2020-02-15 19:28:43 -05:00
2025-05-21 11:21:27 -04:00
runPermitPluginsStatus := f . RunPermitPlugins ( ctx , state , pod , "" )
2025-06-03 18:59:50 -04:00
if runPermitPluginsStatus . Code ( ) != fwk . Wait {
2020-02-15 19:28:43 -05:00
t . Fatalf ( "Expected RunPermitPlugins to return status %v, but got %v" ,
2025-06-03 18:59:50 -04:00
fwk . Wait , runPermitPluginsStatus . Code ( ) )
2020-02-15 19:28:43 -05:00
}
go tt . action ( f )
2022-08-05 12:05:22 -04:00
got := f . WaitOnPermit ( ctx , pod )
2025-01-27 05:01:57 -05:00
if diff := cmp . Diff ( tt . want , got , statusCmpOpts ... ) ; diff != "" {
t . Errorf ( "Unexpected status (-want,+got):\n%s" , diff )
2020-02-15 19:28:43 -05:00
}
} )
2019-11-05 09:04:44 -05:00
}
}
2020-03-02 03:17:15 -05:00
func TestListPlugins ( t * testing . T ) {
tests := [ ] struct {
name string
plugins * config . Plugins
2021-06-10 08:45:49 -04:00
want * config . Plugins
2020-03-02 03:17:15 -05:00
} {
{
2021-06-10 08:45:49 -04:00
name : "Add empty plugin" ,
plugins : & config . Plugins { } ,
want : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : queueSortPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : bindPlugin } } } ,
2020-03-02 03:17:15 -05:00
} ,
} ,
2021-03-29 04:34:10 -04:00
{
2021-06-10 08:45:49 -04:00
name : "Add multiple plugins" ,
2021-03-29 04:34:10 -04:00
plugins : & config . Plugins {
2021-06-10 08:45:49 -04:00
Score : config . PluginSet { Enabled : [ ] config . Plugin { { Name : scorePlugin1 , Weight : 3 } , { Name : scoreWithNormalizePlugin1 } } } ,
2021-03-29 04:34:10 -04:00
} ,
2021-06-10 08:45:49 -04:00
want : & config . Plugins {
QueueSort : config . PluginSet { Enabled : [ ] config . Plugin { { Name : queueSortPlugin } } } ,
Bind : config . PluginSet { Enabled : [ ] config . Plugin { { Name : bindPlugin } } } ,
Score : config . PluginSet { Enabled : [ ] config . Plugin { { Name : scorePlugin1 , Weight : 3 } , { Name : scoreWithNormalizePlugin1 , Weight : 1 } } } ,
2021-03-29 04:34:10 -04:00
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
profile := config . KubeSchedulerProfile { Plugins : tt . plugins }
2023-05-15 06:36:17 -04:00
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
f , err := newFrameworkWithQueueSortAndBind ( ctx , registry , profile )
2021-03-29 04:34:10 -04:00
if err != nil {
t . Fatalf ( "Failed to create framework for testing: %v" , err )
}
2024-07-03 02:18:25 -04:00
defer func ( ) {
_ = f . Close ( )
} ( )
2021-06-10 08:45:49 -04:00
got := f . ListPlugins ( )
if diff := cmp . Diff ( tt . want , got ) ; diff != "" {
2025-01-27 05:01:57 -05:00
t . Errorf ( "Unexpected plugins (-want,+got):\n%s" , diff )
2021-03-29 04:34:10 -04:00
}
} )
}
}
2023-12-27 10:18:29 -05:00
func TestClose ( t * testing . T ) {
tests := [ ] struct {
name string
plugins * config . Plugins
wantErr error
} {
{
name : "close doesn't return error" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin , Weight : 5 } ,
} ,
} ,
} ,
} ,
{
name : "close returns error" ,
plugins : & config . Plugins {
MultiPoint : config . PluginSet {
Enabled : [ ] config . Plugin {
{ Name : testPlugin , Weight : 5 } ,
{ Name : testCloseErrorPlugin } ,
} ,
} ,
} ,
wantErr : errClose ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
_ , ctx := ktesting . NewTestContext ( t )
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
fw , err := NewFramework ( ctx , registry , & config . KubeSchedulerProfile { Plugins : tc . plugins } )
if err != nil {
t . Fatalf ( "Unexpected error during calling NewFramework, got %v" , err )
}
err = fw . Close ( )
if ! errors . Is ( err , tc . wantErr ) {
t . Fatalf ( "Unexpected error from Close(), got: %v, want: %v" , err , tc . wantErr )
}
} )
}
}
2019-10-04 10:25:17 -04:00
func buildScoreConfigDefaultWeights ( ps ... string ) * config . Plugins {
return buildScoreConfigWithWeights ( defaultWeights , ps ... )
2019-08-19 16:08:14 -04:00
}
2019-10-04 10:25:17 -04:00
func buildScoreConfigWithWeights ( weights map [ string ] int32 , ps ... string ) * config . Plugins {
2019-08-19 16:08:14 -04:00
var plugins [ ] config . Plugin
for _ , p := range ps {
plugins = append ( plugins , config . Plugin { Name : p , Weight : weights [ p ] } )
}
2021-02-10 10:45:59 -05:00
return & config . Plugins { Score : config . PluginSet { Enabled : plugins } }
2019-08-19 16:08:14 -04:00
}
type injectedResult struct {
2025-07-24 07:48:07 -04:00
ScoreRes int64 ` json:"scoreRes,omitempty" `
NormalizeRes int64 ` json:"normalizeRes,omitempty" `
ScoreStatus int ` json:"scoreStatus,omitempty" `
NormalizeStatus int ` json:"normalizeStatus,omitempty" `
PreFilterResult * fwk . PreFilterResult ` json:"preFilterResult,omitempty" `
PreFilterStatus int ` json:"preFilterStatus,omitempty" `
PreFilterAddPodStatus int ` json:"preFilterAddPodStatus,omitempty" `
PreFilterRemovePodStatus int ` json:"preFilterRemovePodStatus,omitempty" `
FilterStatus int ` json:"filterStatus,omitempty" `
PostFilterStatus int ` json:"postFilterStatus,omitempty" `
PreScoreStatus int ` json:"preScoreStatus,omitempty" `
ReserveStatus int ` json:"reserveStatus,omitempty" `
PreBindPreFlightStatus int ` json:"preBindPreFlightStatus,omitempty" `
PreBindStatus int ` json:"preBindStatus,omitempty" `
BindStatus int ` json:"bindStatus,omitempty" `
PermitStatus int ` json:"permitStatus,omitempty" `
2019-08-19 16:08:14 -04:00
}
2025-06-03 18:59:50 -04:00
func setScoreRes ( inj injectedResult ) ( int64 , * fwk . Status ) {
if fwk . Code ( inj . ScoreStatus ) != fwk . Success {
return 0 , fwk . NewStatus ( fwk . Code ( inj . ScoreStatus ) , "injecting failure." )
2019-08-19 16:08:14 -04:00
}
2019-09-09 01:13:15 -04:00
return inj . ScoreRes , nil
2019-08-19 16:08:14 -04:00
}
2025-07-24 07:48:07 -04:00
func injectNormalizeRes ( inj injectedResult , scores fwk . NodeScoreList ) * fwk . Status {
2025-06-03 18:59:50 -04:00
if fwk . Code ( inj . NormalizeStatus ) != fwk . Success {
return fwk . NewStatus ( fwk . Code ( inj . NormalizeStatus ) , "injecting failure." )
2019-08-19 16:08:14 -04:00
}
for i := range scores {
2019-09-09 01:13:15 -04:00
scores [ i ] . Score = inj . NormalizeRes
2019-08-19 16:08:14 -04:00
}
return nil
}
2019-10-04 10:25:17 -04:00
2025-06-03 18:59:50 -04:00
func collectAndComparePluginMetrics ( t * testing . T , wantExtensionPoint , wantPlugin string , wantStatus fwk . Code ) {
2020-01-15 11:26:35 -05:00
t . Helper ( )
2021-01-29 23:15:22 -05:00
m := metrics . PluginExecutionDuration . WithLabelValues ( wantPlugin , wantExtensionPoint , wantStatus . String ( ) )
2019-10-29 10:54:02 -04:00
2021-01-29 23:15:22 -05:00
count , err := testutil . GetHistogramMetricCount ( m )
if err != nil {
t . Errorf ( "Failed to get %s sampleCount, err: %v" , metrics . PluginExecutionDuration . Name , err )
2019-10-29 10:54:02 -04:00
}
2021-01-29 23:15:22 -05:00
if count == 0 {
2019-10-29 10:54:02 -04:00
t . Error ( "Expect at least 1 sample" )
}
2021-01-29 23:15:22 -05:00
value , err := testutil . GetHistogramMetricValue ( m )
if err != nil {
t . Errorf ( "Failed to get %s value, err: %v" , metrics . PluginExecutionDuration . Name , err )
}
2022-05-23 09:53:00 -04:00
checkLatency ( t , value )
2019-10-29 10:54:02 -04:00
}
2025-06-03 18:59:50 -04:00
func collectAndCompareFrameworkMetrics ( t * testing . T , wantExtensionPoint string , wantStatus fwk . Code ) {
2020-01-15 11:26:35 -05:00
t . Helper ( )
2021-01-29 23:15:22 -05:00
m := metrics . FrameworkExtensionPointDuration . WithLabelValues ( wantExtensionPoint , wantStatus . String ( ) , testProfileName )
2019-10-04 10:25:17 -04:00
2021-01-29 23:15:22 -05:00
count , err := testutil . GetHistogramMetricCount ( m )
if err != nil {
t . Errorf ( "Failed to get %s sampleCount, err: %v" , metrics . FrameworkExtensionPointDuration . Name , err )
2019-10-04 10:25:17 -04:00
}
2021-01-29 23:15:22 -05:00
if count != 1 {
t . Errorf ( "Expect 1 sample, got: %v" , count )
2019-10-04 10:25:17 -04:00
}
2021-01-29 23:15:22 -05:00
value , err := testutil . GetHistogramMetricValue ( m )
if err != nil {
t . Errorf ( "Failed to get %s value, err: %v" , metrics . FrameworkExtensionPointDuration . Name , err )
2019-10-04 10:25:17 -04:00
}
2022-05-23 09:53:00 -04:00
checkLatency ( t , value )
2019-10-04 10:25:17 -04:00
}
2019-10-16 10:15:54 -04:00
func collectAndComparePermitWaitDuration ( t * testing . T , wantRes string ) {
2021-01-29 23:15:22 -05:00
m := metrics . PermitWaitDuration . WithLabelValues ( wantRes )
count , err := testutil . GetHistogramMetricCount ( m )
if err != nil {
t . Errorf ( "Failed to get %s sampleCount, err: %v" , metrics . PermitWaitDuration . Name , err )
}
2019-10-16 10:15:54 -04:00
if wantRes == "" {
2021-01-29 23:15:22 -05:00
if count != 0 {
t . Errorf ( "Expect 0 sample, got: %v" , count )
2019-10-16 10:15:54 -04:00
}
2021-01-29 23:15:22 -05:00
} else {
if count != 1 {
t . Errorf ( "Expect 1 sample, got: %v" , count )
2019-10-16 10:15:54 -04:00
}
2021-01-29 23:15:22 -05:00
value , err := testutil . GetHistogramMetricValue ( m )
if err != nil {
t . Errorf ( "Failed to get %s value, err: %v" , metrics . PermitWaitDuration . Name , err )
2019-10-16 10:15:54 -04:00
}
2022-05-23 09:53:00 -04:00
checkLatency ( t , value )
2019-10-16 10:15:54 -04:00
}
}
2022-10-12 10:11:04 -04:00
func mustNewPodInfo ( t * testing . T , pod * v1 . Pod ) * framework . PodInfo {
podInfo , err := framework . NewPodInfo ( pod )
if err != nil {
t . Fatal ( err )
}
return podInfo
}
2023-11-18 05:21:58 -05:00
// BuildNodeInfos build NodeInfo slice from a v1.Node slice
2025-06-11 05:56:18 -04:00
func BuildNodeInfos ( nodes [ ] * v1 . Node ) [ ] fwk . NodeInfo {
res := make ( [ ] fwk . NodeInfo , len ( nodes ) )
2023-11-18 05:21:58 -05:00
for i := 0 ; i < len ( nodes ) ; i ++ {
res [ i ] = framework . NewNodeInfo ( )
res [ i ] . SetNode ( nodes [ i ] )
}
return res
}