@@ -173,7 +173,7 @@ func TestPriorityQueue_AddWithReversePriorityLessFunc(t *testing.T) {
173
173
174
174
func Test_InFlightPods (t * testing.T ) {
175
175
logger , _ := ktesting .NewTestContext (t )
176
- pod := st .MakePod ().Name ("targetpod" ).UID ("pod1" ).Obj ()
176
+ pod1 := st .MakePod ().Name ("targetpod" ).UID ("pod1" ).Obj ()
177
177
pod2 := st .MakePod ().Name ("targetpod2" ).UID ("pod2" ).Obj ()
178
178
pod3 := st .MakePod ().Name ("targetpod3" ).UID ("pod3" ).Obj ()
179
179
var poppedPod , poppedPod2 * framework.QueuedPodInfo
@@ -182,8 +182,11 @@ func Test_InFlightPods(t *testing.T) {
182
182
// ONLY ONE of the following should be set.
183
183
eventHappens * framework.ClusterEvent
184
184
podPopped * v1.Pod
185
- podEnqueued * framework.QueuedPodInfo
186
- callback func (t * testing.T , q * PriorityQueue )
185
+ // podCreated is the Pod that is created and inserted into the activeQ.
186
+ podCreated * v1.Pod
187
+ // podEnqueued is the Pod that is enqueued back to activeQ.
188
+ podEnqueued * framework.QueuedPodInfo
189
+ callback func (t * testing.T , q * PriorityQueue )
187
190
}
188
191
189
192
tests := []struct {
@@ -201,10 +204,10 @@ func Test_InFlightPods(t *testing.T) {
201
204
}{
202
205
{
203
206
name : "when SchedulingQueueHint is disabled, inFlightPods and inFlightEvents should be empty" ,
204
- initialPods : []* v1.Pod {pod },
207
+ initialPods : []* v1.Pod {pod1 },
205
208
actions : []action {
206
209
// This Pod shouldn't be added to inFlightPods because SchedulingQueueHint is disabled.
207
- {podPopped : pod },
210
+ {podPopped : pod1 },
208
211
// This event shouldn't be added to inFlightEvents because SchedulingQueueHint is disabled.
209
212
{eventHappens : & framework .PvAdd },
210
213
},
@@ -224,18 +227,18 @@ func Test_InFlightPods(t *testing.T) {
224
227
{
225
228
name : "Pod and interested events are registered in inFlightPods/inFlightEvents" ,
226
229
isSchedulingQueueHintEnabled : true ,
227
- initialPods : []* v1.Pod {pod },
230
+ initialPods : []* v1.Pod {pod1 },
228
231
actions : []action {
229
232
// This won't be added to inFlightEvents because no inFlightPods at this point.
230
233
{eventHappens : & framework .PvcAdd },
231
- {podPopped : pod },
234
+ {podPopped : pod1 },
232
235
// This gets added for the pod.
233
236
{eventHappens : & framework .PvAdd },
234
237
// This doesn't get added because no plugin is interested in framework.PvUpdate.
235
238
{eventHappens : & framework .PvUpdate },
236
239
},
237
- wantInFlightPods : []* v1.Pod {pod },
238
- wantInFlightEvents : []interface {}{pod , framework .PvAdd },
240
+ wantInFlightPods : []* v1.Pod {pod1 },
241
+ wantInFlightEvents : []interface {}{pod1 , framework .PvAdd },
239
242
queueingHintMap : QueueingHintMapPerProfile {
240
243
"" : {
241
244
framework .PvAdd : {
@@ -250,16 +253,16 @@ func Test_InFlightPods(t *testing.T) {
250
253
{
251
254
name : "Pod, registered in inFlightPods, is enqueued back to activeQ" ,
252
255
isSchedulingQueueHintEnabled : true ,
253
- initialPods : []* v1.Pod {pod , pod2 },
256
+ initialPods : []* v1.Pod {pod1 , pod2 },
254
257
actions : []action {
255
258
// This won't be added to inFlightEvents because no inFlightPods at this point.
256
259
{eventHappens : & framework .PvcAdd },
257
- {podPopped : pod },
260
+ {podPopped : pod1 },
258
261
{eventHappens : & framework .PvAdd },
259
262
{podPopped : pod2 },
260
263
{eventHappens : & framework .NodeAdd },
261
264
// This pod will be requeued to backoffQ because no plugin is registered as unschedulable plugin.
262
- {podEnqueued : newQueuedPodInfoForLookup (pod )},
265
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 )},
263
266
},
264
267
wantBackoffQPodNames : []string {"targetpod" },
265
268
wantInFlightPods : []* v1.Pod {pod2 }, // only pod2 is registered because pod is already enqueued back.
@@ -290,16 +293,16 @@ func Test_InFlightPods(t *testing.T) {
290
293
{
291
294
name : "All Pods registered in inFlightPods are enqueued back to activeQ" ,
292
295
isSchedulingQueueHintEnabled : true ,
293
- initialPods : []* v1.Pod {pod , pod2 },
296
+ initialPods : []* v1.Pod {pod1 , pod2 },
294
297
actions : []action {
295
298
// This won't be added to inFlightEvents because no inFlightPods at this point.
296
299
{eventHappens : & framework .PvcAdd },
297
- {podPopped : pod },
300
+ {podPopped : pod1 },
298
301
{eventHappens : & framework .PvAdd },
299
302
{podPopped : pod2 },
300
303
{eventHappens : & framework .NodeAdd },
301
304
// This pod will be requeued to backoffQ because no plugin is registered as unschedulable plugin.
302
- {podEnqueued : newQueuedPodInfoForLookup (pod )},
305
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 )},
303
306
{eventHappens : & framework .CSINodeUpdate },
304
307
// This pod will be requeued to backoffQ because no plugin is registered as unschedulable plugin.
305
308
{podEnqueued : newQueuedPodInfoForLookup (pod2 )},
@@ -338,11 +341,11 @@ func Test_InFlightPods(t *testing.T) {
338
341
{
339
342
name : "One intermediate Pod registered in inFlightPods is enqueued back to activeQ" ,
340
343
isSchedulingQueueHintEnabled : true ,
341
- initialPods : []* v1.Pod {pod , pod2 , pod3 },
344
+ initialPods : []* v1.Pod {pod1 , pod2 , pod3 },
342
345
actions : []action {
343
346
// This won't be added to inFlightEvents because no inFlightPods at this point.
344
347
{eventHappens : & framework .PvcAdd },
345
- {podPopped : pod },
348
+ {podPopped : pod1 },
346
349
{eventHappens : & framework .PvAdd },
347
350
{podPopped : pod2 },
348
351
{eventHappens : & framework .NodeAdd },
@@ -352,8 +355,8 @@ func Test_InFlightPods(t *testing.T) {
352
355
{podEnqueued : newQueuedPodInfoForLookup (pod2 )},
353
356
},
354
357
wantBackoffQPodNames : []string {"targetpod2" },
355
- wantInFlightPods : []* v1.Pod {pod , pod3 },
356
- wantInFlightEvents : []interface {}{pod , framework .PvAdd , framework .NodeAdd , pod3 , framework .AssignedPodAdd },
358
+ wantInFlightPods : []* v1.Pod {pod1 , pod3 },
359
+ wantInFlightEvents : []interface {}{pod1 , framework .PvAdd , framework .NodeAdd , pod3 , framework .AssignedPodAdd },
357
360
queueingHintMap : QueueingHintMapPerProfile {
358
361
"" : {
359
362
framework .PvAdd : {
@@ -379,11 +382,11 @@ func Test_InFlightPods(t *testing.T) {
379
382
},
380
383
{
381
384
name : "pod is enqueued to queue without QueueingHint when SchedulingQueueHint is disabled" ,
382
- initialPods : []* v1.Pod {pod },
385
+ initialPods : []* v1.Pod {pod1 },
383
386
actions : []action {
384
- {podPopped : pod },
387
+ {podPopped : pod1 },
385
388
{eventHappens : & framework .AssignedPodAdd },
386
- {podEnqueued : newQueuedPodInfoForLookup (pod , "fooPlugin1" )},
389
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 , "fooPlugin1" )},
387
390
},
388
391
wantBackoffQPodNames : []string {"targetpod" },
389
392
wantInFlightPods : nil ,
@@ -404,13 +407,13 @@ func Test_InFlightPods(t *testing.T) {
404
407
{
405
408
name : "events before popping Pod are ignored when Pod is enqueued back to queue" ,
406
409
isSchedulingQueueHintEnabled : true ,
407
- initialPods : []* v1.Pod {pod },
410
+ initialPods : []* v1.Pod {pod1 },
408
411
actions : []action {
409
412
{eventHappens : & framework .WildCardEvent },
410
- {podPopped : pod },
413
+ {podPopped : pod1 },
411
414
{eventHappens : & framework .AssignedPodAdd },
412
415
// This Pod won't be requeued to activeQ/backoffQ because fooPlugin1 returns QueueSkip.
413
- {podEnqueued : newQueuedPodInfoForLookup (pod , "fooPlugin1" )},
416
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 , "fooPlugin1" )},
414
417
},
415
418
wantUnschedPodPoolPodNames : []string {"targetpod" },
416
419
wantInFlightPods : nil ,
@@ -431,11 +434,11 @@ func Test_InFlightPods(t *testing.T) {
431
434
{
432
435
name : "pod is enqueued to backoff if no failed plugin" ,
433
436
isSchedulingQueueHintEnabled : true ,
434
- initialPods : []* v1.Pod {pod },
437
+ initialPods : []* v1.Pod {pod1 },
435
438
actions : []action {
436
- {podPopped : pod },
439
+ {podPopped : pod1 },
437
440
{eventHappens : & framework .AssignedPodAdd },
438
- {podEnqueued : newQueuedPodInfoForLookup (pod )},
441
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 )},
439
442
},
440
443
wantBackoffQPodNames : []string {"targetpod" },
441
444
wantInFlightPods : nil ,
@@ -455,11 +458,11 @@ func Test_InFlightPods(t *testing.T) {
455
458
{
456
459
name : "pod is enqueued to unschedulable pod pool if no events that can make the pod schedulable" ,
457
460
isSchedulingQueueHintEnabled : true ,
458
- initialPods : []* v1.Pod {pod },
461
+ initialPods : []* v1.Pod {pod1 },
459
462
actions : []action {
460
- {podPopped : pod },
463
+ {podPopped : pod1 },
461
464
{eventHappens : & framework .NodeAdd },
462
- {podEnqueued : newQueuedPodInfoForLookup (pod , "fooPlugin1" )},
465
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 , "fooPlugin1" )},
463
466
},
464
467
wantUnschedPodPoolPodNames : []string {"targetpod" },
465
468
wantInFlightPods : nil ,
@@ -480,11 +483,11 @@ func Test_InFlightPods(t *testing.T) {
480
483
{
481
484
name : "pod is enqueued to unschedulable pod pool because the failed plugin has a hint fn but it returns Skip" ,
482
485
isSchedulingQueueHintEnabled : true ,
483
- initialPods : []* v1.Pod {pod },
486
+ initialPods : []* v1.Pod {pod1 },
484
487
actions : []action {
485
- {podPopped : pod },
488
+ {podPopped : pod1 },
486
489
{eventHappens : & framework .AssignedPodAdd },
487
- {podEnqueued : newQueuedPodInfoForLookup (pod , "fooPlugin1" )},
490
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 , "fooPlugin1" )},
488
491
},
489
492
wantUnschedPodPoolPodNames : []string {"targetpod" },
490
493
wantInFlightPods : nil ,
@@ -505,12 +508,12 @@ func Test_InFlightPods(t *testing.T) {
505
508
{
506
509
name : "pod is enqueued to activeQ because the Pending plugins has a hint fn and it returns Queue" ,
507
510
isSchedulingQueueHintEnabled : true ,
508
- initialPods : []* v1.Pod {pod },
511
+ initialPods : []* v1.Pod {pod1 },
509
512
actions : []action {
510
- {podPopped : pod },
513
+ {podPopped : pod1 },
511
514
{eventHappens : & framework .AssignedPodAdd },
512
515
{podEnqueued : & framework.QueuedPodInfo {
513
- PodInfo : mustNewPodInfo (pod ),
516
+ PodInfo : mustNewPodInfo (pod1 ),
514
517
UnschedulablePlugins : sets .New ("fooPlugin2" , "fooPlugin3" ),
515
518
PendingPlugins : sets .New ("fooPlugin1" ),
516
519
}},
@@ -541,11 +544,11 @@ func Test_InFlightPods(t *testing.T) {
541
544
{
542
545
name : "pod is enqueued to backoffQ because the failed plugin has a hint fn and it returns Queue" ,
543
546
isSchedulingQueueHintEnabled : true ,
544
- initialPods : []* v1.Pod {pod },
547
+ initialPods : []* v1.Pod {pod1 },
545
548
actions : []action {
546
- {podPopped : pod },
549
+ {podPopped : pod1 },
547
550
{eventHappens : & framework .AssignedPodAdd },
548
- {podEnqueued : newQueuedPodInfoForLookup (pod , "fooPlugin1" , "fooPlugin2" )},
551
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 , "fooPlugin1" , "fooPlugin2" )},
549
552
},
550
553
wantBackoffQPodNames : []string {"targetpod" },
551
554
wantInFlightPods : nil ,
@@ -570,9 +573,9 @@ func Test_InFlightPods(t *testing.T) {
570
573
{
571
574
name : "pod is enqueued to activeQ because the failed plugin has a hint fn and it returns Queue for a concurrent event that was received while some other pod was in flight" ,
572
575
isSchedulingQueueHintEnabled : true ,
573
- initialPods : []* v1.Pod {pod , pod2 },
576
+ initialPods : []* v1.Pod {pod1 , pod2 },
574
577
actions : []action {
575
- {callback : func (t * testing.T , q * PriorityQueue ) { poppedPod = popPod (t , logger , q , pod ) }},
578
+ {callback : func (t * testing.T , q * PriorityQueue ) { poppedPod = popPod (t , logger , q , pod1 ) }},
576
579
{eventHappens : & framework .NodeAdd },
577
580
{callback : func (t * testing.T , q * PriorityQueue ) { poppedPod2 = popPod (t , logger , q , pod2 ) }},
578
581
{eventHappens : & framework .AssignedPodAdd },
@@ -622,9 +625,9 @@ func Test_InFlightPods(t *testing.T) {
622
625
{
623
626
name : "popped pod must have empty UnschedulablePlugins and PendingPlugins" ,
624
627
isSchedulingQueueHintEnabled : true ,
625
- initialPods : []* v1.Pod {pod },
628
+ initialPods : []* v1.Pod {pod1 },
626
629
actions : []action {
627
- {callback : func (t * testing.T , q * PriorityQueue ) { poppedPod = popPod (t , logger , q , pod ) }},
630
+ {callback : func (t * testing.T , q * PriorityQueue ) { poppedPod = popPod (t , logger , q , pod1 ) }},
628
631
{callback : func (t * testing.T , q * PriorityQueue ) {
629
632
logger , _ := ktesting .NewTestContext (t )
630
633
// Unschedulable due to PendingPlugins.
@@ -636,7 +639,7 @@ func Test_InFlightPods(t *testing.T) {
636
639
}},
637
640
{eventHappens : & framework .PvAdd }, // Active again.
638
641
{callback : func (t * testing.T , q * PriorityQueue ) {
639
- poppedPod = popPod (t , logger , q , pod )
642
+ poppedPod = popPod (t , logger , q , pod1 )
640
643
if len (poppedPod .UnschedulablePlugins ) > 0 {
641
644
t .Errorf ("QueuedPodInfo from Pop should have empty UnschedulablePlugins, got instead: %+v" , poppedPod )
642
645
}
@@ -661,6 +664,76 @@ func Test_InFlightPods(t *testing.T) {
661
664
},
662
665
},
663
666
},
667
+ {
668
+ // This scenario shouldn't happen unless we make the similar bug like https://github.com/kubernetes/kubernetes/issues/118226.
669
+ // But, given the bug could make a serious memory leak and likely would be hard to detect,
670
+ // we should have a safe guard from the same bug so that, at least, we can prevent the memory leak.
671
+ name : "Pop is made twice for the same Pod, but the cleanup still happen correctly" ,
672
+ isSchedulingQueueHintEnabled : true ,
673
+ initialPods : []* v1.Pod {pod1 , pod2 },
674
+ actions : []action {
675
+ // This won't be added to inFlightEvents because no inFlightPods at this point.
676
+ {eventHappens : & framework .PvcAdd },
677
+ {podPopped : pod1 },
678
+ {eventHappens : & framework .PvAdd },
679
+ {podPopped : pod2 },
680
+ // Simulate a bug, putting pod into activeQ, while pod is being scheduled.
681
+ {callback : func (t * testing.T , q * PriorityQueue ) {
682
+ q .activeQ .underLock (func (unlocked unlockedActiveQueuer ) {
683
+ unlocked .AddOrUpdate (newQueuedPodInfoForLookup (pod1 ))
684
+ })
685
+ }},
686
+ // At this point, in the activeQ, we have pod1 and pod3 in this order.
687
+ {podCreated : pod3 },
688
+ // pod3 is poped, not pod1.
689
+ // In detail, this Pop() first tries to pop pod1, but it's already being scheduled and hence discarded.
690
+ // Then, it pops the next pod, pod3.
691
+ {podPopped : pod3 },
692
+ {callback : func (t * testing.T , q * PriorityQueue ) {
693
+ // Make sure that pod1 is discarded and hence no pod in activeQ.
694
+ if len (q .activeQ .list ()) != 0 {
695
+ t .Fatalf ("activeQ should be empty, but got: %v" , q .activeQ .list ())
696
+ }
697
+ }},
698
+ {eventHappens : & framework .NodeAdd },
699
+ // This pod will be requeued to backoffQ because no plugin is registered as unschedulable plugin.
700
+ {podEnqueued : newQueuedPodInfoForLookup (pod1 )},
701
+ {eventHappens : & framework .CSINodeUpdate },
702
+ // This pod will be requeued to backoffQ because no plugin is registered as unschedulable plugin.
703
+ {podEnqueued : newQueuedPodInfoForLookup (pod2 )},
704
+ {podEnqueued : newQueuedPodInfoForLookup (pod3 )},
705
+ },
706
+ wantBackoffQPodNames : []string {"targetpod" , "targetpod2" , "targetpod3" },
707
+ wantInFlightPods : nil , // should be empty
708
+ queueingHintMap : QueueingHintMapPerProfile {
709
+ "" : {
710
+ framework .PvAdd : {
711
+ {
712
+ PluginName : "fooPlugin1" ,
713
+ QueueingHintFn : queueHintReturnQueue ,
714
+ },
715
+ },
716
+ framework .NodeAdd : {
717
+ {
718
+ PluginName : "fooPlugin1" ,
719
+ QueueingHintFn : queueHintReturnQueue ,
720
+ },
721
+ },
722
+ framework .PvcAdd : {
723
+ {
724
+ PluginName : "fooPlugin1" ,
725
+ QueueingHintFn : queueHintReturnQueue ,
726
+ },
727
+ },
728
+ framework .CSINodeUpdate : {
729
+ {
730
+ PluginName : "fooPlugin1" ,
731
+ QueueingHintFn : queueHintReturnQueue ,
732
+ },
733
+ },
734
+ },
735
+ },
736
+ },
664
737
}
665
738
666
739
for _ , test := range tests {
@@ -692,6 +765,8 @@ func Test_InFlightPods(t *testing.T) {
692
765
693
766
for _ , action := range test .actions {
694
767
switch {
768
+ case action .podCreated != nil :
769
+ q .Add (logger , action .podCreated )
695
770
case action .podPopped != nil :
696
771
popPod (t , logger , q , action .podPopped )
697
772
case action .eventHappens != nil :
0 commit comments