2017-10-24 14:14:29 -04:00
/ *
Copyright 2017 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 .
* /
2018-09-21 19:18:48 -04:00
package queue
2017-10-24 14:14:29 -04:00
import (
2021-03-04 07:30:24 -05:00
"context"
2018-09-14 19:59:54 -04:00
"fmt"
2021-09-18 22:09:06 -04:00
"math"
2017-10-24 14:14:29 -04:00
"reflect"
2019-09-29 22:05:50 -04:00
"strings"
2017-11-28 04:40:35 -05:00
"sync"
2017-10-24 14:14:29 -04:00
"testing"
2019-01-15 23:08:19 -05:00
"time"
2017-10-24 14:14:29 -04:00
2021-03-11 15:31:33 -05:00
"github.com/google/go-cmp/cmp"
2021-06-04 14:04:44 -04:00
"github.com/google/go-cmp/cmp/cmpopts"
2021-03-09 06:42:20 -05:00
v1 "k8s.io/api/core/v1"
2017-10-24 14:14:29 -04:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021-09-18 22:09:06 -04:00
"k8s.io/apimachinery/pkg/runtime"
2018-11-27 19:46:24 -05:00
"k8s.io/apimachinery/pkg/types"
2021-01-29 01:29:10 -05:00
"k8s.io/apimachinery/pkg/util/sets"
2021-06-04 14:04:44 -04:00
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
2019-09-29 22:05:50 -04:00
"k8s.io/component-base/metrics/testutil"
2018-11-27 19:46:24 -05:00
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
2020-10-09 10:41:44 -04:00
"k8s.io/kubernetes/pkg/scheduler/framework"
2020-02-13 11:08:46 -05:00
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
2019-03-20 02:53:33 -04:00
"k8s.io/kubernetes/pkg/scheduler/metrics"
2018-01-03 21:12:18 -05:00
"k8s.io/kubernetes/pkg/scheduler/util"
2021-09-17 05:48:22 -04:00
testingclock "k8s.io/utils/clock/testing"
2021-03-11 15:31:33 -05:00
"k8s.io/utils/pointer"
2017-10-24 14:14:29 -04:00
)
2019-10-07 13:29:53 -04:00
const queueMetricMetadata = `
2021-11-09 09:08:18 -05:00
# HELP scheduler_queue_incoming_pods_total [ STABLE ] Number of pods added to scheduling queues by event and queue type .
2019-10-07 13:29:53 -04:00
# TYPE scheduler_queue_incoming_pods_total counter
`
2021-03-16 18:08:19 -04:00
var (
TestEvent = framework . ClusterEvent { Resource : "test" }
NodeAllEvent = framework . ClusterEvent { Resource : framework . Node , ActionType : framework . All }
EmptyEvent = framework . ClusterEvent { }
)
2019-08-21 16:42:36 -04:00
var lowPriority , midPriority , highPriority = int32 ( 0 ) , int32 ( 100 ) , int32 ( 1000 )
2017-10-24 14:14:29 -04:00
var mediumPriority = ( lowPriority + highPriority ) / 2
2021-02-22 09:00:23 -05:00
var highPriorityPodInfo , highPriNominatedPodInfo , medPriorityPodInfo , unschedulablePodInfo = framework . NewPodInfo ( & v1 . Pod {
2017-10-24 14:14:29 -04:00
ObjectMeta : metav1 . ObjectMeta {
Name : "hpp" ,
Namespace : "ns1" ,
2018-02-12 13:10:20 -05:00
UID : "hppns1" ,
2017-10-24 14:14:29 -04:00
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
2021-02-22 09:00:23 -05:00
} ) ,
framework . NewPodInfo ( & v1 . Pod {
2018-02-08 21:19:31 -05:00
ObjectMeta : metav1 . ObjectMeta {
Name : "hpp" ,
Namespace : "ns1" ,
2018-02-12 13:10:20 -05:00
UID : "hppns1" ,
2018-02-08 21:19:31 -05:00
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
2021-02-22 09:00:23 -05:00
} ) ,
framework . NewPodInfo ( & v1 . Pod {
2017-10-24 14:14:29 -04:00
ObjectMeta : metav1 . ObjectMeta {
Name : "mpp" ,
Namespace : "ns2" ,
2018-02-12 13:10:20 -05:00
UID : "mppns2" ,
2017-10-24 14:14:29 -04:00
Annotations : map [ string ] string {
2018-02-02 14:24:20 -05:00
"annot2" : "val2" ,
2017-10-24 14:14:29 -04:00
} ,
} ,
Spec : v1 . PodSpec {
Priority : & mediumPriority ,
} ,
2018-02-02 14:24:20 -05:00
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
2021-02-22 09:00:23 -05:00
} ) ,
framework . NewPodInfo ( & v1 . Pod {
2017-10-24 14:14:29 -04:00
ObjectMeta : metav1 . ObjectMeta {
Name : "up" ,
Namespace : "ns1" ,
2018-02-12 13:10:20 -05:00
UID : "upns1" ,
2017-10-24 14:14:29 -04:00
Annotations : map [ string ] string {
2018-02-02 14:24:20 -05:00
"annot2" : "val2" ,
2017-10-24 14:14:29 -04:00
} ,
} ,
Spec : v1 . PodSpec {
Priority : & lowPriority ,
} ,
Status : v1 . PodStatus {
Conditions : [ ] v1 . PodCondition {
{
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
} ,
} ,
2018-02-02 14:24:20 -05:00
NominatedNodeName : "node1" ,
2017-10-24 14:14:29 -04:00
} ,
2021-02-22 09:00:23 -05:00
} )
2017-10-24 14:14:29 -04:00
2019-01-17 15:24:18 -05:00
func getUnschedulablePod ( p * PriorityQueue , pod * v1 . Pod ) * v1 . Pod {
2019-02-21 20:46:18 -05:00
pInfo := p . unschedulableQ . get ( pod )
if pInfo != nil {
2019-05-06 21:03:00 -04:00
return pInfo . Pod
2019-02-21 20:46:18 -05:00
}
return nil
2019-01-17 15:24:18 -05:00
}
2017-10-24 14:14:29 -04:00
func TestPriorityQueue_Add ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { medPriorityPodInfo . Pod , unschedulablePodInfo . Pod , highPriorityPodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
if err := q . Add ( medPriorityPodInfo . Pod ) ; err != nil {
2018-12-14 19:31:08 -05:00
t . Errorf ( "add failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
if err := q . Add ( unschedulablePodInfo . Pod ) ; err != nil {
2018-12-14 19:31:08 -05:00
t . Errorf ( "add failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
if err := q . Add ( highPriorityPodInfo . Pod ) ; err != nil {
2018-12-14 19:31:08 -05:00
t . Errorf ( "add failed: %v" , err )
}
2021-06-05 14:30:17 -04:00
expectedNominatedPods := & nominator {
2018-12-18 02:41:53 -05:00
nominatedPodToNode : map [ types . UID ] string {
2021-02-22 09:00:23 -05:00
medPriorityPodInfo . Pod . UID : "node1" ,
unschedulablePodInfo . Pod . UID : "node1" ,
2018-12-18 02:41:53 -05:00
} ,
2021-02-22 09:00:23 -05:00
nominatedPods : map [ string ] [ ] * framework . PodInfo {
"node1" : { medPriorityPodInfo , unschedulablePodInfo } ,
2018-12-18 02:41:53 -05:00
} ,
2018-02-08 21:19:31 -05:00
}
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after adding pods (-want, +got):\n%s" , diff )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != highPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriorityPodInfo . Pod . Name , p . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != medPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , p . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != unschedulablePodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , unschedulablePodInfo . Pod . Name , p . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods [ "node1" ] ) != 2 {
t . Errorf ( "Expected medPriorityPodInfo and unschedulablePodInfo to be still present in nomindatePods: %v" , q . PodNominator . ( * nominator ) . nominatedPods [ "node1" ] )
2018-02-08 21:19:31 -05:00
}
}
2020-02-13 11:08:46 -05:00
func newDefaultQueueSort ( ) framework . LessFunc {
sort := & queuesort . PrioritySort { }
return sort . Less
2020-01-07 22:22:51 -05:00
}
2019-05-06 21:03:00 -04:00
func TestPriorityQueue_AddWithReversePriorityLessFunc ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { medPriorityPodInfo . Pod , highPriorityPodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
if err := q . Add ( medPriorityPodInfo . Pod ) ; err != nil {
2019-05-06 21:03:00 -04:00
t . Errorf ( "add failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
if err := q . Add ( highPriorityPodInfo . Pod ) ; err != nil {
2019-05-06 21:03:00 -04:00
t . Errorf ( "add failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != highPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriorityPodInfo . Pod . Name , p . Pod . Name )
2019-05-06 21:03:00 -04:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != medPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , p . Pod . Name )
2020-01-15 15:26:22 -05:00
}
2019-05-06 21:03:00 -04:00
}
2018-02-08 21:19:31 -05:00
func TestPriorityQueue_AddUnschedulableIfNotPresent ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { highPriNominatedPodInfo . Pod , unschedulablePodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
q . Add ( highPriNominatedPodInfo . Pod )
q . AddUnschedulableIfNotPresent ( newQueuedPodInfoForLookup ( highPriNominatedPodInfo . Pod ) , q . SchedulingCycle ( ) ) // Must not add anything.
q . AddUnschedulableIfNotPresent ( newQueuedPodInfoForLookup ( unschedulablePodInfo . Pod ) , q . SchedulingCycle ( ) )
2021-06-05 14:30:17 -04:00
expectedNominatedPods := & nominator {
2018-12-18 02:41:53 -05:00
nominatedPodToNode : map [ types . UID ] string {
2021-02-22 09:00:23 -05:00
unschedulablePodInfo . Pod . UID : "node1" ,
highPriNominatedPodInfo . Pod . UID : "node1" ,
2018-12-18 02:41:53 -05:00
} ,
2021-02-22 09:00:23 -05:00
nominatedPods : map [ string ] [ ] * framework . PodInfo {
"node1" : { highPriNominatedPodInfo , unschedulablePodInfo } ,
2018-12-18 02:41:53 -05:00
} ,
2018-02-08 21:19:31 -05:00
}
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after adding pods (-want, +got):\n%s" , diff )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != highPriNominatedPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriNominatedPodInfo . Pod . Name , p . Pod . Name )
2018-02-08 21:19:31 -05:00
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods ) != 1 {
2020-05-18 13:29:08 -04:00
t . Errorf ( "Expected nomindatePods to have one element: %v" , q . PodNominator )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
if getUnschedulablePod ( q , unschedulablePodInfo . Pod ) != unschedulablePodInfo . Pod {
t . Errorf ( "Pod %v was not found in the unschedulableQ." , unschedulablePodInfo . Pod . Name )
2018-02-08 21:19:31 -05:00
}
2017-10-24 14:14:29 -04:00
}
2019-07-01 20:29:34 -04:00
// TestPriorityQueue_AddUnschedulableIfNotPresent_Backoff tests the scenarios when
// AddUnschedulableIfNotPresent is called asynchronously.
// Pods in and before current scheduling cycle will be put back to activeQueue
// if we were trying to schedule them when we received move request.
2019-02-15 20:43:08 -05:00
func TestPriorityQueue_AddUnschedulableIfNotPresent_Backoff ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( testingclock . NewFakeClock ( time . Now ( ) ) ) )
2019-01-25 05:39:53 -05:00
totalNum := 10
expectedPods := make ( [ ] v1 . Pod , 0 , totalNum )
for i := 0 ; i < totalNum ; i ++ {
priority := int32 ( i )
p := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "pod%d" , i ) ,
Namespace : fmt . Sprintf ( "ns%d" , i ) ,
UID : types . UID ( fmt . Sprintf ( "upns%d" , i ) ) ,
} ,
Spec : v1 . PodSpec {
Priority : & priority ,
} ,
}
expectedPods = append ( expectedPods , p )
// priority is to make pods ordered in the PriorityQueue
q . Add ( & p )
}
// Pop all pods except for the first one
for i := totalNum - 1 ; i > 0 ; i -- {
p , _ := q . Pop ( )
2019-10-07 19:06:00 -04:00
if ! reflect . DeepEqual ( & expectedPods [ i ] , p . Pod ) {
2019-01-25 05:39:53 -05:00
t . Errorf ( "Unexpected pod. Expected: %v, got: %v" , & expectedPods [ i ] , p )
}
}
// move all pods to active queue when we were trying to schedule them
2021-03-16 18:08:19 -04:00
q . MoveAllToActiveOrBackoffQueue ( TestEvent , nil )
2019-02-15 20:43:08 -05:00
oldCycle := q . SchedulingCycle ( )
firstPod , _ := q . Pop ( )
2019-10-07 19:06:00 -04:00
if ! reflect . DeepEqual ( & expectedPods [ 0 ] , firstPod . Pod ) {
2019-02-15 20:43:08 -05:00
t . Errorf ( "Unexpected pod. Expected: %v, got: %v" , & expectedPods [ 0 ] , firstPod )
}
// mark pods[1] ~ pods[totalNum-1] as unschedulable and add them back
2019-01-25 05:39:53 -05:00
for i := 1 ; i < totalNum ; i ++ {
unschedulablePod := expectedPods [ i ] . DeepCopy ( )
unschedulablePod . Status = v1 . PodStatus {
Conditions : [ ] v1 . PodCondition {
{
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
} ,
} ,
}
2019-02-15 20:43:08 -05:00
2021-02-22 09:00:23 -05:00
if err := q . AddUnschedulableIfNotPresent ( newQueuedPodInfoForLookup ( unschedulablePod ) , oldCycle ) ; err != nil {
2019-07-01 20:29:34 -04:00
t . Errorf ( "Failed to call AddUnschedulableIfNotPresent(%v): %v" , unschedulablePod . Name , err )
}
2019-01-25 05:39:53 -05:00
}
2019-02-15 20:43:08 -05:00
// Since there was a move request at the same cycle as "oldCycle", these pods
// should be in the backoff queue.
2019-01-25 05:39:53 -05:00
for i := 1 ; i < totalNum ; i ++ {
2021-02-22 09:00:23 -05:00
if _ , exists , _ := q . podBackoffQ . Get ( newQueuedPodInfoForLookup ( & expectedPods [ i ] ) ) ; ! exists {
2019-02-15 20:43:08 -05:00
t . Errorf ( "Expected %v to be added to podBackoffQ." , expectedPods [ i ] . Name )
2019-01-25 05:39:53 -05:00
}
}
}
2017-10-24 14:14:29 -04:00
func TestPriorityQueue_Pop ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { medPriorityPodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2017-11-28 04:40:35 -05:00
wg := sync . WaitGroup { }
wg . Add ( 1 )
2017-10-24 14:14:29 -04:00
go func ( ) {
2017-11-28 04:40:35 -05:00
defer wg . Done ( )
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != medPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , p . Pod . Name )
2018-02-08 21:19:31 -05:00
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods [ "node1" ] ) != 1 {
t . Errorf ( "Expected medPriorityPodInfo to be present in nomindatePods: %v" , q . PodNominator . ( * nominator ) . nominatedPods [ "node1" ] )
2017-10-24 14:14:29 -04:00
}
} ( )
2021-02-22 09:00:23 -05:00
q . Add ( medPriorityPodInfo . Pod )
2017-11-28 04:40:35 -05:00
wg . Wait ( )
2017-10-24 14:14:29 -04:00
}
func TestPriorityQueue_Update ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { highPriorityPodInfo . Pod , unschedulablePodInfo . Pod , medPriorityPodInfo . Pod }
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-06-05 14:30:17 -04:00
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs , WithClock ( c ) )
2021-02-22 09:00:23 -05:00
q . Update ( nil , highPriorityPodInfo . Pod )
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( highPriorityPodInfo . Pod ) ) ; ! exists {
t . Errorf ( "Expected %v to be added to activeQ." , highPriorityPodInfo . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods ) != 0 {
2020-05-18 13:29:08 -04:00
t . Errorf ( "Expected nomindatePods to be empty: %v" , q . PodNominator )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
// Update highPriorityPodInfo and add a nominatedNodeName to it.
q . Update ( highPriorityPodInfo . Pod , highPriNominatedPodInfo . Pod )
2017-12-09 18:09:48 -05:00
if q . activeQ . Len ( ) != 1 {
2017-10-24 14:14:29 -04:00
t . Error ( "Expected only one item in activeQ." )
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods ) != 1 {
2020-05-18 13:29:08 -04:00
t . Errorf ( "Expected one item in nomindatePods map: %v" , q . PodNominator )
2018-02-08 21:19:31 -05:00
}
2017-10-24 14:14:29 -04:00
// Updating an unschedulable pod which is not in any of the two queues, should
// add the pod to activeQ.
2021-02-22 09:00:23 -05:00
q . Update ( unschedulablePodInfo . Pod , unschedulablePodInfo . Pod )
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( unschedulablePodInfo . Pod ) ) ; ! exists {
t . Errorf ( "Expected %v to be added to activeQ." , unschedulablePodInfo . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2018-02-08 21:19:31 -05:00
// Updating a pod that is already in activeQ, should not change it.
2021-02-22 09:00:23 -05:00
q . Update ( unschedulablePodInfo . Pod , unschedulablePodInfo . Pod )
2019-02-21 20:46:18 -05:00
if len ( q . unschedulableQ . podInfoMap ) != 0 {
2017-10-24 14:14:29 -04:00
t . Error ( "Expected unschedulableQ to be empty." )
}
2021-02-22 09:00:23 -05:00
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( unschedulablePodInfo . Pod ) ) ; ! exists {
t . Errorf ( "Expected: %v to be added to activeQ." , unschedulablePodInfo . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != highPriNominatedPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriorityPodInfo . Pod . Name , p . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-02-06 04:08:16 -05:00
// Updating a pod that is in backoff queue and it is still backing off
// pod will not be moved to active queue, and it will be updated in backoff queue
podInfo := q . newQueuedPodInfo ( medPriorityPodInfo . Pod )
if err := q . podBackoffQ . Add ( podInfo ) ; err != nil {
t . Errorf ( "adding pod to backoff queue error: %v" , err )
}
q . Update ( podInfo . Pod , podInfo . Pod )
rawPodInfo , err := q . podBackoffQ . Pop ( )
podGotFromBackoffQ := rawPodInfo . ( * framework . QueuedPodInfo ) . Pod
if err != nil || podGotFromBackoffQ != medPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , podGotFromBackoffQ . Name )
}
// updating a pod which is in unschedulable queue, and it is still backing off,
// we will move it to backoff queue
2021-02-22 09:00:23 -05:00
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( medPriorityPodInfo . Pod ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
if len ( q . unschedulableQ . podInfoMap ) != 1 {
t . Error ( "Expected unschedulableQ to be 1." )
}
2021-02-22 09:00:23 -05:00
updatedPod := medPriorityPodInfo . Pod . DeepCopy ( )
2020-02-13 19:31:07 -05:00
updatedPod . ClusterName = "test"
2021-02-22 09:00:23 -05:00
q . Update ( medPriorityPodInfo . Pod , updatedPod )
2021-02-06 04:08:16 -05:00
rawPodInfo , err = q . podBackoffQ . Pop ( )
podGotFromBackoffQ = rawPodInfo . ( * framework . QueuedPodInfo ) . Pod
if err != nil || podGotFromBackoffQ != updatedPod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , updatedPod . Name , podGotFromBackoffQ . Name )
}
// updating a pod which is in unschedulable queue, and it is not backing off,
// we will move it to active queue
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( medPriorityPodInfo . Pod ) , q . SchedulingCycle ( ) )
if len ( q . unschedulableQ . podInfoMap ) != 1 {
t . Error ( "Expected unschedulableQ to be 1." )
}
updatedPod = medPriorityPodInfo . Pod . DeepCopy ( )
updatedPod . ClusterName = "test1"
// Move clock by podInitialBackoffDuration, so that pods in the unschedulableQ would pass the backing off,
// and the pods will be moved into activeQ.
c . Step ( q . podInitialBackoffDuration )
q . Update ( medPriorityPodInfo . Pod , updatedPod )
2020-02-13 19:31:07 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != updatedPod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , updatedPod . Name , p . Pod . Name )
}
2017-10-24 14:14:29 -04:00
}
func TestPriorityQueue_Delete ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { highPriorityPodInfo . Pod , unschedulablePodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
q . Update ( highPriorityPodInfo . Pod , highPriNominatedPodInfo . Pod )
q . Add ( unschedulablePodInfo . Pod )
if err := q . Delete ( highPriNominatedPodInfo . Pod ) ; err != nil {
2018-12-14 19:31:08 -05:00
t . Errorf ( "delete failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( unschedulablePodInfo . Pod ) ) ; ! exists {
t . Errorf ( "Expected %v to be in activeQ." , unschedulablePodInfo . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-02-22 09:00:23 -05:00
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( highPriNominatedPodInfo . Pod ) ) ; exists {
t . Errorf ( "Didn't expect %v to be in activeQ." , highPriorityPodInfo . Pod . Name )
2017-10-24 14:14:29 -04:00
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods ) != 1 {
t . Errorf ( "Expected nomindatePods to have only 'unschedulablePodInfo': %v" , q . PodNominator . ( * nominator ) . nominatedPods )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
if err := q . Delete ( unschedulablePodInfo . Pod ) ; err != nil {
2018-12-14 19:31:08 -05:00
t . Errorf ( "delete failed: %v" , err )
}
2021-06-05 14:30:17 -04:00
if len ( q . PodNominator . ( * nominator ) . nominatedPods ) != 0 {
2020-05-18 13:29:08 -04:00
t . Errorf ( "Expected nomindatePods to be empty: %v" , q . PodNominator )
2018-02-08 21:19:31 -05:00
}
2017-10-24 14:14:29 -04:00
}
2021-02-19 22:18:33 -05:00
func BenchmarkMoveAllToActiveOrBackoffQueue ( b * testing . B ) {
tests := [ ] struct {
name string
2021-03-16 18:08:19 -04:00
moveEvent framework . ClusterEvent
2021-02-19 22:18:33 -05:00
} {
{
name : "baseline" ,
moveEvent : UnschedulableTimeout ,
} ,
{
name : "worst" ,
moveEvent : NodeAdd ,
} ,
{
name : "random" ,
// leave "moveEvent" unspecified
} ,
}
podTemplates := [ ] * v1 . Pod {
highPriorityPodInfo . Pod , highPriNominatedPodInfo . Pod ,
medPriorityPodInfo . Pod , unschedulablePodInfo . Pod ,
}
2021-03-16 18:08:19 -04:00
events := [ ] framework . ClusterEvent {
NodeAdd ,
NodeTaintChange ,
NodeAllocatableChange ,
NodeConditionChange ,
NodeLabelChange ,
PvcAdd ,
PvcUpdate ,
PvAdd ,
PvUpdate ,
StorageClassAdd ,
2021-03-09 06:42:20 -05:00
StorageClassUpdate ,
2021-03-16 18:08:19 -04:00
CSINodeAdd ,
CSINodeUpdate ,
2021-03-09 06:42:20 -05:00
CSIDriverAdd ,
CSIDriverUpdate ,
CSIStorageCapacityAdd ,
CSIStorageCapacityUpdate ,
2021-03-16 18:08:19 -04:00
}
2021-02-19 22:18:33 -05:00
pluginNum := 20
var plugins [ ] string
// Mimic that we have 20 plugins loaded in runtime.
for i := 0 ; i < pluginNum ; i ++ {
plugins = append ( plugins , fmt . Sprintf ( "fake-plugin-%v" , i ) )
}
for _ , tt := range tests {
for _ , podsInUnschedulableQ := range [ ] int { 1000 , 5000 } {
b . Run ( fmt . Sprintf ( "%v-%v" , tt . name , podsInUnschedulableQ ) , func ( b * testing . B ) {
for i := 0 ; i < b . N ; i ++ {
b . StopTimer ( )
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-02-19 22:18:33 -05:00
m := make ( map [ framework . ClusterEvent ] sets . String )
// - All plugins registered for events[0], which is NodeAdd.
// - 1/2 of plugins registered for events[1]
// - 1/3 of plugins registered for events[2]
// - ...
for j := 0 ; j < len ( events ) ; j ++ {
2021-03-16 18:08:19 -04:00
m [ events [ j ] ] = sets . NewString ( )
2021-02-19 22:18:33 -05:00
for k := 0 ; k < len ( plugins ) ; k ++ {
if ( k + 1 ) % ( j + 1 ) == 0 {
2021-03-16 18:08:19 -04:00
m [ events [ j ] ] . Insert ( plugins [ k ] )
2021-02-19 22:18:33 -05:00
}
}
}
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) , WithClusterEventMap ( m ) )
2021-02-19 22:18:33 -05:00
// Init pods in unschedulableQ.
for j := 0 ; j < podsInUnschedulableQ ; j ++ {
p := podTemplates [ j % len ( podTemplates ) ] . DeepCopy ( )
p . Name , p . UID = fmt . Sprintf ( "%v-%v" , p . Name , j ) , types . UID ( fmt . Sprintf ( "%v-%v" , p . UID , j ) )
var podInfo * framework . QueuedPodInfo
// The ultimate goal of composing each PodInfo is to cover the path that intersects
// (unschedulable) plugin names with the plugins that register the moveEvent,
// here the rational is:
// - in baseline case, don't inject unschedulable plugin names, so podMatchesEvent()
// never gets executed.
// - in worst case, make both ends (of the intersection) a big number,i.e.,
// M intersected with N instead of M with 1 (or 1 with N)
// - in random case, each pod failed by a random plugin, and also the moveEvent
// is randomized.
if tt . name == "baseline" {
podInfo = q . newQueuedPodInfo ( p )
} else if tt . name == "worst" {
// Each pod failed by all plugins.
podInfo = q . newQueuedPodInfo ( p , plugins ... )
} else {
// Random case.
podInfo = q . newQueuedPodInfo ( p , plugins [ j % len ( plugins ) ] )
}
q . AddUnschedulableIfNotPresent ( podInfo , q . SchedulingCycle ( ) )
}
b . StartTimer ( )
2021-03-16 18:08:19 -04:00
if tt . moveEvent . Resource != "" {
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( tt . moveEvent , nil )
2021-02-19 22:18:33 -05:00
} else {
// Random case.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( events [ i % len ( events ) ] , nil )
2021-02-19 22:18:33 -05:00
}
}
} )
}
}
}
2020-02-13 19:31:07 -05:00
func TestPriorityQueue_MoveAllToActiveOrBackoffQueue ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-01-29 01:29:10 -05:00
m := map [ framework . ClusterEvent ] sets . String {
{ Resource : framework . Node , ActionType : framework . Add } : sets . NewString ( "fooPlugin" ) ,
}
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) , WithClusterEventMap ( m ) )
2021-02-22 09:00:23 -05:00
q . Add ( medPriorityPodInfo . Pod )
2021-01-29 01:29:10 -05:00
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( unschedulablePodInfo . Pod , "fooPlugin" ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( highPriorityPodInfo . Pod , "fooPlugin" ) , q . SchedulingCycle ( ) )
// Construct a Pod, but don't associate its scheduler failure to any plugin
hpp1 := highPriorityPodInfo . Pod . DeepCopy ( )
hpp1 . Name = "hpp1"
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( hpp1 ) , q . SchedulingCycle ( ) )
// Construct another Pod, and associate its scheduler failure to plugin "barPlugin".
hpp2 := highPriorityPodInfo . Pod . DeepCopy ( )
hpp2 . Name = "hpp2"
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( hpp2 , "barPlugin" ) , q . SchedulingCycle ( ) )
2020-09-02 01:28:45 -04:00
// Pods is still backing off, move the pod into backoffQ.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( NodeAdd , nil )
2020-02-13 19:31:07 -05:00
if q . activeQ . Len ( ) != 1 {
2020-09-02 01:28:45 -04:00
t . Errorf ( "Expected 1 item to be in activeQ, but got: %v" , q . activeQ . Len ( ) )
2020-02-13 19:31:07 -05:00
}
2021-01-29 01:29:10 -05:00
// hpp2 won't be moved.
if q . podBackoffQ . Len ( ) != 3 {
t . Fatalf ( "Expected 3 items to be in podBackoffQ, but got: %v" , q . podBackoffQ . Len ( ) )
2020-09-02 01:28:45 -04:00
}
// pop out the pods in the backoffQ.
2021-01-29 01:29:10 -05:00
for q . podBackoffQ . Len ( ) != 0 {
q . podBackoffQ . Pop ( )
}
2020-09-02 01:28:45 -04:00
q . schedulingCycle ++
2021-01-29 01:29:10 -05:00
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( unschedulablePodInfo . Pod , "fooPlugin" ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( highPriorityPodInfo . Pod , "fooPlugin" ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( hpp1 ) , q . SchedulingCycle ( ) )
for _ , pod := range [ ] * v1 . Pod { unschedulablePodInfo . Pod , highPriorityPodInfo . Pod , hpp1 , hpp2 } {
if q . unschedulableQ . get ( pod ) == nil {
t . Errorf ( "Expected %v in the unschedulableQ" , pod . Name )
}
2020-09-02 01:28:45 -04:00
}
// Move clock by podInitialBackoffDuration, so that pods in the unschedulableQ would pass the backing off,
// and the pods will be moved into activeQ.
c . Step ( q . podInitialBackoffDuration )
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( NodeAdd , nil )
2021-01-29 01:29:10 -05:00
// hpp2 won't be moved regardless of its backoff timer.
if q . activeQ . Len ( ) != 4 {
t . Errorf ( "Expected 4 items to be in activeQ, but got: %v" , q . activeQ . Len ( ) )
2017-10-24 14:14:29 -04:00
}
2020-09-02 01:28:45 -04:00
if q . podBackoffQ . Len ( ) != 0 {
t . Errorf ( "Expected 0 item to be in podBackoffQ, but got: %v" , q . podBackoffQ . Len ( ) )
}
2017-10-24 14:14:29 -04:00
}
// TestPriorityQueue_AssignedPodAdded tests AssignedPodAdded. It checks that
// when a pod with pod affinity is in unschedulableQ and another pod with a
// matching label is added, the unschedulable pod is moved to activeQ.
func TestPriorityQueue_AssignedPodAdded ( t * testing . T ) {
2021-02-22 09:00:23 -05:00
affinityPod := unschedulablePodInfo . Pod . DeepCopy ( )
2017-10-24 14:14:29 -04:00
affinityPod . Name = "afp"
affinityPod . Spec = v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
Priority : & mediumPriority ,
}
labelPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "lbp" ,
Namespace : affinityPod . Namespace ,
Labels : map [ string ] string { "service" : "securityscan" } ,
} ,
Spec : v1 . PodSpec { NodeName : "machine1" } ,
}
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-03-16 18:08:19 -04:00
m := map [ framework . ClusterEvent ] sets . String { AssignedPodAdd : sets . NewString ( "fakePlugin" ) }
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) , WithClusterEventMap ( m ) )
2021-02-22 09:00:23 -05:00
q . Add ( medPriorityPodInfo . Pod )
2017-10-24 14:14:29 -04:00
// Add a couple of pods to the unschedulableQ.
2021-01-29 01:29:10 -05:00
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( unschedulablePodInfo . Pod , "fakePlugin" ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( affinityPod , "fakePlugin" ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
// Move clock to make the unschedulable pods complete backoff.
c . Step ( DefaultPodInitialBackoffDuration + time . Second )
2017-10-24 14:14:29 -04:00
// Simulate addition of an assigned pod. The pod has matching labels for
// affinityPod. So, affinityPod should go to activeQ.
q . AssignedPodAdded ( & labelPod )
2019-01-17 15:24:18 -05:00
if getUnschedulablePod ( q , affinityPod ) != nil {
2017-10-24 14:14:29 -04:00
t . Error ( "affinityPod is still in the unschedulableQ." )
}
2021-02-22 09:00:23 -05:00
if _ , exists , _ := q . activeQ . Get ( newQueuedPodInfoForLookup ( affinityPod ) ) ; ! exists {
2017-10-24 14:14:29 -04:00
t . Error ( "affinityPod is not moved to activeQ." )
}
// Check that the other pod is still in the unschedulableQ.
2021-02-22 09:00:23 -05:00
if getUnschedulablePod ( q , unschedulablePodInfo . Pod ) == nil {
t . Error ( "unschedulablePodInfo is not in the unschedulableQ." )
2017-10-24 14:14:29 -04:00
}
}
2018-12-18 02:41:53 -05:00
func TestPriorityQueue_NominatedPodsForNode ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { medPriorityPodInfo . Pod , unschedulablePodInfo . Pod , highPriorityPodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
q . Add ( medPriorityPodInfo . Pod )
q . Add ( unschedulablePodInfo . Pod )
q . Add ( highPriorityPodInfo . Pod )
if p , err := q . Pop ( ) ; err != nil || p . Pod != highPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriorityPodInfo . Pod . Name , p . Pod . Name )
2018-02-08 21:19:31 -05:00
}
2021-02-22 09:00:23 -05:00
expectedList := [ ] * framework . PodInfo { medPriorityPodInfo , unschedulablePodInfo }
2021-07-08 23:56:43 -04:00
podInfos := q . NominatedPodsForNode ( "node1" )
if diff := cmp . Diff ( expectedList , podInfos ) ; diff != "" {
t . Errorf ( "Unexpected list of nominated Pods for node: (-want, +got):\n%s" , diff )
2018-02-08 21:19:31 -05:00
}
2021-07-08 23:56:43 -04:00
podInfos [ 0 ] . Pod . Name = "not mpp"
if diff := cmp . Diff ( podInfos , q . NominatedPodsForNode ( "node1" ) ) ; diff == "" {
t . Error ( "Expected list of nominated Pods for node2 is different from podInfos" )
}
if len ( q . NominatedPodsForNode ( "node2" ) ) != 0 {
2018-02-08 21:19:31 -05:00
t . Error ( "Expected list of nominated Pods for node2 to be empty." )
}
}
2021-06-04 14:04:44 -04:00
func TestPriorityQueue_NominatedPodDeleted ( t * testing . T ) {
tests := [ ] struct {
name string
podInfo * framework . PodInfo
deletePod bool
want bool
} {
{
name : "alive pod gets added into PodNominator" ,
podInfo : medPriorityPodInfo ,
want : true ,
} ,
{
name : "deleted pod shouldn't be added into PodNominator" ,
podInfo : highPriNominatedPodInfo ,
deletePod : true ,
want : false ,
} ,
{
name : "pod without .status.nominatedPodName specified shouldn't be added into PodNominator" ,
podInfo : highPriorityPodInfo ,
want : false ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
cs := fake . NewSimpleClientset ( tt . podInfo . Pod )
informerFactory := informers . NewSharedInformerFactory ( cs , 0 )
podLister := informerFactory . Core ( ) . V1 ( ) . Pods ( ) . Lister ( )
// Build a PriorityQueue.
2021-06-05 14:30:17 -04:00
q := NewPriorityQueue ( newDefaultQueueSort ( ) , informerFactory , WithPodNominator ( NewPodNominator ( podLister ) ) )
2021-06-04 14:04:44 -04:00
ctx := context . Background ( )
informerFactory . Start ( ctx . Done ( ) )
informerFactory . WaitForCacheSync ( ctx . Done ( ) )
if tt . deletePod {
// Simulate that the test pod gets deleted physically.
informerFactory . Core ( ) . V1 ( ) . Pods ( ) . Informer ( ) . GetStore ( ) . Delete ( tt . podInfo . Pod )
}
q . AddNominatedPod ( tt . podInfo , tt . podInfo . Pod . Status . NominatedNodeName )
if got := len ( q . NominatedPodsForNode ( tt . podInfo . Pod . Status . NominatedNodeName ) ) == 1 ; got != tt . want {
t . Errorf ( "Want %v, but got %v" , tt . want , got )
}
} )
}
}
2018-12-20 20:28:23 -05:00
func TestPriorityQueue_PendingPods ( t * testing . T ) {
2019-02-11 19:38:26 -05:00
makeSet := func ( pods [ ] * v1 . Pod ) map [ * v1 . Pod ] struct { } {
pendingSet := map [ * v1 . Pod ] struct { } { }
for _ , p := range pods {
pendingSet [ p ] = struct { } { }
}
return pendingSet
}
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) )
2021-02-22 09:00:23 -05:00
q . Add ( medPriorityPodInfo . Pod )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( unschedulablePodInfo . Pod ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( highPriorityPodInfo . Pod ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
2021-02-22 09:00:23 -05:00
expectedSet := makeSet ( [ ] * v1 . Pod { medPriorityPodInfo . Pod , unschedulablePodInfo . Pod , highPriorityPodInfo . Pod } )
2019-02-11 19:38:26 -05:00
if ! reflect . DeepEqual ( expectedSet , makeSet ( q . PendingPods ( ) ) ) {
t . Error ( "Unexpected list of pending Pods." )
2018-12-20 20:28:23 -05:00
}
// Move all to active queue. We should still see the same set of pods.
2021-03-16 18:08:19 -04:00
q . MoveAllToActiveOrBackoffQueue ( TestEvent , nil )
2019-02-11 19:38:26 -05:00
if ! reflect . DeepEqual ( expectedSet , makeSet ( q . PendingPods ( ) ) ) {
t . Error ( "Unexpected list of pending Pods..." )
2018-12-20 20:28:23 -05:00
}
}
2018-12-18 02:41:53 -05:00
func TestPriorityQueue_UpdateNominatedPodForNode ( t * testing . T ) {
2021-06-05 14:30:17 -04:00
objs := [ ] runtime . Object { medPriorityPodInfo . Pod , unschedulablePodInfo . Pod , highPriorityPodInfo . Pod }
q := NewTestQueueWithObjects ( context . Background ( ) , newDefaultQueueSort ( ) , objs )
2021-02-22 09:00:23 -05:00
if err := q . Add ( medPriorityPodInfo . Pod ) ; err != nil {
2018-12-18 02:41:53 -05:00
t . Errorf ( "add failed: %v" , err )
}
2021-02-22 09:00:23 -05:00
// Update unschedulablePodInfo on a different node than specified in the pod.
q . AddNominatedPod ( framework . NewPodInfo ( unschedulablePodInfo . Pod ) , "node5" )
2018-12-18 02:41:53 -05:00
// Update nominated node name of a pod on a node that is not specified in the pod object.
2021-02-22 09:00:23 -05:00
q . AddNominatedPod ( framework . NewPodInfo ( highPriorityPodInfo . Pod ) , "node2" )
2021-06-05 14:30:17 -04:00
expectedNominatedPods := & nominator {
2018-12-18 02:41:53 -05:00
nominatedPodToNode : map [ types . UID ] string {
2021-02-22 09:00:23 -05:00
medPriorityPodInfo . Pod . UID : "node1" ,
highPriorityPodInfo . Pod . UID : "node2" ,
unschedulablePodInfo . Pod . UID : "node5" ,
2018-12-18 02:41:53 -05:00
} ,
2021-02-22 09:00:23 -05:00
nominatedPods : map [ string ] [ ] * framework . PodInfo {
"node1" : { medPriorityPodInfo } ,
"node2" : { highPriorityPodInfo } ,
"node5" : { unschedulablePodInfo } ,
2018-12-18 02:41:53 -05:00
} ,
}
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after adding pods (-want, +got):\n%s" , diff )
2018-12-18 02:41:53 -05:00
}
2021-02-22 09:00:23 -05:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != medPriorityPodInfo . Pod {
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , p . Pod . Name )
2018-12-18 02:41:53 -05:00
}
// List of nominated pods shouldn't change after popping them from the queue.
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after popping pods (-want, +got):\n%s" , diff )
2018-12-18 02:41:53 -05:00
}
// Update one of the nominated pods that doesn't have nominatedNodeName in the
// pod object. It should be updated correctly.
2021-02-22 09:00:23 -05:00
q . AddNominatedPod ( highPriorityPodInfo , "node4" )
2021-06-05 14:30:17 -04:00
expectedNominatedPods = & nominator {
2018-12-18 02:41:53 -05:00
nominatedPodToNode : map [ types . UID ] string {
2021-02-22 09:00:23 -05:00
medPriorityPodInfo . Pod . UID : "node1" ,
highPriorityPodInfo . Pod . UID : "node4" ,
unschedulablePodInfo . Pod . UID : "node5" ,
2018-12-18 02:41:53 -05:00
} ,
2021-02-22 09:00:23 -05:00
nominatedPods : map [ string ] [ ] * framework . PodInfo {
"node1" : { medPriorityPodInfo } ,
"node4" : { highPriorityPodInfo } ,
"node5" : { unschedulablePodInfo } ,
2018-12-18 02:41:53 -05:00
} ,
}
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after updating pods (-want, +got):\n%s" , diff )
2018-12-18 02:41:53 -05:00
}
// Delete a nominated pod that doesn't have nominatedNodeName in the pod
// object. It should be deleted.
2021-02-22 09:00:23 -05:00
q . DeleteNominatedPodIfExists ( highPriorityPodInfo . Pod )
2021-06-05 14:30:17 -04:00
expectedNominatedPods = & nominator {
2018-12-18 02:41:53 -05:00
nominatedPodToNode : map [ types . UID ] string {
2021-02-22 09:00:23 -05:00
medPriorityPodInfo . Pod . UID : "node1" ,
unschedulablePodInfo . Pod . UID : "node5" ,
2018-12-18 02:41:53 -05:00
} ,
2021-02-22 09:00:23 -05:00
nominatedPods : map [ string ] [ ] * framework . PodInfo {
"node1" : { medPriorityPodInfo } ,
"node5" : { unschedulablePodInfo } ,
2018-12-18 02:41:53 -05:00
} ,
}
2021-06-05 14:30:17 -04:00
if diff := cmp . Diff ( q . PodNominator , expectedNominatedPods , cmp . AllowUnexported ( nominator { } ) , cmpopts . IgnoreFields ( nominator { } , "podLister" , "RWMutex" ) ) ; diff != "" {
2021-06-04 14:04:44 -04:00
t . Errorf ( "Unexpected diff after deleting pods (-want, +got):\n%s" , diff )
2018-12-18 02:41:53 -05:00
}
}
2019-08-11 20:26:32 -04:00
func TestPriorityQueue_NewWithOptions ( t * testing . T ) {
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) ,
2020-02-13 11:08:46 -05:00
newDefaultQueueSort ( ) ,
2019-08-11 20:26:32 -04:00
WithPodInitialBackoffDuration ( 2 * time . Second ) ,
WithPodMaxBackoffDuration ( 20 * time . Second ) ,
)
2020-02-13 19:31:07 -05:00
if q . podInitialBackoffDuration != 2 * time . Second {
t . Errorf ( "Unexpected pod backoff initial duration. Expected: %v, got: %v" , 2 * time . Second , q . podInitialBackoffDuration )
2019-08-11 20:26:32 -04:00
}
2020-02-13 19:31:07 -05:00
if q . podMaxBackoffDuration != 20 * time . Second {
t . Errorf ( "Unexpected pod backoff max duration. Expected: %v, got: %v" , 2 * time . Second , q . podMaxBackoffDuration )
2019-08-11 20:26:32 -04:00
}
}
2017-10-24 14:14:29 -04:00
func TestUnschedulablePodsMap ( t * testing . T ) {
var pods = [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "p0" ,
Namespace : "ns1" ,
Annotations : map [ string ] string {
2018-02-02 14:24:20 -05:00
"annot1" : "val1" ,
2017-10-24 14:14:29 -04:00
} ,
} ,
2018-02-02 14:24:20 -05:00
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
2017-10-24 14:14:29 -04:00
} ,
{
ObjectMeta : metav1 . ObjectMeta {
Name : "p1" ,
Namespace : "ns1" ,
Annotations : map [ string ] string {
"annot" : "val" ,
} ,
} ,
} ,
{
ObjectMeta : metav1 . ObjectMeta {
Name : "p2" ,
Namespace : "ns2" ,
Annotations : map [ string ] string {
2018-02-02 14:24:20 -05:00
"annot2" : "val2" , "annot3" : "val3" ,
2017-10-24 14:14:29 -04:00
} ,
} ,
2018-02-02 14:24:20 -05:00
Status : v1 . PodStatus {
NominatedNodeName : "node3" ,
} ,
2017-10-24 14:14:29 -04:00
} ,
{
ObjectMeta : metav1 . ObjectMeta {
Name : "p3" ,
Namespace : "ns4" ,
2018-02-02 14:24:20 -05:00
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
2017-10-24 14:14:29 -04:00
} ,
} ,
}
var updatedPods = make ( [ ] * v1 . Pod , len ( pods ) )
updatedPods [ 0 ] = pods [ 0 ] . DeepCopy ( )
updatedPods [ 1 ] = pods [ 1 ] . DeepCopy ( )
updatedPods [ 3 ] = pods [ 3 ] . DeepCopy ( )
tests := [ ] struct {
2018-06-01 10:16:50 -04:00
name string
2018-02-08 21:19:31 -05:00
podsToAdd [ ] * v1 . Pod
2020-04-20 20:36:26 -04:00
expectedMapAfterAdd map [ string ] * framework . QueuedPodInfo
2018-02-08 21:19:31 -05:00
podsToUpdate [ ] * v1 . Pod
2020-04-20 20:36:26 -04:00
expectedMapAfterUpdate map [ string ] * framework . QueuedPodInfo
2018-02-08 21:19:31 -05:00
podsToDelete [ ] * v1 . Pod
2020-04-20 20:36:26 -04:00
expectedMapAfterDelete map [ string ] * framework . QueuedPodInfo
2017-10-24 14:14:29 -04:00
} {
{
2018-06-01 10:16:50 -04:00
name : "create, update, delete subset of pods" ,
2017-10-24 14:14:29 -04:00
podsToAdd : [ ] * v1 . Pod { pods [ 0 ] , pods [ 1 ] , pods [ 2 ] , pods [ 3 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterAdd : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 0 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 0 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 1 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 1 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 2 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 2 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 3 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 3 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
podsToUpdate : [ ] * v1 . Pod { updatedPods [ 0 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterUpdate : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 0 ] ) : { PodInfo : framework . NewPodInfo ( updatedPods [ 0 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 1 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 1 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 2 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 2 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 3 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 3 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
podsToDelete : [ ] * v1 . Pod { pods [ 0 ] , pods [ 1 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterDelete : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 2 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 2 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 3 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 3 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
} ,
{
2018-06-01 10:16:50 -04:00
name : "create, update, delete all" ,
2017-10-24 14:14:29 -04:00
podsToAdd : [ ] * v1 . Pod { pods [ 0 ] , pods [ 3 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterAdd : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 0 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 0 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 3 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 3 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
podsToUpdate : [ ] * v1 . Pod { updatedPods [ 3 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterUpdate : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 0 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 0 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 3 ] ) : { PodInfo : framework . NewPodInfo ( updatedPods [ 3 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
2018-02-08 21:19:31 -05:00
podsToDelete : [ ] * v1 . Pod { pods [ 0 ] , pods [ 3 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterDelete : map [ string ] * framework . QueuedPodInfo { } ,
2017-10-24 14:14:29 -04:00
} ,
{
2018-06-01 10:16:50 -04:00
name : "delete non-existing and existing pods" ,
2017-10-24 14:14:29 -04:00
podsToAdd : [ ] * v1 . Pod { pods [ 1 ] , pods [ 2 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterAdd : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 1 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 1 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 2 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 2 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
podsToUpdate : [ ] * v1 . Pod { updatedPods [ 1 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterUpdate : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 1 ] ) : { PodInfo : framework . NewPodInfo ( updatedPods [ 1 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
util . GetPodFullName ( pods [ 2 ] ) : { PodInfo : framework . NewPodInfo ( pods [ 2 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
podsToDelete : [ ] * v1 . Pod { pods [ 2 ] , pods [ 3 ] } ,
2020-04-20 20:36:26 -04:00
expectedMapAfterDelete : map [ string ] * framework . QueuedPodInfo {
2021-01-29 01:29:10 -05:00
util . GetPodFullName ( pods [ 1 ] ) : { PodInfo : framework . NewPodInfo ( updatedPods [ 1 ] ) , UnschedulablePlugins : sets . NewString ( ) } ,
2017-10-24 14:14:29 -04:00
} ,
} ,
}
2018-06-01 10:16:50 -04:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2019-03-19 02:43:43 -04:00
upm := newUnschedulablePodsMap ( nil )
2018-06-01 10:16:50 -04:00
for _ , p := range test . podsToAdd {
2021-02-22 09:00:23 -05:00
upm . addOrUpdate ( newQueuedPodInfoForLookup ( p ) )
2017-10-24 14:14:29 -04:00
}
2019-02-21 20:46:18 -05:00
if ! reflect . DeepEqual ( upm . podInfoMap , test . expectedMapAfterAdd ) {
2018-06-01 10:16:50 -04:00
t . Errorf ( "Unexpected map after adding pods. Expected: %v, got: %v" ,
2019-02-21 20:46:18 -05:00
test . expectedMapAfterAdd , upm . podInfoMap )
2017-10-24 14:14:29 -04:00
}
2018-06-01 10:16:50 -04:00
if len ( test . podsToUpdate ) > 0 {
for _ , p := range test . podsToUpdate {
2021-02-22 09:00:23 -05:00
upm . addOrUpdate ( newQueuedPodInfoForLookup ( p ) )
2018-06-01 10:16:50 -04:00
}
2019-02-21 20:46:18 -05:00
if ! reflect . DeepEqual ( upm . podInfoMap , test . expectedMapAfterUpdate ) {
2018-06-01 10:16:50 -04:00
t . Errorf ( "Unexpected map after updating pods. Expected: %v, got: %v" ,
2019-02-21 20:46:18 -05:00
test . expectedMapAfterUpdate , upm . podInfoMap )
2018-06-01 10:16:50 -04:00
}
}
for _ , p := range test . podsToDelete {
upm . delete ( p )
}
2019-02-21 20:46:18 -05:00
if ! reflect . DeepEqual ( upm . podInfoMap , test . expectedMapAfterDelete ) {
2018-06-01 10:16:50 -04:00
t . Errorf ( "Unexpected map after deleting pods. Expected: %v, got: %v" ,
2019-02-21 20:46:18 -05:00
test . expectedMapAfterDelete , upm . podInfoMap )
2018-06-01 10:16:50 -04:00
}
upm . clear ( )
2019-02-21 20:46:18 -05:00
if len ( upm . podInfoMap ) != 0 {
t . Errorf ( "Expected the map to be empty, but has %v elements." , len ( upm . podInfoMap ) )
2018-06-01 10:16:50 -04:00
}
} )
2017-10-24 14:14:29 -04:00
}
}
2018-09-14 19:59:54 -04:00
func TestSchedulingQueue_Close ( t * testing . T ) {
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) )
2020-06-07 09:52:16 -04:00
wantErr := fmt . Errorf ( queueClosed )
wg := sync . WaitGroup { }
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
pod , err := q . Pop ( )
if err . Error ( ) != wantErr . Error ( ) {
t . Errorf ( "Expected err %q from Pop() if queue is closed, but got %q" , wantErr . Error ( ) , err . Error ( ) )
}
if pod != nil {
t . Errorf ( "Expected pod nil from Pop() if queue is closed, but got: %v" , pod )
}
} ( )
q . Close ( )
wg . Wait ( )
2018-09-14 19:59:54 -04:00
}
2018-11-27 19:46:24 -05:00
// TestRecentlyTriedPodsGoBack tests that pods which are recently tried and are
// unschedulable go behind other pods with the same priority. This behavior
// ensures that an unschedulable pod does not block head of the queue when there
// are frequent events that move pods to the active queue.
func TestRecentlyTriedPodsGoBack ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) )
2018-11-27 19:46:24 -05:00
// Add a few pods to priority queue.
for i := 0 ; i < 5 ; i ++ {
p := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "test-pod-%v" , i ) ,
Namespace : "ns1" ,
UID : types . UID ( fmt . Sprintf ( "tp00%v" , i ) ) ,
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
q . Add ( & p )
}
2020-05-05 03:11:04 -04:00
c . Step ( time . Microsecond )
2018-11-27 19:46:24 -05:00
// Simulate a pod being popped by the scheduler, determined unschedulable, and
// then moved back to the active queue.
p1 , err := q . Pop ( )
if err != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err )
}
// Update pod condition to unschedulable.
2021-02-22 09:00:23 -05:00
podutil . UpdatePodCondition ( & p1 . PodInfo . Pod . Status , & v1 . PodCondition {
2018-12-29 09:24:51 -05:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
LastProbeTime : metav1 . Now ( ) ,
2018-11-27 19:46:24 -05:00
} )
// Put in the unschedulable queue.
2019-01-25 05:39:53 -05:00
q . AddUnschedulableIfNotPresent ( p1 , q . SchedulingCycle ( ) )
2020-05-05 03:11:04 -04:00
c . Step ( DefaultPodInitialBackoffDuration )
2018-11-27 19:46:24 -05:00
// Move all unschedulable pods to the active queue.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( UnschedulableTimeout , nil )
2018-11-27 19:46:24 -05:00
// Simulation is over. Now let's pop all pods. The pod popped first should be
// the last one we pop here.
for i := 0 ; i < 5 ; i ++ {
p , err := q . Pop ( )
if err != nil {
t . Errorf ( "Error while popping pods from the queue: %v" , err )
}
if ( i == 4 ) != ( p1 == p ) {
2021-02-22 09:00:23 -05:00
t . Errorf ( "A pod tried before is not the last pod popped: i: %v, pod name: %v" , i , p . PodInfo . Pod . Name )
2018-11-27 19:46:24 -05:00
}
}
}
2018-07-24 16:46:40 -04:00
2018-12-29 09:24:51 -05:00
// TestPodFailedSchedulingMultipleTimesDoesNotBlockNewerPod tests
// that a pod determined as unschedulable multiple times doesn't block any newer pod.
// This behavior ensures that an unschedulable pod does not block head of the queue when there
// are frequent events that move pods to the active queue.
func TestPodFailedSchedulingMultipleTimesDoesNotBlockNewerPod ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) )
2018-12-29 09:24:51 -05:00
// Add an unschedulable pod to a priority queue.
// This makes a situation that the pod was tried to schedule
2019-09-17 14:19:56 -04:00
// and had been determined unschedulable so far
2018-12-29 09:24:51 -05:00
unschedulablePod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-pod-unscheduled" ,
Namespace : "ns1" ,
UID : "tp001" ,
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
2019-02-21 20:46:18 -05:00
2018-12-29 09:24:51 -05:00
// Update pod condition to unschedulable.
podutil . UpdatePodCondition ( & unschedulablePod . Status , & v1 . PodCondition {
2019-02-21 20:46:18 -05:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
2018-12-29 09:24:51 -05:00
} )
2019-02-21 20:46:18 -05:00
2018-12-29 09:24:51 -05:00
// Put in the unschedulable queue
2021-02-22 09:00:23 -05:00
q . AddUnschedulableIfNotPresent ( newQueuedPodInfoForLookup ( & unschedulablePod ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
// Move clock to make the unschedulable pods complete backoff.
c . Step ( DefaultPodInitialBackoffDuration + time . Second )
2018-12-29 09:24:51 -05:00
// Move all unschedulable pods to the active queue.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( UnschedulableTimeout , nil )
2018-12-29 09:24:51 -05:00
// Simulate a pod being popped by the scheduler,
// At this time, unschedulable pod should be popped.
p1 , err := q . Pop ( )
if err != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err )
}
2019-10-07 19:06:00 -04:00
if p1 . Pod != & unschedulablePod {
t . Errorf ( "Expected that test-pod-unscheduled was popped, got %v" , p1 . Pod . Name )
2018-12-29 09:24:51 -05:00
}
// Assume newer pod was added just after unschedulable pod
// being popped and before being pushed back to the queue.
newerPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-newer-pod" ,
Namespace : "ns1" ,
UID : "tp002" ,
CreationTimestamp : metav1 . Now ( ) ,
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
q . Add ( & newerPod )
2021-02-22 09:00:23 -05:00
// And then unschedulablePodInfo was determined as unschedulable AGAIN.
2018-12-29 09:24:51 -05:00
podutil . UpdatePodCondition ( & unschedulablePod . Status , & v1 . PodCondition {
2019-02-21 20:46:18 -05:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
2018-12-29 09:24:51 -05:00
} )
2019-02-21 20:46:18 -05:00
2018-12-29 09:24:51 -05:00
// And then, put unschedulable pod to the unschedulable queue
2021-02-22 09:00:23 -05:00
q . AddUnschedulableIfNotPresent ( newQueuedPodInfoForLookup ( & unschedulablePod ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
// Move clock to make the unschedulable pods complete backoff.
c . Step ( DefaultPodInitialBackoffDuration + time . Second )
2018-12-29 09:24:51 -05:00
// Move all unschedulable pods to the active queue.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( UnschedulableTimeout , nil )
2018-12-29 09:24:51 -05:00
// At this time, newerPod should be popped
// because it is the oldest tried pod.
p2 , err2 := q . Pop ( )
if err2 != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err2 )
}
2019-10-07 19:06:00 -04:00
if p2 . Pod != & newerPod {
t . Errorf ( "Expected that test-newer-pod was popped, got %v" , p2 . Pod . Name )
2018-12-29 09:24:51 -05:00
}
}
2018-07-24 16:46:40 -04:00
// TestHighPriorityBackoff tests that a high priority pod does not block
// other pods if it is unschedulable
2019-06-05 16:04:22 -04:00
func TestHighPriorityBackoff ( t * testing . T ) {
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) )
2018-07-24 16:46:40 -04:00
midPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-midpod" ,
Namespace : "ns1" ,
UID : types . UID ( "tp-mid" ) ,
} ,
Spec : v1 . PodSpec {
Priority : & midPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
highPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-highpod" ,
Namespace : "ns1" ,
UID : types . UID ( "tp-high" ) ,
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
q . Add ( & midPod )
q . Add ( & highPod )
// Simulate a pod being popped by the scheduler, determined unschedulable, and
// then moved back to the active queue.
p , err := q . Pop ( )
if err != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err )
}
2019-10-07 19:06:00 -04:00
if p . Pod != & highPod {
2019-06-05 16:04:22 -04:00
t . Errorf ( "Expected to get high priority pod, got: %v" , p )
2018-07-24 16:46:40 -04:00
}
// Update pod condition to unschedulable.
2019-10-07 19:06:00 -04:00
podutil . UpdatePodCondition ( & p . Pod . Status , & v1 . PodCondition {
2018-07-24 16:46:40 -04:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
} )
// Put in the unschedulable queue.
2019-01-25 05:39:53 -05:00
q . AddUnschedulableIfNotPresent ( p , q . SchedulingCycle ( ) )
2018-07-24 16:46:40 -04:00
// Move all unschedulable pods to the active queue.
2021-03-16 18:08:19 -04:00
q . MoveAllToActiveOrBackoffQueue ( TestEvent , nil )
2018-07-24 16:46:40 -04:00
p , err = q . Pop ( )
if err != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err )
}
2019-10-07 19:06:00 -04:00
if p . Pod != & midPod {
2019-06-05 16:04:22 -04:00
t . Errorf ( "Expected to get mid priority pod, got: %v" , p )
2018-07-24 16:46:40 -04:00
}
}
2019-01-15 23:08:19 -05:00
2019-06-05 16:04:22 -04:00
// TestHighPriorityFlushUnschedulableQLeftover tests that pods will be moved to
2019-01-15 23:08:19 -05:00
// activeQ after one minutes if it is in unschedulableQ
2019-06-05 16:04:22 -04:00
func TestHighPriorityFlushUnschedulableQLeftover ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( time . Now ( ) )
2021-01-29 01:29:10 -05:00
m := map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAdd : sets . NewString ( "fakePlugin" ) ,
2021-01-29 01:29:10 -05:00
}
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) , WithClusterEventMap ( m ) )
2019-01-15 23:08:19 -05:00
midPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-midpod" ,
Namespace : "ns1" ,
UID : types . UID ( "tp-mid" ) ,
} ,
Spec : v1 . PodSpec {
Priority : & midPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
highPod := v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-highpod" ,
Namespace : "ns1" ,
UID : types . UID ( "tp-high" ) ,
} ,
Spec : v1 . PodSpec {
Priority : & highPriority ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
// Update pod condition to highPod.
podutil . UpdatePodCondition ( & highPod . Status , & v1 . PodCondition {
2019-02-21 20:46:18 -05:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
2019-01-15 23:08:19 -05:00
} )
// Update pod condition to midPod.
podutil . UpdatePodCondition ( & midPod . Status , & v1 . PodCondition {
2019-02-21 20:46:18 -05:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
2019-01-15 23:08:19 -05:00
} )
2021-01-29 01:29:10 -05:00
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( & highPod , "fakePlugin" ) , q . SchedulingCycle ( ) )
q . AddUnschedulableIfNotPresent ( q . newQueuedPodInfo ( & midPod , "fakePlugin" ) , q . SchedulingCycle ( ) )
2020-02-13 19:31:07 -05:00
c . Step ( unschedulableQTimeInterval + time . Second )
2020-05-05 03:11:04 -04:00
q . flushUnschedulableQLeftover ( )
2019-02-21 20:46:18 -05:00
2019-10-07 19:06:00 -04:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != & highPod {
2021-02-22 09:00:23 -05:00
t . Errorf ( "Expected: %v after Pop, but got: %v" , highPriorityPodInfo . Pod . Name , p . Pod . Name )
2019-01-15 23:08:19 -05:00
}
2019-10-07 19:06:00 -04:00
if p , err := q . Pop ( ) ; err != nil || p . Pod != & midPod {
2021-02-22 09:00:23 -05:00
t . Errorf ( "Expected: %v after Pop, but got: %v" , medPriorityPodInfo . Pod . Name , p . Pod . Name )
2019-01-15 23:08:19 -05:00
}
}
2019-02-21 20:46:18 -05:00
2020-04-20 20:36:26 -04:00
type operation func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo )
2019-03-19 20:02:45 -04:00
var (
2020-04-20 20:36:26 -04:00
add = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-10-07 13:29:53 -04:00
queue . Add ( pInfo . Pod )
}
2020-04-20 20:36:26 -04:00
addUnschedulablePodBackToUnschedulableQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-10-07 13:29:53 -04:00
queue . AddUnschedulableIfNotPresent ( pInfo , 0 )
}
2020-04-20 20:36:26 -04:00
addUnschedulablePodBackToBackoffQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-10-07 13:29:53 -04:00
queue . AddUnschedulableIfNotPresent ( pInfo , - 1 )
}
2020-04-20 20:36:26 -04:00
addPodActiveQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-03-19 20:02:45 -04:00
queue . activeQ . Add ( pInfo )
}
2020-04-20 20:36:26 -04:00
updatePodActiveQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-03-19 20:02:45 -04:00
queue . activeQ . Update ( pInfo )
}
2020-04-20 20:36:26 -04:00
addPodUnschedulableQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-03-19 20:02:45 -04:00
// Update pod condition to unschedulable.
2019-05-06 21:03:00 -04:00
podutil . UpdatePodCondition ( & pInfo . Pod . Status , & v1 . PodCondition {
2019-03-19 20:02:45 -04:00
Type : v1 . PodScheduled ,
Status : v1 . ConditionFalse ,
Reason : v1 . PodReasonUnschedulable ,
Message : "fake scheduling failure" ,
} )
queue . unschedulableQ . addOrUpdate ( pInfo )
}
2020-04-20 20:36:26 -04:00
addPodBackoffQ = func ( queue * PriorityQueue , pInfo * framework . QueuedPodInfo ) {
2019-03-19 20:02:45 -04:00
queue . podBackoffQ . Add ( pInfo )
}
2020-04-20 20:36:26 -04:00
moveAllToActiveOrBackoffQ = func ( queue * PriorityQueue , _ * framework . QueuedPodInfo ) {
2021-03-11 15:31:33 -05:00
queue . MoveAllToActiveOrBackoffQueue ( UnschedulableTimeout , nil )
2019-03-19 20:02:45 -04:00
}
2020-04-20 20:36:26 -04:00
flushBackoffQ = func ( queue * PriorityQueue , _ * framework . QueuedPodInfo ) {
2021-09-17 05:48:22 -04:00
queue . clock . ( * testingclock . FakeClock ) . Step ( 2 * time . Second )
2019-03-19 20:02:45 -04:00
queue . flushBackoffQCompleted ( )
}
2020-04-20 20:36:26 -04:00
moveClockForward = func ( queue * PriorityQueue , _ * framework . QueuedPodInfo ) {
2021-09-17 05:48:22 -04:00
queue . clock . ( * testingclock . FakeClock ) . Step ( 2 * time . Second )
2019-10-07 13:29:53 -04:00
}
2019-03-19 20:02:45 -04:00
)
2020-04-20 20:36:26 -04:00
// TestPodTimestamp tests the operations related to QueuedPodInfo.
2019-02-21 20:46:18 -05:00
func TestPodTimestamp ( t * testing . T ) {
pod1 := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-pod-1" ,
Namespace : "ns1" ,
UID : types . UID ( "tp-1" ) ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node1" ,
} ,
}
pod2 := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-pod-2" ,
Namespace : "ns2" ,
UID : types . UID ( "tp-2" ) ,
} ,
Status : v1 . PodStatus {
NominatedNodeName : "node2" ,
} ,
}
2019-02-27 18:23:27 -05:00
var timestamp = time . Now ( )
2020-04-20 20:36:26 -04:00
pInfo1 := & framework . QueuedPodInfo {
2021-02-22 09:00:23 -05:00
PodInfo : framework . NewPodInfo ( pod1 ) ,
2019-05-06 21:03:00 -04:00
Timestamp : timestamp ,
2019-02-21 20:46:18 -05:00
}
2020-04-20 20:36:26 -04:00
pInfo2 := & framework . QueuedPodInfo {
2021-02-22 09:00:23 -05:00
PodInfo : framework . NewPodInfo ( pod2 ) ,
2019-05-06 21:03:00 -04:00
Timestamp : timestamp . Add ( time . Second ) ,
2019-02-21 20:46:18 -05:00
}
tests := [ ] struct {
name string
operations [ ] operation
2020-04-20 20:36:26 -04:00
operands [ ] * framework . QueuedPodInfo
expected [ ] * framework . QueuedPodInfo
2019-02-21 20:46:18 -05:00
} {
{
name : "add two pod to activeQ and sort them by the timestamp" ,
operations : [ ] operation {
2019-03-19 20:02:45 -04:00
addPodActiveQ ,
addPodActiveQ ,
2019-02-21 20:46:18 -05:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] * framework . QueuedPodInfo { pInfo2 , pInfo1 } ,
expected : [ ] * framework . QueuedPodInfo { pInfo1 , pInfo2 } ,
2019-02-21 20:46:18 -05:00
} ,
{
name : "update two pod to activeQ and sort them by the timestamp" ,
operations : [ ] operation {
2019-03-19 20:02:45 -04:00
updatePodActiveQ ,
updatePodActiveQ ,
2019-02-21 20:46:18 -05:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] * framework . QueuedPodInfo { pInfo2 , pInfo1 } ,
expected : [ ] * framework . QueuedPodInfo { pInfo1 , pInfo2 } ,
2019-02-21 20:46:18 -05:00
} ,
{
name : "add two pod to unschedulableQ then move them to activeQ and sort them by the timestamp" ,
operations : [ ] operation {
2019-03-19 20:02:45 -04:00
addPodUnschedulableQ ,
addPodUnschedulableQ ,
2020-02-13 19:31:07 -05:00
moveClockForward ,
2019-10-07 13:29:53 -04:00
moveAllToActiveOrBackoffQ ,
2019-02-21 20:46:18 -05:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] * framework . QueuedPodInfo { pInfo2 , pInfo1 , nil , nil } ,
expected : [ ] * framework . QueuedPodInfo { pInfo1 , pInfo2 } ,
2019-02-21 20:46:18 -05:00
} ,
{
name : "add one pod to BackoffQ and move it to activeQ" ,
operations : [ ] operation {
2019-03-19 20:02:45 -04:00
addPodActiveQ ,
addPodBackoffQ ,
flushBackoffQ ,
2019-10-07 13:29:53 -04:00
moveAllToActiveOrBackoffQ ,
2019-02-21 20:46:18 -05:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] * framework . QueuedPodInfo { pInfo2 , pInfo1 , nil , nil } ,
expected : [ ] * framework . QueuedPodInfo { pInfo1 , pInfo2 } ,
2019-02-21 20:46:18 -05:00
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
queue := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( testingclock . NewFakeClock ( timestamp ) ) )
2020-04-20 20:36:26 -04:00
var podInfoList [ ] * framework . QueuedPodInfo
2019-02-21 20:46:18 -05:00
2019-03-19 20:02:45 -04:00
for i , op := range test . operations {
2019-03-20 02:53:33 -04:00
op ( queue , test . operands [ i ] )
2019-02-21 20:46:18 -05:00
}
for i := 0 ; i < len ( test . expected ) ; i ++ {
if pInfo , err := queue . activeQ . Pop ( ) ; err != nil {
t . Errorf ( "Error while popping the head of the queue: %v" , err )
} else {
2020-04-20 20:36:26 -04:00
podInfoList = append ( podInfoList , pInfo . ( * framework . QueuedPodInfo ) )
2019-02-21 20:46:18 -05:00
}
}
if ! reflect . DeepEqual ( test . expected , podInfoList ) {
2020-04-20 20:36:26 -04:00
t . Errorf ( "Unexpected QueuedPodInfo list. Expected: %v, got: %v" ,
2019-02-21 20:46:18 -05:00
test . expected , podInfoList )
}
} )
}
}
2019-03-20 02:53:33 -04:00
// TestPendingPodsMetric tests Prometheus metrics related with pending pods
func TestPendingPodsMetric ( t * testing . T ) {
timestamp := time . Now ( )
2019-08-22 21:00:06 -04:00
metrics . Register ( )
2020-02-13 19:31:07 -05:00
total := 50
2020-04-20 20:36:26 -04:00
pInfos := makeQueuedPodInfos ( total , timestamp )
2020-02-13 19:31:07 -05:00
totalWithDelay := 20
2020-04-20 20:36:26 -04:00
pInfosWithDelay := makeQueuedPodInfos ( totalWithDelay , timestamp . Add ( 2 * time . Second ) )
2020-02-13 19:31:07 -05:00
2019-03-20 02:53:33 -04:00
tests := [ ] struct {
2019-09-29 22:05:50 -04:00
name string
operations [ ] operation
2020-04-20 20:36:26 -04:00
operands [ ] [ ] * framework . QueuedPodInfo
2019-09-29 22:05:50 -04:00
metricsName string
wants string
2019-03-20 02:53:33 -04:00
} {
{
name : "add pods to activeQ and unschedulableQ" ,
operations : [ ] operation {
addPodActiveQ ,
addPodUnschedulableQ ,
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] [ ] * framework . QueuedPodInfo {
2019-03-20 02:53:33 -04:00
pInfos [ : 30 ] ,
pInfos [ 30 : ] ,
} ,
2019-09-29 22:05:50 -04:00
metricsName : "scheduler_pending_pods" ,
wants : `
2021-10-27 12:39:19 -04:00
# HELP scheduler_pending_pods [ STABLE ] Number of pending pods , by the queue type . ' active ' means number of pods in activeQ ; ' backoff ' means number of pods in backoffQ ; ' unschedulable ' means number of pods in unschedulableQ .
2019-09-29 22:05:50 -04:00
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods { queue = "active" } 30
scheduler_pending_pods { queue = "backoff" } 0
scheduler_pending_pods { queue = "unschedulable" } 20
` ,
2019-03-20 02:53:33 -04:00
} ,
{
name : "add pods to all kinds of queues" ,
operations : [ ] operation {
addPodActiveQ ,
addPodBackoffQ ,
addPodUnschedulableQ ,
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] [ ] * framework . QueuedPodInfo {
2019-03-20 02:53:33 -04:00
pInfos [ : 15 ] ,
pInfos [ 15 : 40 ] ,
pInfos [ 40 : ] ,
} ,
2019-09-29 22:05:50 -04:00
metricsName : "scheduler_pending_pods" ,
wants : `
2021-10-27 12:39:19 -04:00
# HELP scheduler_pending_pods [ STABLE ] Number of pending pods , by the queue type . ' active ' means number of pods in activeQ ; ' backoff ' means number of pods in backoffQ ; ' unschedulable ' means number of pods in unschedulableQ .
2019-09-29 22:05:50 -04:00
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods { queue = "active" } 15
scheduler_pending_pods { queue = "backoff" } 25
scheduler_pending_pods { queue = "unschedulable" } 10
` ,
2019-03-20 02:53:33 -04:00
} ,
{
name : "add pods to unschedulableQ and then move all to activeQ" ,
operations : [ ] operation {
addPodUnschedulableQ ,
2020-02-13 19:31:07 -05:00
moveClockForward ,
2019-10-07 13:29:53 -04:00
moveAllToActiveOrBackoffQ ,
2019-03-20 02:53:33 -04:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] [ ] * framework . QueuedPodInfo {
2019-03-20 02:53:33 -04:00
pInfos [ : total ] ,
{ nil } ,
2020-02-13 19:31:07 -05:00
{ nil } ,
2019-03-20 02:53:33 -04:00
} ,
2019-09-29 22:05:50 -04:00
metricsName : "scheduler_pending_pods" ,
wants : `
2021-10-27 12:39:19 -04:00
# HELP scheduler_pending_pods [ STABLE ] Number of pending pods , by the queue type . ' active ' means number of pods in activeQ ; ' backoff ' means number of pods in backoffQ ; ' unschedulable ' means number of pods in unschedulableQ .
2019-09-29 22:05:50 -04:00
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods { queue = "active" } 50
scheduler_pending_pods { queue = "backoff" } 0
scheduler_pending_pods { queue = "unschedulable" } 0
` ,
2019-03-20 02:53:33 -04:00
} ,
{
name : "make some pods subject to backoff, add pods to unschedulableQ, and then move all to activeQ" ,
operations : [ ] operation {
2020-02-13 19:31:07 -05:00
addPodUnschedulableQ ,
moveClockForward ,
2019-03-20 02:53:33 -04:00
addPodUnschedulableQ ,
2019-10-07 13:29:53 -04:00
moveAllToActiveOrBackoffQ ,
2019-03-20 02:53:33 -04:00
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] [ ] * framework . QueuedPodInfo {
2020-02-13 19:31:07 -05:00
pInfos [ 20 : total ] ,
{ nil } ,
pInfosWithDelay [ : 20 ] ,
2019-03-20 02:53:33 -04:00
{ nil } ,
} ,
2019-09-29 22:05:50 -04:00
metricsName : "scheduler_pending_pods" ,
wants : `
2021-10-27 12:39:19 -04:00
# HELP scheduler_pending_pods [ STABLE ] Number of pending pods , by the queue type . ' active ' means number of pods in activeQ ; ' backoff ' means number of pods in backoffQ ; ' unschedulable ' means number of pods in unschedulableQ .
2019-09-29 22:05:50 -04:00
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods { queue = "active" } 30
scheduler_pending_pods { queue = "backoff" } 20
scheduler_pending_pods { queue = "unschedulable" } 0
` ,
2019-03-20 02:53:33 -04:00
} ,
{
name : "make some pods subject to backoff, add pods to unschedulableQ/activeQ, move all to activeQ, and finally flush backoffQ" ,
operations : [ ] operation {
addPodUnschedulableQ ,
addPodActiveQ ,
2019-10-07 13:29:53 -04:00
moveAllToActiveOrBackoffQ ,
2019-03-20 02:53:33 -04:00
flushBackoffQ ,
} ,
2020-04-20 20:36:26 -04:00
operands : [ ] [ ] * framework . QueuedPodInfo {
2019-03-20 02:53:33 -04:00
pInfos [ : 40 ] ,
pInfos [ 40 : ] ,
{ nil } ,
{ nil } ,
} ,
2019-09-29 22:05:50 -04:00
metricsName : "scheduler_pending_pods" ,
wants : `
2021-10-27 12:39:19 -04:00
# HELP scheduler_pending_pods [ STABLE ] Number of pending pods , by the queue type . ' active ' means number of pods in activeQ ; ' backoff ' means number of pods in backoffQ ; ' unschedulable ' means number of pods in unschedulableQ .
2019-09-29 22:05:50 -04:00
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods { queue = "active" } 50
scheduler_pending_pods { queue = "backoff" } 0
scheduler_pending_pods { queue = "unschedulable" } 0
` ,
2019-03-20 02:53:33 -04:00
} ,
}
resetMetrics := func ( ) {
2019-08-22 21:00:06 -04:00
metrics . ActivePods ( ) . Set ( 0 )
metrics . BackoffPods ( ) . Set ( 0 )
metrics . UnschedulablePods ( ) . Set ( 0 )
2019-03-20 02:53:33 -04:00
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
resetMetrics ( )
2021-09-17 05:48:22 -04:00
queue := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( testingclock . NewFakeClock ( timestamp ) ) )
2019-03-20 02:53:33 -04:00
for i , op := range test . operations {
for _ , pInfo := range test . operands [ i ] {
op ( queue , pInfo )
}
}
2019-09-29 22:05:50 -04:00
if err := testutil . GatherAndCompare ( metrics . GetGather ( ) , strings . NewReader ( test . wants ) , test . metricsName ) ; err != nil {
t . Fatal ( err )
2019-03-20 02:53:33 -04:00
}
} )
}
}
2019-10-07 19:06:00 -04:00
// TestPerPodSchedulingMetrics makes sure pod schedule attempts is updated correctly while
// initialAttemptTimestamp stays the same during multiple add/pop operations.
func TestPerPodSchedulingMetrics ( t * testing . T ) {
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-pod" ,
Namespace : "test-ns" ,
UID : types . UID ( "test-uid" ) ,
} ,
}
timestamp := time . Now ( )
// Case 1: A pod is created and scheduled after 1 attempt. The queue operations are
// Add -> Pop.
2021-09-17 05:48:22 -04:00
c := testingclock . NewFakeClock ( timestamp )
2021-03-04 07:30:24 -05:00
queue := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) )
2019-10-07 19:06:00 -04:00
queue . Add ( pod )
pInfo , err := queue . Pop ( )
if err != nil {
t . Fatalf ( "Failed to pop a pod %v" , err )
}
checkPerPodSchedulingMetrics ( "Attempt once" , t , pInfo , 1 , timestamp )
// Case 2: A pod is created and scheduled after 2 attempts. The queue operations are
// Add -> Pop -> AddUnschedulableIfNotPresent -> flushUnschedulableQLeftover -> Pop.
2021-09-17 05:48:22 -04:00
c = testingclock . NewFakeClock ( timestamp )
2021-03-04 07:30:24 -05:00
queue = NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) )
2019-10-07 19:06:00 -04:00
queue . Add ( pod )
pInfo , err = queue . Pop ( )
if err != nil {
t . Fatalf ( "Failed to pop a pod %v" , err )
}
queue . AddUnschedulableIfNotPresent ( pInfo , 1 )
// Override clock to exceed the unschedulableQTimeInterval so that unschedulable pods
// will be moved to activeQ
c . SetTime ( timestamp . Add ( unschedulableQTimeInterval + 1 ) )
queue . flushUnschedulableQLeftover ( )
pInfo , err = queue . Pop ( )
if err != nil {
t . Fatalf ( "Failed to pop a pod %v" , err )
}
checkPerPodSchedulingMetrics ( "Attempt twice" , t , pInfo , 2 , timestamp )
// Case 3: Similar to case 2, but before the second pop, call update, the queue operations are
// Add -> Pop -> AddUnschedulableIfNotPresent -> flushUnschedulableQLeftover -> Update -> Pop.
2021-09-17 05:48:22 -04:00
c = testingclock . NewFakeClock ( timestamp )
2021-03-04 07:30:24 -05:00
queue = NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( c ) )
2019-10-07 19:06:00 -04:00
queue . Add ( pod )
pInfo , err = queue . Pop ( )
if err != nil {
t . Fatalf ( "Failed to pop a pod %v" , err )
}
queue . AddUnschedulableIfNotPresent ( pInfo , 1 )
// Override clock to exceed the unschedulableQTimeInterval so that unschedulable pods
// will be moved to activeQ
c . SetTime ( timestamp . Add ( unschedulableQTimeInterval + 1 ) )
queue . flushUnschedulableQLeftover ( )
newPod := pod . DeepCopy ( )
newPod . Generation = 1
queue . Update ( pod , newPod )
pInfo , err = queue . Pop ( )
if err != nil {
t . Fatalf ( "Failed to pop a pod %v" , err )
}
checkPerPodSchedulingMetrics ( "Attempt twice with update" , t , pInfo , 2 , timestamp )
}
2019-10-07 13:29:53 -04:00
func TestIncomingPodsMetrics ( t * testing . T ) {
timestamp := time . Now ( )
metrics . Register ( )
2020-04-20 20:36:26 -04:00
var pInfos = make ( [ ] * framework . QueuedPodInfo , 0 , 3 )
2019-10-07 13:29:53 -04:00
for i := 1 ; i <= 3 ; i ++ {
2020-04-20 20:36:26 -04:00
p := & framework . QueuedPodInfo {
2021-02-22 09:00:23 -05:00
PodInfo : framework . NewPodInfo ( & v1 . Pod {
2019-10-07 13:29:53 -04:00
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "test-pod-%d" , i ) ,
Namespace : fmt . Sprintf ( "ns%d" , i ) ,
UID : types . UID ( fmt . Sprintf ( "tp-%d" , i ) ) ,
} ,
2021-02-22 09:00:23 -05:00
} ) ,
2019-10-07 13:29:53 -04:00
Timestamp : timestamp ,
}
pInfos = append ( pInfos , p )
}
tests := [ ] struct {
name string
operations [ ] operation
want string
} {
{
name : "add pods to activeQ" ,
operations : [ ] operation {
add ,
} ,
want : `
scheduler_queue_incoming_pods_total { event = "PodAdd" , queue = "active" } 3
` ,
} ,
{
name : "add pods to unschedulableQ" ,
operations : [ ] operation {
addUnschedulablePodBackToUnschedulableQ ,
} ,
want : `
scheduler_queue_incoming_pods_total { event = "ScheduleAttemptFailure" , queue = "unschedulable" } 3
` ,
} ,
{
name : "add pods to unschedulableQ and then move all to backoffQ" ,
operations : [ ] operation {
addUnschedulablePodBackToUnschedulableQ ,
moveAllToActiveOrBackoffQ ,
} ,
want : ` scheduler_queue_incoming_pods_total { event = "ScheduleAttemptFailure" , queue = "unschedulable" } 3
2021-01-29 01:29:10 -05:00
scheduler_queue_incoming_pods_total { event = "UnschedulableTimeout" , queue = "backoff" } 3
2019-10-07 13:29:53 -04:00
` ,
} ,
{
name : "add pods to unschedulableQ and then move all to activeQ" ,
operations : [ ] operation {
addUnschedulablePodBackToUnschedulableQ ,
moveClockForward ,
moveAllToActiveOrBackoffQ ,
} ,
want : ` scheduler_queue_incoming_pods_total { event = "ScheduleAttemptFailure" , queue = "unschedulable" } 3
2021-01-29 01:29:10 -05:00
scheduler_queue_incoming_pods_total { event = "UnschedulableTimeout" , queue = "active" } 3
2019-10-07 13:29:53 -04:00
` ,
} ,
{
name : "make some pods subject to backoff and add them to backoffQ, then flush backoffQ" ,
operations : [ ] operation {
addUnschedulablePodBackToBackoffQ ,
moveClockForward ,
flushBackoffQ ,
} ,
want : ` scheduler_queue_incoming_pods_total { event = "BackoffComplete" , queue = "active" } 3
scheduler_queue_incoming_pods_total { event = "ScheduleAttemptFailure" , queue = "backoff" } 3
` ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
metrics . SchedulerQueueIncomingPods . Reset ( )
2021-09-17 05:48:22 -04:00
queue := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( testingclock . NewFakeClock ( timestamp ) ) )
2019-10-07 13:29:53 -04:00
for _ , op := range test . operations {
for _ , pInfo := range pInfos {
op ( queue , pInfo )
}
}
metricName := metrics . SchedulerSubsystem + "_" + metrics . SchedulerQueueIncomingPods . Name
if err := testutil . CollectAndCompare ( metrics . SchedulerQueueIncomingPods , strings . NewReader ( queueMetricMetadata + test . want ) , metricName ) ; err != nil {
t . Errorf ( "unexpected collecting result:\n%s" , err )
}
} )
}
}
2020-04-20 20:36:26 -04:00
func checkPerPodSchedulingMetrics ( name string , t * testing . T , pInfo * framework . QueuedPodInfo , wantAttemtps int , wantInitialAttemptTs time . Time ) {
2019-10-07 19:06:00 -04:00
if pInfo . Attempts != wantAttemtps {
t . Errorf ( "[%s] Pod schedule attempt unexpected, got %v, want %v" , name , pInfo . Attempts , wantAttemtps )
}
if pInfo . InitialAttemptTimestamp != wantInitialAttemptTs {
t . Errorf ( "[%s] Pod initial schedule attempt timestamp unexpected, got %v, want %v" , name , pInfo . InitialAttemptTimestamp , wantInitialAttemptTs )
}
}
2019-12-02 14:35:09 -05:00
2020-01-28 13:29:44 -05:00
func TestBackOffFlow ( t * testing . T ) {
2021-09-17 05:48:22 -04:00
cl := testingclock . NewFakeClock ( time . Now ( ) )
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithClock ( cl ) )
2020-01-28 13:29:44 -05:00
steps := [ ] struct {
wantBackoff time . Duration
} {
{ wantBackoff : time . Second } ,
{ wantBackoff : 2 * time . Second } ,
{ wantBackoff : 4 * time . Second } ,
{ wantBackoff : 8 * time . Second } ,
{ wantBackoff : 10 * time . Second } ,
{ wantBackoff : 10 * time . Second } ,
{ wantBackoff : 10 * time . Second } ,
}
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-pod" ,
Namespace : "test-ns" ,
UID : "test-uid" ,
} ,
}
2021-01-25 02:07:39 -05:00
2021-04-09 03:31:32 -04:00
podID := types . NamespacedName {
2021-01-25 02:07:39 -05:00
Namespace : pod . Namespace ,
Name : pod . Name ,
}
2020-01-28 13:29:44 -05:00
if err := q . Add ( pod ) ; err != nil {
t . Fatal ( err )
}
for i , step := range steps {
t . Run ( fmt . Sprintf ( "step %d" , i ) , func ( t * testing . T ) {
timestamp := cl . Now ( )
// Simulate schedule attempt.
podInfo , err := q . Pop ( )
if err != nil {
t . Fatal ( err )
}
if podInfo . Attempts != i + 1 {
t . Errorf ( "got attempts %d, want %d" , podInfo . Attempts , i + 1 )
}
if err := q . AddUnschedulableIfNotPresent ( podInfo , int64 ( i ) ) ; err != nil {
t . Fatal ( err )
}
// An event happens.
2021-03-11 15:31:33 -05:00
q . MoveAllToActiveOrBackoffQueue ( UnschedulableTimeout , nil )
2020-01-28 13:29:44 -05:00
if _ , ok , _ := q . podBackoffQ . Get ( podInfo ) ; ! ok {
t . Errorf ( "pod %v is not in the backoff queue" , podID )
}
// Check backoff duration.
2020-02-13 19:31:07 -05:00
deadline := q . getBackoffTime ( podInfo )
2020-01-28 13:29:44 -05:00
backoff := deadline . Sub ( timestamp )
if backoff != step . wantBackoff {
t . Errorf ( "got backoff %s, want %s" , backoff , step . wantBackoff )
}
// Simulate routine that continuously flushes the backoff queue.
cl . Step ( time . Millisecond )
q . flushBackoffQCompleted ( )
// Still in backoff queue after an early flush.
if _ , ok , _ := q . podBackoffQ . Get ( podInfo ) ; ! ok {
t . Errorf ( "pod %v is not in the backoff queue" , podID )
}
// Moved out of the backoff queue after timeout.
cl . Step ( backoff )
q . flushBackoffQCompleted ( )
if _ , ok , _ := q . podBackoffQ . Get ( podInfo ) ; ok {
t . Errorf ( "pod %v is still in the backoff queue" , podID )
}
} )
}
2020-02-13 19:31:07 -05:00
}
2021-01-29 01:29:10 -05:00
func TestPodMatchesEvent ( t * testing . T ) {
tests := [ ] struct {
name string
podInfo * framework . QueuedPodInfo
2021-03-16 18:08:19 -04:00
event framework . ClusterEvent
2021-01-29 01:29:10 -05:00
clusterEventMap map [ framework . ClusterEvent ] sets . String
want bool
} {
{
name : "event not registered" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } ) ,
2021-03-16 18:08:19 -04:00
event : EmptyEvent ,
2021-01-29 01:29:10 -05:00
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "foo" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : false ,
} ,
{
name : "pod's failed plugin matches but event does not match" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "bar" ) ,
2021-03-16 18:08:19 -04:00
event : AssignedPodAdd ,
2021-01-29 01:29:10 -05:00
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "foo" , "bar" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : false ,
} ,
{
name : "wildcard event wins regardless of event matching" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "bar" ) ,
2021-03-16 18:08:19 -04:00
event : WildCardEvent ,
2021-01-29 01:29:10 -05:00
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "foo" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : true ,
} ,
{
name : "pod's failed plugin and event both match" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "bar" ) ,
event : NodeTaintChange ,
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "foo" , "bar" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : true ,
} ,
{
name : "pod's failed plugin registers fine-grained event" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "bar" ) ,
event : NodeTaintChange ,
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "foo" ) ,
NodeTaintChange : sets . NewString ( "bar" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : true ,
} ,
{
name : "if pod failed by multiple plugins, a single match gets a final match" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "foo" , "bar" ) ,
event : NodeAdd ,
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
NodeAllEvent : sets . NewString ( "bar" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : true ,
} ,
{
name : "plugin returns WildCardEvent and plugin name matches" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "foo" ) ,
event : PvAdd ,
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
WildCardEvent : sets . NewString ( "foo" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : true ,
} ,
{
name : "plugin returns WildCardEvent but plugin name not match" ,
podInfo : newQueuedPodInfoForLookup ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "p" } } , "foo" ) ,
event : PvAdd ,
clusterEventMap : map [ framework . ClusterEvent ] sets . String {
2021-03-16 18:08:19 -04:00
WildCardEvent : sets . NewString ( "bar" ) ,
2021-01-29 01:29:10 -05:00
} ,
want : false ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2021-03-04 07:30:24 -05:00
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) )
2021-01-29 01:29:10 -05:00
q . clusterEventMap = tt . clusterEventMap
if got := q . podMatchesEvent ( tt . podInfo , tt . event ) ; got != tt . want {
t . Errorf ( "Want %v, but got %v" , tt . want , got )
}
} )
}
}
2021-03-11 15:31:33 -05:00
func TestMoveAllToActiveOrBackoffQueue_PreEnqueueChecks ( t * testing . T ) {
var podInfos [ ] * framework . QueuedPodInfo
for i := 0 ; i < 5 ; i ++ {
pInfo := newQueuedPodInfoForLookup ( & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Name : fmt . Sprintf ( "p%d" , i ) } ,
Spec : v1 . PodSpec { Priority : pointer . Int32Ptr ( int32 ( i ) ) } ,
} )
podInfos = append ( podInfos , pInfo )
}
tests := [ ] struct {
name string
preEnqueueCheck PreEnqueueCheck
podInfos [ ] * framework . QueuedPodInfo
want [ ] string
} {
{
name : "nil PreEnqueueCheck" ,
podInfos : podInfos ,
want : [ ] string { "p0" , "p1" , "p2" , "p3" , "p4" } ,
} ,
{
name : "move Pods with priority greater than 2" ,
podInfos : podInfos ,
preEnqueueCheck : func ( pod * v1 . Pod ) bool { return * pod . Spec . Priority >= 2 } ,
want : [ ] string { "p2" , "p3" , "p4" } ,
} ,
{
name : "move Pods with even priority and greater than 2" ,
podInfos : podInfos ,
preEnqueueCheck : func ( pod * v1 . Pod ) bool {
return * pod . Spec . Priority % 2 == 0 && * pod . Spec . Priority >= 2
} ,
want : [ ] string { "p2" , "p4" } ,
} ,
{
name : "move Pods with even and negative priority" ,
podInfos : podInfos ,
preEnqueueCheck : func ( pod * v1 . Pod ) bool {
return * pod . Spec . Priority % 2 == 0 && * pod . Spec . Priority < 0
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) )
for _ , podInfo := range tt . podInfos {
q . AddUnschedulableIfNotPresent ( podInfo , q . schedulingCycle )
}
2021-03-16 18:08:19 -04:00
q . MoveAllToActiveOrBackoffQueue ( TestEvent , tt . preEnqueueCheck )
2021-03-11 15:31:33 -05:00
var got [ ] string
for q . podBackoffQ . Len ( ) != 0 {
obj , err := q . podBackoffQ . Pop ( )
if err != nil {
t . Fatalf ( "Fail to pop pod from backoffQ: %v" , err )
}
queuedPodInfo , ok := obj . ( * framework . QueuedPodInfo )
if ! ok {
t . Fatalf ( "Fail to covert popped obj (type %T) to *framework.QueuedPodInfo" , obj )
}
got = append ( got , queuedPodInfo . Pod . Name )
}
if diff := cmp . Diff ( tt . want , got ) ; diff != "" {
t . Errorf ( "Unexpected diff (-want, +got):\n%s" , diff )
}
} )
}
}
2020-04-20 20:36:26 -04:00
func makeQueuedPodInfos ( num int , timestamp time . Time ) [ ] * framework . QueuedPodInfo {
var pInfos = make ( [ ] * framework . QueuedPodInfo , 0 , num )
2020-02-13 19:31:07 -05:00
for i := 1 ; i <= num ; i ++ {
2020-04-20 20:36:26 -04:00
p := & framework . QueuedPodInfo {
2021-02-22 09:00:23 -05:00
PodInfo : framework . NewPodInfo ( & v1 . Pod {
2020-02-13 19:31:07 -05:00
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "test-pod-%d" , i ) ,
Namespace : fmt . Sprintf ( "ns%d" , i ) ,
UID : types . UID ( fmt . Sprintf ( "tp-%d" , i ) ) ,
} ,
2021-02-22 09:00:23 -05:00
} ) ,
2020-02-13 19:31:07 -05:00
Timestamp : timestamp ,
}
pInfos = append ( pInfos , p )
2020-01-28 13:29:44 -05:00
}
2020-02-13 19:31:07 -05:00
return pInfos
2020-01-28 13:29:44 -05:00
}
2021-09-18 22:09:06 -04:00
func TestPriorityQueue_calculateBackoffDuration ( t * testing . T ) {
tests := [ ] struct {
name string
initialBackoffDuration time . Duration
maxBackoffDuration time . Duration
podInfo * framework . QueuedPodInfo
want time . Duration
} {
{
name : "normal" ,
initialBackoffDuration : 1 * time . Nanosecond ,
maxBackoffDuration : 32 * time . Nanosecond ,
podInfo : & framework . QueuedPodInfo { Attempts : 16 } ,
want : 32 * time . Nanosecond ,
} ,
{
name : "overflow_32bit" ,
initialBackoffDuration : 1 * time . Nanosecond ,
maxBackoffDuration : math . MaxInt32 * time . Nanosecond ,
podInfo : & framework . QueuedPodInfo { Attempts : 32 } ,
want : math . MaxInt32 * time . Nanosecond ,
} ,
{
name : "overflow_64bit" ,
initialBackoffDuration : 1 * time . Nanosecond ,
maxBackoffDuration : math . MaxInt64 * time . Nanosecond ,
podInfo : & framework . QueuedPodInfo { Attempts : 64 } ,
want : math . MaxInt64 * time . Nanosecond ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
q := NewTestQueue ( context . Background ( ) , newDefaultQueueSort ( ) , WithPodInitialBackoffDuration ( tt . initialBackoffDuration ) , WithPodMaxBackoffDuration ( tt . maxBackoffDuration ) )
if got := q . calculateBackoffDuration ( tt . podInfo ) ; got != tt . want {
t . Errorf ( "PriorityQueue.calculateBackoffDuration() = %v, want %v" , got , tt . want )
}
} )
}
}