]> git.feebdaed.xyz Git - 0xmirror/kubernetes.git/commitdiff
Scheduler: Fix GatedPods metric desync in unschedulable queue
authorVlad Shkrabkov <vshkrabkov@google.com>
Thu, 20 Nov 2025 11:21:44 +0000 (11:21 +0000)
committerVlad Shkrabkov <vshkrabkov@google.com>
Mon, 15 Dec 2025 11:47:22 +0000 (11:47 +0000)
Previously, when a Pod residing in the 'unschedulablePods' queue was updated and subsequently rejected by PreEnqueue plugins (returning 'Wait'), the logic in 'moveToActiveQ' would return early because the Pod was already present in the queue.

This caused the 'scheduler_gated_pods_total' metric to fail to increment, leading to metric inconsistencies (and potentially negative values upon Pod deletion).

This change adds a check to detect the transition from Ungated to Gated. If detected, the Pod is removed and re-added to the queue to ensure metrics are correctly swapped (Unschedulable-- and Gated++).

Added regression test 'TestSchedulingQueueMetrics_UngatedToGated' to verify the fix.

Signed-off-by: Vlad Shkrabkov <vshkrabkov@google.com>
pkg/scheduler/backend/queue/scheduling_queue.go
pkg/scheduler/backend/queue/scheduling_queue_test.go
pkg/scheduler/backend/queue/unschedulable_pods.go
pkg/scheduler/backend/queue/unschedulable_pods_test.go

index 717b55656f142c39ad0e2f9974788c12b42f1758..b264aa94c396094d26a811a378338cb80dc9f106 100644 (file)
@@ -655,11 +655,11 @@ func (p *PriorityQueue) moveToActiveQ(logger klog.Logger, pInfo *framework.Queue
                        if p.backoffQ.has(pInfo) {
                                return
                        }
-                       if p.unschedulablePods.get(pInfo.Pod) != nil {
-                               return
+
+                       if p.unschedulablePods.get(pInfo.Pod) == nil {
+                               logger.V(5).Info("Pod moved to an internal scheduling queue, because the pod is gated", "pod", klog.KObj(pInfo.Pod), "event", event, "queue", unschedulableQ)
                        }
-                       p.unschedulablePods.addOrUpdate(pInfo, event)
-                       logger.V(5).Info("Pod moved to an internal scheduling queue, because the pod is gated", "pod", klog.KObj(pInfo.Pod), "event", event, "queue", unschedulableQ)
+                       p.unschedulablePods.addOrUpdate(pInfo, gatedBefore, event)
                        return
                }
                if pInfo.InitialAttemptTimestamp == nil {
@@ -690,9 +690,9 @@ func (p *PriorityQueue) moveToBackoffQ(logger klog.Logger, pInfo *framework.Queu
                p.runPreEnqueuePlugins(context.Background(), pInfo)
                if pInfo.Gated() {
                        if p.unschedulablePods.get(pInfo.Pod) == nil {
-                               p.unschedulablePods.addOrUpdate(pInfo, event)
                                logger.V(5).Info("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", event, "queue", unschedulableQ)
                        }
+                       p.unschedulablePods.addOrUpdate(pInfo, gatedBefore, event)
                        return false
                }
        }
@@ -850,7 +850,7 @@ func (p *PriorityQueue) addUnschedulableWithoutQueueingHint(logger klog.Logger,
                        }
                }
        } else {
-               p.unschedulablePods.addOrUpdate(pInfo, framework.ScheduleAttemptFailure)
+               p.unschedulablePods.addOrUpdate(pInfo, false /* the Pod was absent from all queues */, framework.ScheduleAttemptFailure)
                logger.V(5).Info("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", framework.ScheduleAttemptFailure, "queue", unschedulableQ)
        }
 
@@ -1100,7 +1100,8 @@ func (p *PriorityQueue) Update(logger klog.Logger, oldPod, newPod *v1.Pod) {
                }
 
                // Pod update didn't make it schedulable, keep it in the unschedulable queue.
-               p.unschedulablePods.addOrUpdate(pInfo, framework.EventUnscheduledPodUpdate.Label())
+               // Use pInfo.Gated() to avoid double-counting "Gated" metrics during an in-place update.
+               p.unschedulablePods.addOrUpdate(pInfo, pInfo.Gated(), framework.EventUnscheduledPodUpdate.Label())
                return
        }
        // If pod is not in any of the queues, we put it in the active queue.
@@ -1192,7 +1193,8 @@ func (p *PriorityQueue) MoveAllToActiveOrBackoffQueue(logger klog.Logger, event
 // NOTE: this function assumes lock has been acquired in caller
 func (p *PriorityQueue) requeuePodWithQueueingStrategy(logger klog.Logger, pInfo *framework.QueuedPodInfo, strategy queueingStrategy, event string) string {
        if strategy == queueSkip {
-               p.unschedulablePods.addOrUpdate(pInfo, event)
+               // Current Gate status is required for already exisiting pods. For new pods, this parameter is ignored/unused by addOrUpdate.
+               p.unschedulablePods.addOrUpdate(pInfo, pInfo.Gated(), event)
                return unschedulableQ
        }
 
index 505d2bbe8b99a53acaf701a223fa72fe07c46758..4c24d21693e0642869ea6a8448e7f245a7c68221 100644 (file)
@@ -1103,7 +1103,7 @@ func TestPriorityQueue_Pop(t *testing.T) {
                        q.backoffQ.add(logger, errorBackoffPodInfo, framework.EventUnscheduledPodAdd.Label())
                        // Add pod to the unschedulablePods
                        unschedulablePodInfo := q.newQueuedPodInfo(unschedulablePodInfo.Pod, "plugin")
-                       q.unschedulablePods.addOrUpdate(unschedulablePodInfo, framework.EventUnscheduledPodAdd.Label())
+                       q.unschedulablePods.addOrUpdate(unschedulablePodInfo, false, framework.EventUnscheduledPodAdd.Label())
 
                        var gotPods []string
                        for i := 0; i < len(tt.wantPods)+1; i++ {
@@ -1192,13 +1192,13 @@ func TestPriorityQueue_Update(t *testing.T) {
                        schedulingHintsEnablement: []bool{false, true},
                },
                {
-                       name:  "when updating a pod which is in unschedulable queue and is backing off, it will be moved to backoff queue",
+                       name:  "when updating a pod in unschedulablePods, if its backoff timer has not yet expired, it moves to backoffQ",
                        wantQ: backoffQ,
                        prepareFunc: func(t *testing.T, logger klog.Logger, q *PriorityQueue) (oldPod, newPod *v1.Pod) {
                                pInfo := q.newQueuedPodInfo(medPriorityPodInfo.Pod, queuePlugin)
                                // needs to increment to make the pod backing off
                                pInfo.UnschedulableCount++
-                               q.unschedulablePods.addOrUpdate(pInfo, framework.EventUnscheduledPodAdd.Label())
+                               q.unschedulablePods.addOrUpdate(pInfo, false, framework.EventUnscheduledPodAdd.Label())
                                updatedPod := medPriorityPodInfo.Pod.DeepCopy()
                                updatedPod.Annotations["foo"] = "test"
                                return medPriorityPodInfo.Pod, updatedPod
@@ -1206,13 +1206,13 @@ func TestPriorityQueue_Update(t *testing.T) {
                        schedulingHintsEnablement: []bool{false, true},
                },
                {
-                       name:  "when updating a pod which is in unschedulable queue and is not backing off, it will be moved to active queue",
+                       name:  "when updating a pod in unschedulablePods, if its backoff timer has expired, it moves to activeQ",
                        wantQ: activeQ,
                        prepareFunc: func(t *testing.T, logger klog.Logger, q *PriorityQueue) (oldPod, newPod *v1.Pod) {
                                pInfo := q.newQueuedPodInfo(medPriorityPodInfo.Pod, queuePlugin)
                                // needs to increment to make the pod backing off
                                pInfo.UnschedulableCount++
-                               q.unschedulablePods.addOrUpdate(pInfo, framework.EventUnscheduledPodAdd.Label())
+                               q.unschedulablePods.addOrUpdate(pInfo, false, framework.EventUnscheduledPodAdd.Label())
                                updatedPod := medPriorityPodInfo.Pod.DeepCopy()
                                updatedPod.Annotations["foo"] = "test1"
                                // Move clock by podMaxBackoffDuration, so that pods in the unschedulablePods would pass the backing off,
@@ -1223,10 +1223,10 @@ func TestPriorityQueue_Update(t *testing.T) {
                        schedulingHintsEnablement: []bool{false, true},
                },
                {
-                       name:  "when updating a pod which is in unschedulable pods but the plugin returns skip, it will remain in unschedulablePods",
+                       name:  "when updating a pod in unschedulablePods, if the scheduling hint returns QueueSkip, it remains in unschedulablePods",
                        wantQ: unschedulableQ,
                        prepareFunc: func(t *testing.T, logger klog.Logger, q *PriorityQueue) (oldPod, newPod *v1.Pod) {
-                               q.unschedulablePods.addOrUpdate(q.newQueuedPodInfo(medPriorityPodInfo.Pod, skipPlugin), framework.EventUnscheduledPodAdd.Label())
+                               q.unschedulablePods.addOrUpdate(q.newQueuedPodInfo(medPriorityPodInfo.Pod, skipPlugin), false, framework.EventUnscheduledPodAdd.Label())
                                updatedPod := medPriorityPodInfo.Pod.DeepCopy()
                                updatedPod.Annotations["foo"] = "test1"
                                return medPriorityPodInfo.Pod, updatedPod
@@ -1478,7 +1478,7 @@ func TestPriorityQueue_Activate(t *testing.T) {
                        }
 
                        for _, qPodInfo := range tt.qPodInfoInUnschedulablePods {
-                               q.unschedulablePods.addOrUpdate(qPodInfo, framework.EventUnscheduledPodAdd.Label())
+                               q.unschedulablePods.addOrUpdate(qPodInfo, false, framework.EventUnscheduledPodAdd.Label())
                        }
 
                        for _, qPodInfo := range tt.qPodInfoInBackoffQ {
@@ -3171,7 +3171,7 @@ var (
                        // needs to increment it to make it backoff
                        pInfo.UnschedulableCount++
                }
-               queue.unschedulablePods.addOrUpdate(pInfo, framework.EventUnscheduledPodAdd.Label())
+               queue.unschedulablePods.addOrUpdate(pInfo, false, framework.EventUnscheduledPodAdd.Label())
        }
        deletePod = func(t *testing.T, _ klog.Logger, queue *PriorityQueue, pInfo *framework.QueuedPodInfo) {
                queue.Delete(pInfo.Pod)
@@ -3198,6 +3198,12 @@ var (
                queue.clock.(*testingclock.FakeClock).Step(queue.podMaxInUnschedulablePodsDuration)
                queue.flushUnschedulablePodsLeftover(logger)
        }
+       updatePluginToGateAllPods = func(t *testing.T, logger klog.Logger, queue *PriorityQueue, _ *framework.QueuedPodInfo) {
+               queue.preEnqueuePluginMap[""]["preEnqueuePlugin"] = &preEnqueuePlugin{allowlists: []string{""}}
+       }
+       updatePluginToUngateAllPods = func(t *testing.T, logger klog.Logger, queue *PriorityQueue, _ *framework.QueuedPodInfo) {
+               queue.preEnqueuePluginMap[""]["preEnqueuePlugin"] = &preEnqueuePlugin{allowlists: []string{"queueable"}}
+       }
 )
 
 // TestPodTimestamp tests the operations related to QueuedPodInfo.
@@ -3328,6 +3334,7 @@ func TestPendingPodsMetric(t *testing.T) {
                operands                   [][]*framework.QueuedPodInfo
                metricsName                string
                pluginMetricsSamplePercent int
+               disablePopFromBackoffQ     bool
                wants                      string
        }{
                {
@@ -3543,6 +3550,165 @@ scheduler_plugin_execution_duration_seconds_sum{extension_point="PreEnqueue",plu
 scheduler_plugin_execution_duration_seconds_count{extension_point="PreEnqueue",plugin="preEnqueuePlugin",status="Success"} 1
 `, // the observed value will always be 0, because we don't proceed the fake clock.
                },
+               {
+                       name: "Gated metric should be 1 when Ungated to Gated transition into moveToActiveQ",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               moveClockForward,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               {nil},
+                               pInfos[:1],
+                       },
+                       metricsName:                "scheduler_pending_pods",
+                       pluginMetricsSamplePercent: 100,
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 0
+scheduler_pending_pods{queue="backoff"} 0
+scheduler_pending_pods{queue="gated"} 1
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
+               {
+                       name: "Gated metric should be 1 when Ungated to Gated transition into moveToBackoffQ",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               pInfos[:1],
+                       },
+                       metricsName:                "scheduler_pending_pods",
+                       pluginMetricsSamplePercent: 100,
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 0
+scheduler_pending_pods{queue="backoff"} 0
+scheduler_pending_pods{queue="gated"} 1
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
+               {
+                       name: "Gated metric should be 1 when Ungated to Gated transition when popFromBackoffQ is disabled",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               moveClockForward,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               {nil},
+                               pInfos[:1],
+                       },
+                       metricsName:                "scheduler_pending_pods",
+                       pluginMetricsSamplePercent: 100,
+                       disablePopFromBackoffQ:     true,
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 0
+scheduler_pending_pods{queue="backoff"} 0
+scheduler_pending_pods{queue="gated"} 1
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
+               {
+                       name: "Gated metric should be 0 when Ungated -> Gated -> Ungated (ActiveQ) transition",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               moveClockForward,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                               updatePluginToUngateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               {nil},
+                               pInfos[:1],
+                               {nil},
+                               pInfos[:1],
+                       },
+                       pluginMetricsSamplePercent: 100,
+                       metricsName:                "scheduler_pending_pods",
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 1
+scheduler_pending_pods{queue="backoff"} 0
+scheduler_pending_pods{queue="gated"} 0
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
+               {
+                       name: "Gated metric should be 0 when Ungated -> Gated -> Ungated (BackoffQ) transition",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                               updatePluginToUngateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               pInfos[:1],
+                               {nil},
+                               pInfos[:1],
+                       },
+                       pluginMetricsSamplePercent: 100,
+                       metricsName:                "scheduler_pending_pods",
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 0
+scheduler_pending_pods{queue="backoff"} 1
+scheduler_pending_pods{queue="gated"} 0
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
+               {
+                       name: "Gated metric should be 0 when Ungated -> Gated -> Ungated transition, when popFromBackoffQ is disabled",
+                       operations: []operation{
+                               addPodUnschedulablePods,
+                               moveClockForward,
+                               updatePluginToGateAllPods,
+                               updatePodQueueable,
+                               updatePluginToUngateAllPods,
+                               updatePodQueueable,
+                       },
+                       operands: [][]*framework.QueuedPodInfo{
+                               pInfos[:1],
+                               {nil},
+                               {nil},
+                               pInfos[:1],
+                               {nil},
+                               pInfos[:1],
+                       },
+                       pluginMetricsSamplePercent: 100,
+                       disablePopFromBackoffQ:     true,
+                       wants: `
+# 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 unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
+# TYPE scheduler_pending_pods gauge
+scheduler_pending_pods{queue="active"} 1
+scheduler_pending_pods{queue="backoff"} 0
+scheduler_pending_pods{queue="gated"} 0
+scheduler_pending_pods{queue="unschedulable"} 0
+`,
+               },
        }
 
        resetMetrics := func() {
@@ -3571,6 +3737,7 @@ scheduler_plugin_execution_duration_seconds_count{extension_point="PreEnqueue",p
                        preenq := map[string]map[string]fwk.PreEnqueuePlugin{"": {(&preEnqueuePlugin{}).Name(): &preEnqueuePlugin{allowlists: []string{queueable}}}}
                        recorder := metrics.NewMetricsAsyncRecorder(3, 20*time.Microsecond, ctx.Done())
                        queue := NewTestQueue(ctx, newDefaultQueueSort(), WithClock(testingclock.NewFakeClock(timestamp)), WithPreEnqueuePluginMap(preenq), WithPluginMetricsSamplePercent(test.pluginMetricsSamplePercent), WithMetricsRecorder(recorder), WithQueueingHintMapPerProfile(m))
+                       queue.isPopFromBackoffQEnabled = !test.disablePopFromBackoffQ
                        for i, op := range test.operations {
                                for _, pInfo := range test.operands[i] {
                                        op(t, logger, queue, pInfo)
@@ -4355,7 +4522,7 @@ func TestPriorityQueue_GetPod(t *testing.T) {
                unlockedActiveQ.add(logger, newQueuedPodInfoForLookup(activeQPod), framework.EventUnscheduledPodAdd.Label())
        })
        q.backoffQ.add(logger, newQueuedPodInfoForLookup(backoffQPod), framework.EventUnscheduledPodAdd.Label())
-       q.unschedulablePods.addOrUpdate(newQueuedPodInfoForLookup(unschedPod), framework.EventUnscheduledPodAdd.Label())
+       q.unschedulablePods.addOrUpdate(newQueuedPodInfoForLookup(unschedPod), false, framework.EventUnscheduledPodAdd.Label())
 
        tests := []struct {
                name        string
index 4c248bfcd5646e2332f291470b713d7ddd01c89a..a66b6a826ba7af9a4aef81c4edf15d8f8f265344 100644 (file)
@@ -43,11 +43,39 @@ func newUnschedulablePods(unschedulableRecorder, gatedRecorder metrics.MetricRec
        }
 }
 
+// updateMetricsOnStateChange handles the metric accounting when a pod changes
+// between Gated and Unschedulable states.
+func (u *unschedulablePods) updateMetricsOnStateChange(gatedBefore, isGated bool) {
+       if gatedBefore == isGated {
+               return
+       }
+
+       if gatedBefore {
+               // Transition: Gated -> Ungated
+               if u.gatedRecorder != nil {
+                       u.gatedRecorder.Dec()
+               }
+               if u.unschedulableRecorder != nil {
+                       u.unschedulableRecorder.Inc()
+               }
+       } else {
+               // Transition: Ungated -> Gated
+               if u.unschedulableRecorder != nil {
+                       u.unschedulableRecorder.Dec()
+               }
+               if u.gatedRecorder != nil {
+                       u.gatedRecorder.Inc()
+               }
+       }
+}
+
 // addOrUpdate adds a pod to the unschedulable podInfoMap.
 // The event should show which event triggered the addition and is used for the metric recording.
-func (u *unschedulablePods) addOrUpdate(pInfo *framework.QueuedPodInfo, event string) {
+func (u *unschedulablePods) addOrUpdate(pInfo *framework.QueuedPodInfo, gatedBefore bool, event string) {
        podID := u.keyFunc(pInfo.Pod)
-       if _, exists := u.podInfoMap[podID]; !exists {
+       if _, exists := u.podInfoMap[podID]; exists {
+               u.updateMetricsOnStateChange(gatedBefore, pInfo.Gated())
+       } else {
                if pInfo.Gated() && u.gatedRecorder != nil {
                        u.gatedRecorder.Inc()
                } else if !pInfo.Gated() && u.unschedulableRecorder != nil {
index c1e126ed8eb060804b994eee25692c4f8162e732..fe1771e68d3ad6b49cc554db732d51d1bf01c6dd 100644 (file)
@@ -109,7 +109,7 @@ func TestUnschedulablePods(t *testing.T) {
                t.Run(test.name, func(t *testing.T) {
                        upm := newUnschedulablePods(nil, nil)
                        for _, p := range test.podsToAdd {
-                               upm.addOrUpdate(newQueuedPodInfoForLookup(p), framework.EventUnscheduledPodAdd.Label())
+                               upm.addOrUpdate(newQueuedPodInfoForLookup(p), false, framework.EventUnscheduledPodAdd.Label())
                        }
                        if diff := cmp.Diff(test.expectedMapAfterAdd, upm.podInfoMap, cmpopts.IgnoreUnexported(framework.PodInfo{})); diff != "" {
                                t.Errorf("Unexpected map after adding pods(-want, +got):\n%s", diff)
@@ -117,7 +117,7 @@ func TestUnschedulablePods(t *testing.T) {
 
                        if len(test.podsToUpdate) > 0 {
                                for _, p := range test.podsToUpdate {
-                                       upm.addOrUpdate(newQueuedPodInfoForLookup(p), framework.EventUnscheduledPodUpdate.Label())
+                                       upm.addOrUpdate(newQueuedPodInfoForLookup(p), false, framework.EventUnscheduledPodUpdate.Label())
                                }
                                if diff := cmp.Diff(test.expectedMapAfterUpdate, upm.podInfoMap, cmpopts.IgnoreUnexported(framework.PodInfo{})); diff != "" {
                                        t.Errorf("Unexpected map after updating pods (-want, +got):\n%s", diff)