sigs.k8s.io/kueue@v0.6.2/pkg/queue/cluster_queue_impl_test.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package queue
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/google/go-cmp/cmp/cmpopts"
    26  	corev1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/labels"
    29  	testingclock "k8s.io/utils/clock/testing"
    30  	"k8s.io/utils/ptr"
    31  
    32  	config "sigs.k8s.io/kueue/apis/config/v1beta1"
    33  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    34  	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
    35  	"sigs.k8s.io/kueue/pkg/workload"
    36  )
    37  
    38  const (
    39  	defaultNamespace = "default"
    40  )
    41  
    42  var (
    43  	defaultQueueOrderingFunc = queueOrderingFunc(workload.Ordering{
    44  		PodsReadyRequeuingTimestamp: config.EvictionTimestamp,
    45  	})
    46  )
    47  
    48  func Test_PushOrUpdate(t *testing.T) {
    49  	now := time.Now()
    50  	minuteLater := now.Add(time.Minute)
    51  	fakeClock := testingclock.NewFakeClock(now)
    52  	cmpOpts := []cmp.Option{
    53  		cmpopts.EquateEmpty(),
    54  		cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime"),
    55  	}
    56  	wlBase := utiltesting.MakeWorkload("workload-1", defaultNamespace).Clone()
    57  
    58  	cases := map[string]struct {
    59  		workload                  *utiltesting.WorkloadWrapper
    60  		wantWorkload              *workload.Info
    61  		wantInAdmissibleWorkloads map[string]*workload.Info
    62  	}{
    63  		"workload doesn't have re-queue state": {
    64  			workload:     wlBase.Clone(),
    65  			wantWorkload: workload.NewInfo(wlBase.Clone().ResourceVersion("1").Obj()),
    66  		},
    67  		"workload is still under the backoff waiting time": {
    68  			workload: wlBase.Clone().
    69  				RequeueState(ptr.To[int32](10), ptr.To(metav1.NewTime(minuteLater))).
    70  				Condition(metav1.Condition{
    71  					Type:   kueue.WorkloadEvicted,
    72  					Reason: kueue.WorkloadEvictedByPodsReadyTimeout,
    73  					Status: metav1.ConditionTrue,
    74  				}),
    75  			wantInAdmissibleWorkloads: map[string]*workload.Info{
    76  				"default/workload-1": workload.NewInfo(wlBase.Clone().
    77  					ResourceVersion("1").
    78  					RequeueState(ptr.To[int32](10), ptr.To(metav1.NewTime(minuteLater))).
    79  					Condition(metav1.Condition{
    80  						Type:   kueue.WorkloadEvicted,
    81  						Reason: kueue.WorkloadEvictedByPodsReadyTimeout,
    82  						Status: metav1.ConditionTrue,
    83  					}).
    84  					Obj()),
    85  			},
    86  		},
    87  	}
    88  	for name, tc := range cases {
    89  		t.Run(name, func(t *testing.T) {
    90  			cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, fakeClock)
    91  
    92  			if cq.Pending() != 0 {
    93  				t.Error("ClusterQueue should be empty")
    94  			}
    95  			cq.PushOrUpdate(workload.NewInfo(tc.workload.Clone().Obj()))
    96  			if cq.Pending() != 1 {
    97  				t.Error("ClusterQueue should have one workload")
    98  			}
    99  
   100  			// Just used to validate the update operation.
   101  			updatedWl := tc.workload.Clone().ResourceVersion("1").Obj()
   102  			cq.PushOrUpdate(workload.NewInfo(updatedWl))
   103  			newWl := cq.Pop()
   104  			if newWl != nil && cq.Pending() != 0 {
   105  				t.Error("failed to update a workload in ClusterQueue")
   106  			}
   107  			if diff := cmp.Diff(tc.wantWorkload, newWl, cmpOpts...); len(diff) != 0 {
   108  				t.Errorf("Unexpectd workloads in heap (-want,+got):\n%s", diff)
   109  			}
   110  			if diff := cmp.Diff(tc.wantInAdmissibleWorkloads, cq.inadmissibleWorkloads, cmpOpts...); len(diff) != 0 {
   111  				t.Errorf("Unexpectd inadmissibleWorkloads (-want,+got):\n%s", diff)
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func Test_Pop(t *testing.T) {
   118  	now := time.Now()
   119  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(now))
   120  	wl1 := workload.NewInfo(utiltesting.MakeWorkload("workload-1", defaultNamespace).Creation(now).Obj())
   121  	wl2 := workload.NewInfo(utiltesting.MakeWorkload("workload-2", defaultNamespace).Creation(now.Add(time.Second)).Obj())
   122  	if cq.Pop() != nil {
   123  		t.Error("ClusterQueue should be empty")
   124  	}
   125  	cq.PushOrUpdate(wl1)
   126  	cq.PushOrUpdate(wl2)
   127  	newWl := cq.Pop()
   128  	if newWl == nil || newWl.Obj.Name != "workload-1" {
   129  		t.Error("failed to Pop workload")
   130  	}
   131  	newWl = cq.Pop()
   132  	if newWl == nil || newWl.Obj.Name != "workload-2" {
   133  		t.Error("failed to Pop workload")
   134  	}
   135  	if cq.Pop() != nil {
   136  		t.Error("ClusterQueue should be empty")
   137  	}
   138  }
   139  
   140  func Test_Delete(t *testing.T) {
   141  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(time.Now()))
   142  	wl1 := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
   143  	wl2 := utiltesting.MakeWorkload("workload-2", defaultNamespace).Obj()
   144  	cq.PushOrUpdate(workload.NewInfo(wl1))
   145  	cq.PushOrUpdate(workload.NewInfo(wl2))
   146  	if cq.Pending() != 2 {
   147  		t.Error("ClusterQueue should have two workload")
   148  	}
   149  	cq.Delete(wl1)
   150  	if cq.Pending() != 1 {
   151  		t.Error("ClusterQueue should have only one workload")
   152  	}
   153  	// Change workload item, ClusterQueue.Delete should only care about the namespace and name.
   154  	wl2.Spec = kueue.WorkloadSpec{QueueName: "default"}
   155  	cq.Delete(wl2)
   156  	if cq.Pending() != 0 {
   157  		t.Error("ClusterQueue should have be empty")
   158  	}
   159  }
   160  
   161  func Test_Info(t *testing.T) {
   162  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(time.Now()))
   163  	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
   164  	if info := cq.Info(keyFunc(workload.NewInfo(wl))); info != nil {
   165  		t.Error("workload doesn't exist")
   166  	}
   167  	cq.PushOrUpdate(workload.NewInfo(wl))
   168  	if info := cq.Info(keyFunc(workload.NewInfo(wl))); info == nil {
   169  		t.Error("expected workload to exist")
   170  	}
   171  }
   172  
   173  func Test_AddFromLocalQueue(t *testing.T) {
   174  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(time.Now()))
   175  	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
   176  	queue := &LocalQueue{
   177  		items: map[string]*workload.Info{
   178  			wl.Name: workload.NewInfo(wl),
   179  		},
   180  	}
   181  	cq.PushOrUpdate(workload.NewInfo(wl))
   182  	if added := cq.AddFromLocalQueue(queue); added {
   183  		t.Error("expected workload not to be added")
   184  	}
   185  	cq.Delete(wl)
   186  	if added := cq.AddFromLocalQueue(queue); !added {
   187  		t.Error("workload should be added to the ClusterQueue")
   188  	}
   189  }
   190  
   191  func Test_DeleteFromLocalQueue(t *testing.T) {
   192  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(time.Now()))
   193  	q := utiltesting.MakeLocalQueue("foo", "").ClusterQueue("cq").Obj()
   194  	qImpl := newLocalQueue(q)
   195  	wl1 := utiltesting.MakeWorkload("wl1", "").Queue(q.Name).Obj()
   196  	wl2 := utiltesting.MakeWorkload("wl2", "").Queue(q.Name).Obj()
   197  	wl3 := utiltesting.MakeWorkload("wl3", "").Queue(q.Name).Obj()
   198  	wl4 := utiltesting.MakeWorkload("wl4", "").Queue(q.Name).Obj()
   199  	admissibleworkloads := []*kueue.Workload{wl1, wl2}
   200  	inadmissibleWorkloads := []*kueue.Workload{wl3, wl4}
   201  
   202  	for _, w := range admissibleworkloads {
   203  		wInfo := workload.NewInfo(w)
   204  		cq.PushOrUpdate(wInfo)
   205  		qImpl.AddOrUpdate(wInfo)
   206  	}
   207  
   208  	for _, w := range inadmissibleWorkloads {
   209  		wInfo := workload.NewInfo(w)
   210  		cq.requeueIfNotPresent(wInfo, false)
   211  		qImpl.AddOrUpdate(wInfo)
   212  	}
   213  
   214  	wantPending := len(admissibleworkloads) + len(inadmissibleWorkloads)
   215  	if pending := cq.Pending(); pending != wantPending {
   216  		t.Errorf("clusterQueue's workload number not right, want %v, got %v", wantPending, pending)
   217  	}
   218  	if len(cq.inadmissibleWorkloads) != len(inadmissibleWorkloads) {
   219  		t.Errorf("clusterQueue's workload number in inadmissibleWorkloads not right, want %v, got %v", len(inadmissibleWorkloads), len(cq.inadmissibleWorkloads))
   220  	}
   221  
   222  	cq.DeleteFromLocalQueue(qImpl)
   223  	if cq.Pending() != 0 {
   224  		t.Error("clusterQueue should be empty")
   225  	}
   226  }
   227  
   228  func TestClusterQueueImpl(t *testing.T) {
   229  	cl := utiltesting.NewFakeClient(
   230  		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ns1", Labels: map[string]string{"dep": "eng"}}},
   231  		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ns2", Labels: map[string]string{"dep": "sales"}}},
   232  		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ns3", Labels: map[string]string{"dep": "marketing"}}},
   233  	)
   234  
   235  	now := time.Now()
   236  	minuteLater := now.Add(time.Minute)
   237  	fakeClock := testingclock.NewFakeClock(now)
   238  
   239  	var workloads = []*kueue.Workload{
   240  		utiltesting.MakeWorkload("w1", "ns1").Queue("q1").Obj(),
   241  		utiltesting.MakeWorkload("w2", "ns2").Queue("q2").Obj(),
   242  		utiltesting.MakeWorkload("w3", "ns3").Queue("q3").Obj(),
   243  		utiltesting.MakeWorkload("w4-requeue-state", "ns1").
   244  			RequeueState(ptr.To[int32](1), ptr.To(metav1.NewTime(minuteLater))).
   245  			Queue("q1").
   246  			Condition(metav1.Condition{
   247  				Type:   kueue.WorkloadEvicted,
   248  				Reason: kueue.WorkloadEvictedByPodsReadyTimeout,
   249  				Status: metav1.ConditionTrue,
   250  			}).
   251  			Obj(),
   252  	}
   253  	var updatedWorkloads = make([]*kueue.Workload, len(workloads))
   254  
   255  	updatedWorkloads[0] = workloads[0].DeepCopy()
   256  	updatedWorkloads[0].Spec.QueueName = "q2"
   257  	updatedWorkloads[1] = workloads[1].DeepCopy()
   258  	updatedWorkloads[1].Spec.QueueName = "q1"
   259  
   260  	tests := map[string]struct {
   261  		workloadsToAdd                    []*kueue.Workload
   262  		inadmissibleWorkloadsToRequeue    []*workload.Info
   263  		admissibleWorkloadsToRequeue      []*workload.Info
   264  		workloadsToUpdate                 []*kueue.Workload
   265  		workloadsToDelete                 []*kueue.Workload
   266  		queueInadmissibleWorkloads        bool
   267  		wantActiveWorkloads               []string
   268  		wantPending                       int
   269  		wantInadmissibleWorkloadsRequeued bool
   270  	}{
   271  		"add, update, delete workload": {
   272  			workloadsToAdd:                 []*kueue.Workload{workloads[0], workloads[1], workloads[3]},
   273  			inadmissibleWorkloadsToRequeue: []*workload.Info{},
   274  			workloadsToUpdate:              []*kueue.Workload{updatedWorkloads[0]},
   275  			workloadsToDelete:              []*kueue.Workload{workloads[0]},
   276  			wantActiveWorkloads:            []string{workload.Key(workloads[1])},
   277  			wantPending:                    2,
   278  		},
   279  		"re-queue inadmissible workload; workloads with requeueState can't re-queue": {
   280  			workloadsToAdd:                 []*kueue.Workload{workloads[0]},
   281  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1]), workload.NewInfo(workloads[3])},
   282  			wantActiveWorkloads:            []string{workload.Key(workloads[0])},
   283  			wantPending:                    3,
   284  		},
   285  		"re-queue admissible workload that was inadmissible": {
   286  			workloadsToAdd:                 []*kueue.Workload{workloads[0]},
   287  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1]), workload.NewInfo(workloads[3])},
   288  			admissibleWorkloadsToRequeue:   []*workload.Info{workload.NewInfo(workloads[1]), workload.NewInfo(workloads[3])},
   289  			wantActiveWorkloads:            []string{workload.Key(workloads[0]), workload.Key(workloads[1])},
   290  			wantPending:                    3,
   291  		},
   292  		"re-queue inadmissible workload and flush": {
   293  			workloadsToAdd:                    []*kueue.Workload{workloads[0]},
   294  			inadmissibleWorkloadsToRequeue:    []*workload.Info{workload.NewInfo(workloads[1]), workload.NewInfo(workloads[3])},
   295  			queueInadmissibleWorkloads:        true,
   296  			wantActiveWorkloads:               []string{workload.Key(workloads[0]), workload.Key(workloads[1])},
   297  			wantPending:                       3,
   298  			wantInadmissibleWorkloadsRequeued: true,
   299  		},
   300  		"avoid re-queueing inadmissible workloads not matching namespace selector": {
   301  			workloadsToAdd:                 []*kueue.Workload{workloads[0]},
   302  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[2])},
   303  			queueInadmissibleWorkloads:     true,
   304  			wantActiveWorkloads:            []string{workload.Key(workloads[0])},
   305  			wantPending:                    2,
   306  		},
   307  		"update inadmissible workload": {
   308  			workloadsToAdd:                 []*kueue.Workload{workloads[0]},
   309  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1])},
   310  			workloadsToUpdate:              []*kueue.Workload{updatedWorkloads[1]},
   311  			wantActiveWorkloads:            []string{workload.Key(workloads[0]), workload.Key(workloads[1])},
   312  			wantPending:                    2,
   313  		},
   314  		"delete inadmissible workload": {
   315  			workloadsToAdd:                 []*kueue.Workload{workloads[0]},
   316  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1])},
   317  			workloadsToDelete:              []*kueue.Workload{workloads[1]},
   318  			queueInadmissibleWorkloads:     true,
   319  			wantActiveWorkloads:            []string{workload.Key(workloads[0])},
   320  			wantPending:                    1,
   321  		},
   322  		"update inadmissible workload without changes": {
   323  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1])},
   324  			workloadsToUpdate:              []*kueue.Workload{workloads[1]},
   325  			wantPending:                    1,
   326  		},
   327  		"requeue inadmissible workload twice": {
   328  			inadmissibleWorkloadsToRequeue: []*workload.Info{workload.NewInfo(workloads[1]), workload.NewInfo(workloads[1])},
   329  			wantPending:                    1,
   330  		},
   331  		"update reclaimable pods in inadmissible": {
   332  			inadmissibleWorkloadsToRequeue: []*workload.Info{
   333  				workload.NewInfo(utiltesting.MakeWorkload("w", "").PodSets(*utiltesting.MakePodSet("main", 1).Request(corev1.ResourceCPU, "1").Obj()).Obj()),
   334  			},
   335  			workloadsToUpdate: []*kueue.Workload{
   336  				utiltesting.MakeWorkload("w", "").PodSets(*utiltesting.MakePodSet("main", 2).Request(corev1.ResourceCPU, "1").Obj()).
   337  					ReclaimablePods(kueue.ReclaimablePod{Name: "main", Count: 1}).
   338  					Obj(),
   339  			},
   340  			wantActiveWorkloads: []string{"/w"},
   341  			wantPending:         1,
   342  		},
   343  	}
   344  
   345  	for name, test := range tests {
   346  		t.Run(name, func(t *testing.T) {
   347  			cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, fakeClock)
   348  			err := cq.Update(utiltesting.MakeClusterQueue("cq").
   349  				NamespaceSelector(&metav1.LabelSelector{
   350  					MatchExpressions: []metav1.LabelSelectorRequirement{
   351  						{
   352  							Key:      "dep",
   353  							Operator: metav1.LabelSelectorOpIn,
   354  							Values:   []string{"eng", "sales"},
   355  						},
   356  					},
   357  				}).Obj())
   358  			if err != nil {
   359  				t.Fatalf("Failed updating clusterQueue: %v", err)
   360  			}
   361  
   362  			for _, w := range test.workloadsToAdd {
   363  				cq.PushOrUpdate(workload.NewInfo(w))
   364  			}
   365  
   366  			for _, w := range test.inadmissibleWorkloadsToRequeue {
   367  				cq.requeueIfNotPresent(w, false)
   368  			}
   369  			for _, w := range test.admissibleWorkloadsToRequeue {
   370  				cq.requeueIfNotPresent(w, true)
   371  			}
   372  
   373  			for _, w := range test.workloadsToUpdate {
   374  				cq.PushOrUpdate(workload.NewInfo(w))
   375  			}
   376  
   377  			for _, w := range test.workloadsToDelete {
   378  				cq.Delete(w)
   379  			}
   380  
   381  			if test.queueInadmissibleWorkloads {
   382  				if diff := cmp.Diff(test.wantInadmissibleWorkloadsRequeued,
   383  					cq.QueueInadmissibleWorkloads(context.Background(), cl)); diff != "" {
   384  					t.Errorf("Unexpected requeuing of inadmissible workloads (-want,+got):\n%s", diff)
   385  				}
   386  			}
   387  
   388  			gotWorkloads, _ := cq.Dump()
   389  			if diff := cmp.Diff(test.wantActiveWorkloads, gotWorkloads, cmpDump...); diff != "" {
   390  				t.Errorf("Unexpected active workloads in cluster foo (-want,+got):\n%s", diff)
   391  			}
   392  			if got := cq.Pending(); got != test.wantPending {
   393  				t.Errorf("Got %d pending workloads, want %d", got, test.wantPending)
   394  			}
   395  		})
   396  	}
   397  }
   398  
   399  func TestQueueInadmissibleWorkloadsDuringScheduling(t *testing.T) {
   400  	cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, testingclock.NewFakeClock(time.Now()))
   401  	cq.namespaceSelector = labels.Everything()
   402  	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
   403  	cl := utiltesting.NewFakeClient(
   404  		wl,
   405  		&corev1.Namespace{
   406  			ObjectMeta: metav1.ObjectMeta{Name: defaultNamespace},
   407  		},
   408  	)
   409  	ctx := context.Background()
   410  	cq.PushOrUpdate(workload.NewInfo(wl))
   411  
   412  	wantActiveWorkloads := []string{workload.Key(wl)}
   413  
   414  	activeWorkloads, _ := cq.Dump()
   415  	if diff := cmp.Diff(wantActiveWorkloads, activeWorkloads, cmpDump...); diff != "" {
   416  		t.Errorf("Unexpected active workloads before events (-want,+got):\n%s", diff)
   417  	}
   418  
   419  	// Simulate requeuing during scheduling attempt.
   420  	head := cq.Pop()
   421  	cq.QueueInadmissibleWorkloads(ctx, cl)
   422  	cq.requeueIfNotPresent(head, false)
   423  
   424  	activeWorkloads, _ = cq.Dump()
   425  	wantActiveWorkloads = []string{workload.Key(wl)}
   426  	if diff := cmp.Diff(wantActiveWorkloads, activeWorkloads, cmpDump...); diff != "" {
   427  		t.Errorf("Unexpected active workloads after scheduling with requeuing (-want,+got):\n%s", diff)
   428  	}
   429  
   430  	// Simulating scheduling again without requeuing.
   431  	head = cq.Pop()
   432  	cq.requeueIfNotPresent(head, false)
   433  	activeWorkloads, _ = cq.Dump()
   434  	wantActiveWorkloads = nil
   435  	if diff := cmp.Diff(wantActiveWorkloads, activeWorkloads, cmpDump...); diff != "" {
   436  		t.Errorf("Unexpected active workloads after scheduling (-want,+got):\n%s", diff)
   437  	}
   438  }
   439  
   440  func TestBackoffWaitingTimeExpired(t *testing.T) {
   441  	now := time.Now()
   442  	minuteLater := now.Add(time.Minute)
   443  	minuteAgo := now.Add(-time.Minute)
   444  	fakeClock := testingclock.NewFakeClock(now)
   445  
   446  	cases := map[string]struct {
   447  		workloadInfo *workload.Info
   448  		want         bool
   449  	}{
   450  		"workload doesn't have requeueState": {
   451  			workloadInfo: workload.NewInfo(utiltesting.MakeWorkload("wl", "ns").Obj()),
   452  			want:         true,
   453  		},
   454  		"workload doesn't have an evicted condition with reason=PodsReadyTimeout": {
   455  			workloadInfo: workload.NewInfo(utiltesting.MakeWorkload("wl", "ns").
   456  				RequeueState(ptr.To[int32](10), nil).Obj()),
   457  			want: true,
   458  		},
   459  		"now already has exceeded requeueAt": {
   460  			workloadInfo: workload.NewInfo(utiltesting.MakeWorkload("wl", "ns").
   461  				RequeueState(ptr.To[int32](10), ptr.To(metav1.NewTime(minuteAgo))).
   462  				Condition(metav1.Condition{
   463  					Type:   kueue.WorkloadEvicted,
   464  					Status: metav1.ConditionTrue,
   465  					Reason: kueue.WorkloadEvictedByPodsReadyTimeout,
   466  				}).Obj()),
   467  			want: true,
   468  		},
   469  		"now hasn't yet exceeded requeueAt": {
   470  			workloadInfo: workload.NewInfo(utiltesting.MakeWorkload("wl", "ns").
   471  				RequeueState(ptr.To[int32](10), ptr.To(metav1.NewTime(minuteLater))).
   472  				Condition(metav1.Condition{
   473  					Type:   kueue.WorkloadEvicted,
   474  					Status: metav1.ConditionTrue,
   475  					Reason: kueue.WorkloadEvictedByPodsReadyTimeout,
   476  				}).Obj()),
   477  			want: false,
   478  		},
   479  	}
   480  	for name, tc := range cases {
   481  		t.Run(name, func(t *testing.T) {
   482  			cq := newClusterQueueImpl(keyFunc, defaultQueueOrderingFunc, fakeClock)
   483  			got := cq.backoffWaitingTimeExpired(tc.workloadInfo)
   484  			if tc.want != got {
   485  				t.Errorf("Unexpected result from backoffWaitingTimeExpired\nwant: %v\ngot: %v\n", tc.want, got)
   486  			}
   487  		})
   488  	}
   489  }