sigs.k8s.io/kueue@v0.6.2/pkg/controller/jobs/pod/pod_controller_test.go (about)

     1  /*
     2  Copyright 2023 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 pod
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"syscall"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/google/go-cmp/cmp/cmpopts"
    28  	corev1 "k8s.io/api/core/v1"
    29  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/client-go/tools/record"
    33  	"k8s.io/utils/ptr"
    34  	ctrl "sigs.k8s.io/controller-runtime"
    35  	"sigs.k8s.io/controller-runtime/pkg/client"
    36  	"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
    37  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    38  
    39  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    40  	controllerconsts "sigs.k8s.io/kueue/pkg/controller/constants"
    41  	"sigs.k8s.io/kueue/pkg/controller/jobframework"
    42  	_ "sigs.k8s.io/kueue/pkg/controller/jobs/job"
    43  	"sigs.k8s.io/kueue/pkg/podset"
    44  	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
    45  	testingpod "sigs.k8s.io/kueue/pkg/util/testingjobs/pod"
    46  )
    47  
    48  func TestPodsReady(t *testing.T) {
    49  	testCases := map[string]struct {
    50  		pod  *corev1.Pod
    51  		want bool
    52  	}{
    53  		"pod is ready": {
    54  			pod: testingpod.MakePod("test-pod", "test-ns").
    55  				Queue("test-queue").
    56  				StatusConditions(
    57  					corev1.PodCondition{
    58  						Type:   corev1.PodReady,
    59  						Status: corev1.ConditionTrue,
    60  					},
    61  				).
    62  				Obj(),
    63  			want: true,
    64  		},
    65  		"pod is not ready": {
    66  			pod: testingpod.MakePod("test-pod", "test-ns").
    67  				Queue("test-queue").
    68  				StatusConditions().
    69  				Obj(),
    70  			want: false,
    71  		},
    72  	}
    73  
    74  	for name, tc := range testCases {
    75  		t.Run(name, func(t *testing.T) {
    76  			pod := fromObject(tc.pod)
    77  			got := pod.PodsReady()
    78  			if tc.want != got {
    79  				t.Errorf("Unexpected response (want: %v, got: %v)", tc.want, got)
    80  			}
    81  		})
    82  	}
    83  }
    84  
    85  func TestRun(t *testing.T) {
    86  	testCases := map[string]struct {
    87  		pods                 []corev1.Pod
    88  		runInfo, restoreInfo []podset.PodSetInfo
    89  		wantErr              error
    90  	}{
    91  		"pod set info > 1 for the single pod": {
    92  			pods:    []corev1.Pod{*testingpod.MakePod("test-pod", "test-namespace").Obj()},
    93  			runInfo: make([]podset.PodSetInfo, 2),
    94  			wantErr: podset.ErrInvalidPodsetInfo,
    95  		},
    96  	}
    97  
    98  	for name, tc := range testCases {
    99  		t.Run(name, func(t *testing.T) {
   100  			pod := fromObject(&tc.pods[0])
   101  
   102  			ctx, _ := utiltesting.ContextWithLog(t)
   103  			clientBuilder := utiltesting.NewClientBuilder()
   104  			if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil {
   105  				t.Fatalf("Could not setup indexes: %v", err)
   106  			}
   107  
   108  			kClient := clientBuilder.WithLists(&corev1.PodList{Items: tc.pods}).Build()
   109  
   110  			gotErr := pod.Run(ctx, kClient, tc.runInfo, nil, "")
   111  
   112  			if diff := cmp.Diff(tc.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" {
   113  				t.Errorf("error mismatch (-want +got):\n%s", diff)
   114  			}
   115  		})
   116  	}
   117  }
   118  
   119  var (
   120  	podCmpOpts = []cmp.Option{
   121  		cmpopts.EquateEmpty(),
   122  		cmpopts.IgnoreFields(corev1.Pod{}, "TypeMeta", "ObjectMeta.ResourceVersion",
   123  			"ObjectMeta.DeletionTimestamp"),
   124  		cmpopts.IgnoreFields(corev1.PodCondition{}, "LastTransitionTime"),
   125  	}
   126  	defaultWorkloadCmpOpts = []cmp.Option{
   127  		cmpopts.EquateEmpty(),
   128  		cmpopts.SortSlices(func(a, b kueue.Workload) bool {
   129  			return a.Name < b.Name
   130  		}),
   131  		cmpopts.SortSlices(func(a, b metav1.Condition) bool {
   132  			return a.Type < b.Type
   133  		}),
   134  		cmpopts.IgnoreFields(
   135  			kueue.Workload{}, "TypeMeta",
   136  			"ObjectMeta.ResourceVersion",
   137  		),
   138  		cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime"),
   139  	}
   140  )
   141  
   142  func TestReconciler(t *testing.T) {
   143  	basePodWrapper := testingpod.MakePod("pod", "ns").
   144  		UID("test-uid").
   145  		Queue("user-queue").
   146  		Request(corev1.ResourceCPU, "1").
   147  		Image("", nil)
   148  
   149  	now := time.Now()
   150  
   151  	testCases := map[string]struct {
   152  		reconcileKey           *types.NamespacedName
   153  		initObjects            []client.Object
   154  		pods                   []corev1.Pod
   155  		wantPods               []corev1.Pod
   156  		workloads              []kueue.Workload
   157  		wantWorkloads          []kueue.Workload
   158  		wantErr                error
   159  		workloadCmpOpts        []cmp.Option
   160  		excessPodsExpectations []keyUIDs
   161  		// If true, the test will delete workloads before running reconcile
   162  		deleteWorkloads bool
   163  
   164  		wantEvents []utiltesting.EventRecord
   165  	}{
   166  		"scheduling gate is removed and node selector is added if workload is admitted": {
   167  			initObjects: []client.Object{
   168  				utiltesting.MakeResourceFlavor("unit-test-flavor").Label("kubernetes.io/arch", "arm64").Obj(),
   169  			},
   170  			pods: []corev1.Pod{*basePodWrapper.
   171  				Clone().
   172  				Label("kueue.x-k8s.io/managed", "true").
   173  				KueueFinalizer().
   174  				KueueSchedulingGate().
   175  				Obj()},
   176  			wantPods: []corev1.Pod{*basePodWrapper.
   177  				Clone().
   178  				Label("kueue.x-k8s.io/managed", "true").
   179  				NodeSelector("kubernetes.io/arch", "arm64").
   180  				KueueFinalizer().
   181  				Obj()},
   182  			workloads: []kueue.Workload{
   183  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   184  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   185  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   186  					ReserveQuota(
   187  						utiltesting.MakeAdmission("cq").
   188  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "1").
   189  							AssignmentPodCount(1).
   190  							Obj(),
   191  					).
   192  					Admitted(true).
   193  					Obj(),
   194  			},
   195  			wantWorkloads: []kueue.Workload{
   196  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   197  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   198  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   199  					ReserveQuota(
   200  						utiltesting.MakeAdmission("cq").
   201  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "1").
   202  							AssignmentPodCount(1).
   203  							Obj(),
   204  					).
   205  					Admitted(true).
   206  					Obj(),
   207  			},
   208  			workloadCmpOpts: defaultWorkloadCmpOpts,
   209  			wantEvents: []utiltesting.EventRecord{
   210  				{
   211  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   212  					EventType: "Normal",
   213  					Reason:    "Started",
   214  					Message:   "Admitted by clusterQueue cq",
   215  				},
   216  			},
   217  		},
   218  		"non-matching admitted workload is deleted and pod is finalized": {
   219  			pods: []corev1.Pod{*basePodWrapper.
   220  				Clone().
   221  				Label("kueue.x-k8s.io/managed", "true").
   222  				KueueFinalizer().
   223  				Obj()},
   224  			wantPods: nil,
   225  			workloads: []kueue.Workload{
   226  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   227  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 2).Request(corev1.ResourceCPU, "1").Obj()).
   228  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   229  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   230  					Admitted(true).
   231  					Obj(),
   232  			},
   233  			wantErr:         jobframework.ErrNoMatchingWorkloads,
   234  			workloadCmpOpts: defaultWorkloadCmpOpts,
   235  			wantEvents: []utiltesting.EventRecord{
   236  				{
   237  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   238  					EventType: "Normal",
   239  					Reason:    "Stopped",
   240  					Message:   "No matching Workload; restoring pod templates according to existent Workload",
   241  				},
   242  				{
   243  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   244  					EventType: "Normal",
   245  					Reason:    "DeletedWorkload",
   246  					Message:   "Deleted not matching Workload: ns/unit-test",
   247  				},
   248  			},
   249  		},
   250  		"the workload is created when queue name is set": {
   251  			pods: []corev1.Pod{*basePodWrapper.
   252  				Clone().
   253  				Label("kueue.x-k8s.io/managed", "true").
   254  				KueueFinalizer().
   255  				KueueSchedulingGate().
   256  				Queue("test-queue").
   257  				Obj()},
   258  			wantPods: []corev1.Pod{*basePodWrapper.
   259  				Clone().
   260  				Label("kueue.x-k8s.io/managed", "true").
   261  				KueueFinalizer().
   262  				KueueSchedulingGate().
   263  				Queue("test-queue").
   264  				Obj()},
   265  			wantWorkloads: []kueue.Workload{
   266  				*utiltesting.MakeWorkload("pod-pod-a91e8", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   267  					PodSets(
   268  						*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).
   269  							Request(corev1.ResourceCPU, "1").
   270  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
   271  							Obj(),
   272  					).
   273  					Queue("test-queue").
   274  					Priority(0).
   275  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   276  					Labels(map[string]string{
   277  						controllerconsts.JobUIDLabel: "test-uid",
   278  					}).
   279  					Obj(),
   280  			},
   281  			workloadCmpOpts: defaultWorkloadCmpOpts,
   282  			wantEvents: []utiltesting.EventRecord{
   283  				{
   284  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   285  					EventType: "Normal",
   286  					Reason:    "CreatedWorkload",
   287  					Message:   "Created Workload: ns/pod-pod-a91e8",
   288  				},
   289  			},
   290  		},
   291  		"the pod reconciliation is skipped when 'kueue.x-k8s.io/managed' label is not set": {
   292  			pods: []corev1.Pod{*basePodWrapper.
   293  				Clone().
   294  				Obj()},
   295  			wantPods: []corev1.Pod{*basePodWrapper.
   296  				Clone().
   297  				Obj()},
   298  			wantWorkloads:   []kueue.Workload{},
   299  			workloadCmpOpts: defaultWorkloadCmpOpts,
   300  		},
   301  		"pod is stopped when workload is evicted": {
   302  			pods: []corev1.Pod{*basePodWrapper.
   303  				Clone().
   304  				Label("kueue.x-k8s.io/managed", "true").
   305  				KueueFinalizer().
   306  				Queue("test-queue").
   307  				Obj()},
   308  			wantPods: []corev1.Pod{*basePodWrapper.
   309  				Clone().
   310  				Label("kueue.x-k8s.io/managed", "true").
   311  				KueueFinalizer().
   312  				Queue("test-queue").
   313  				StatusConditions(corev1.PodCondition{
   314  					Type:    "TerminationTarget",
   315  					Status:  corev1.ConditionTrue,
   316  					Reason:  "StoppedByKueue",
   317  					Message: "Preempted to accommodate a higher priority Workload",
   318  				}).
   319  				Obj()},
   320  			workloads: []kueue.Workload{
   321  				*utiltesting.MakeWorkload("job", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   322  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   323  					Queue("test-queue").
   324  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   325  					Condition(metav1.Condition{
   326  						Type:               kueue.WorkloadEvicted,
   327  						Status:             metav1.ConditionTrue,
   328  						LastTransitionTime: metav1.Now(),
   329  						Reason:             "Preempted",
   330  						Message:            "Preempted to accommodate a higher priority Workload",
   331  					}).
   332  					Obj(),
   333  			},
   334  			wantWorkloads: []kueue.Workload{
   335  				*utiltesting.MakeWorkload("job", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   336  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   337  					Queue("test-queue").
   338  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   339  					Condition(metav1.Condition{
   340  						Type:               kueue.WorkloadEvicted,
   341  						Status:             metav1.ConditionTrue,
   342  						LastTransitionTime: metav1.Now(),
   343  						Reason:             "Preempted",
   344  						Message:            "Preempted to accommodate a higher priority Workload",
   345  					}).
   346  					Obj(),
   347  			},
   348  			workloadCmpOpts: defaultWorkloadCmpOpts,
   349  			wantEvents: []utiltesting.EventRecord{
   350  				{
   351  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   352  					EventType: "Normal",
   353  					Reason:    "Stopped",
   354  					Message:   "Preempted to accommodate a higher priority Workload",
   355  				},
   356  			},
   357  		},
   358  		"pod is finalized when it's succeeded": {
   359  			pods: []corev1.Pod{*basePodWrapper.
   360  				Clone().
   361  				Label("kueue.x-k8s.io/managed", "true").
   362  				KueueFinalizer().
   363  				StatusPhase(corev1.PodSucceeded).
   364  				Obj()},
   365  			wantPods: []corev1.Pod{*basePodWrapper.
   366  				Clone().
   367  				Label("kueue.x-k8s.io/managed", "true").
   368  				StatusPhase(corev1.PodSucceeded).
   369  				Obj()},
   370  			workloads: []kueue.Workload{
   371  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   372  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   373  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   374  					Admitted(true).
   375  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   376  					Obj(),
   377  			},
   378  			wantWorkloads: []kueue.Workload{
   379  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   380  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   381  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   382  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   383  					Admitted(true).
   384  					Condition(metav1.Condition{
   385  						Type:    "Finished",
   386  						Status:  "True",
   387  						Reason:  "JobFinished",
   388  						Message: "Job finished successfully",
   389  					}).
   390  					Obj(),
   391  			},
   392  			workloadCmpOpts: append(
   393  				defaultWorkloadCmpOpts,
   394  				// This is required because SSA doesn't work properly for the fake k8s client.
   395  				// Reconciler appends "Finished" condition using SSA. Fake client will just
   396  				// replace all the older conditions.
   397  				// See: https://github.com/kubernetes-sigs/controller-runtime/issues/2341
   398  				cmpopts.IgnoreSliceElements(func(c metav1.Condition) bool {
   399  					return c.Type == "Admitted"
   400  				}),
   401  			),
   402  			wantEvents: []utiltesting.EventRecord{
   403  				{
   404  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   405  					EventType: "Normal",
   406  					Reason:    "FinishedWorkload",
   407  					Message:   "Workload 'ns/unit-test' is declared finished",
   408  				},
   409  			},
   410  		},
   411  		"workload status condition is added even if the pod is finalized": {
   412  			pods: []corev1.Pod{*basePodWrapper.
   413  				Clone().
   414  				Label("kueue.x-k8s.io/managed", "true").
   415  				StatusPhase(corev1.PodSucceeded).
   416  				Obj()},
   417  			wantPods: []corev1.Pod{*basePodWrapper.
   418  				Clone().
   419  				Label("kueue.x-k8s.io/managed", "true").
   420  				StatusPhase(corev1.PodSucceeded).
   421  				Obj()},
   422  			workloads: []kueue.Workload{
   423  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   424  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   425  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   426  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   427  					Admitted(true).
   428  					Obj(),
   429  			},
   430  			wantWorkloads: []kueue.Workload{
   431  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   432  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   433  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   434  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   435  					Admitted(true).
   436  					Condition(metav1.Condition{
   437  						Type:    "Finished",
   438  						Status:  "True",
   439  						Reason:  "JobFinished",
   440  						Message: "Job finished successfully",
   441  					}).
   442  					Obj(),
   443  			},
   444  			workloadCmpOpts: defaultWorkloadCmpOpts,
   445  			wantEvents: []utiltesting.EventRecord{
   446  				{
   447  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   448  					EventType: "Normal",
   449  					Reason:    "FinishedWorkload",
   450  					Message:   "Workload 'ns/unit-test' is declared finished",
   451  				},
   452  			},
   453  		},
   454  		"pod without scheduling gate is terminated if workload is not admitted": {
   455  			pods: []corev1.Pod{*basePodWrapper.
   456  				Clone().
   457  				Label("kueue.x-k8s.io/managed", "true").
   458  				KueueFinalizer().
   459  				Obj()},
   460  			wantPods: []corev1.Pod{*basePodWrapper.
   461  				Clone().
   462  				Label("kueue.x-k8s.io/managed", "true").
   463  				KueueFinalizer().
   464  				StatusConditions(corev1.PodCondition{
   465  					Type:    "TerminationTarget",
   466  					Status:  corev1.ConditionTrue,
   467  					Reason:  "StoppedByKueue",
   468  					Message: "Not admitted by cluster queue",
   469  				}).
   470  				Obj()},
   471  			workloads: []kueue.Workload{
   472  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   473  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   474  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   475  					Obj(),
   476  			},
   477  			wantWorkloads: []kueue.Workload{
   478  				*utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   479  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   480  					PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
   481  					Obj(),
   482  			},
   483  			workloadCmpOpts: defaultWorkloadCmpOpts,
   484  			wantEvents: []utiltesting.EventRecord{
   485  				{
   486  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   487  					EventType: "Normal",
   488  					Reason:    "Stopped",
   489  					Message:   "Not admitted by cluster queue",
   490  				},
   491  			},
   492  		},
   493  		"workload is composed and created for the pod group": {
   494  			pods: []corev1.Pod{
   495  				*basePodWrapper.
   496  					Clone().
   497  					Label("kueue.x-k8s.io/managed", "true").
   498  					KueueFinalizer().
   499  					KueueSchedulingGate().
   500  					Group("test-group").
   501  					GroupTotalCount("2").
   502  					Obj(),
   503  				*basePodWrapper.
   504  					Clone().
   505  					Name("pod2").
   506  					Label("kueue.x-k8s.io/managed", "true").
   507  					KueueFinalizer().
   508  					KueueSchedulingGate().
   509  					Group("test-group").
   510  					GroupTotalCount("2").
   511  					Obj(),
   512  			},
   513  			wantPods: []corev1.Pod{
   514  				*basePodWrapper.
   515  					Clone().
   516  					Label("kueue.x-k8s.io/managed", "true").
   517  					KueueFinalizer().
   518  					KueueSchedulingGate().
   519  					Group("test-group").
   520  					GroupTotalCount("2").
   521  					Obj(),
   522  				*basePodWrapper.
   523  					Clone().
   524  					Name("pod2").
   525  					Label("kueue.x-k8s.io/managed", "true").
   526  					KueueFinalizer().
   527  					KueueSchedulingGate().
   528  					Group("test-group").
   529  					GroupTotalCount("2").
   530  					Obj(),
   531  			},
   532  			wantWorkloads: []kueue.Workload{
   533  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   534  					PodSets(
   535  						*utiltesting.MakePodSet("dc85db45", 2).
   536  							Request(corev1.ResourceCPU, "1").
   537  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
   538  							Obj(),
   539  					).
   540  					Queue("user-queue").
   541  					Priority(0).
   542  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   543  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   544  					Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}).
   545  					Obj(),
   546  			},
   547  			workloadCmpOpts: defaultWorkloadCmpOpts,
   548  			wantEvents: []utiltesting.EventRecord{
   549  				{
   550  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   551  					EventType: "Normal",
   552  					Reason:    "CreatedWorkload",
   553  					Message:   "Created Workload: ns/test-group",
   554  				},
   555  			},
   556  		},
   557  		"workload is found for the pod group": {
   558  			pods: []corev1.Pod{
   559  				*basePodWrapper.
   560  					Clone().
   561  					Label("kueue.x-k8s.io/managed", "true").
   562  					KueueFinalizer().
   563  					KueueSchedulingGate().
   564  					Group("test-group").
   565  					GroupTotalCount("2").
   566  					Obj(),
   567  				*basePodWrapper.
   568  					Clone().
   569  					Name("pod2").
   570  					Label("kueue.x-k8s.io/managed", "true").
   571  					KueueFinalizer().
   572  					KueueSchedulingGate().
   573  					Group("test-group").
   574  					GroupTotalCount("2").
   575  					Obj(),
   576  			},
   577  			wantPods: []corev1.Pod{
   578  				*basePodWrapper.
   579  					Clone().
   580  					Label("kueue.x-k8s.io/managed", "true").
   581  					KueueFinalizer().
   582  					KueueSchedulingGate().
   583  					Group("test-group").
   584  					GroupTotalCount("2").
   585  					Obj(),
   586  				*basePodWrapper.
   587  					Clone().
   588  					Name("pod2").
   589  					Label("kueue.x-k8s.io/managed", "true").
   590  					KueueFinalizer().
   591  					KueueSchedulingGate().
   592  					Group("test-group").
   593  					GroupTotalCount("2").
   594  					Obj(),
   595  			},
   596  			workloads: []kueue.Workload{
   597  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   598  					PodSets(
   599  						*utiltesting.MakePodSet("dc85db45", 2).
   600  							Request(corev1.ResourceCPU, "1").
   601  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
   602  							Obj(),
   603  					).
   604  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   605  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   606  					Queue("user-queue").
   607  					Priority(0).
   608  					Obj(),
   609  			},
   610  			wantWorkloads: []kueue.Workload{
   611  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   612  					PodSets(
   613  						*utiltesting.MakePodSet("dc85db45", 2).
   614  							Request(corev1.ResourceCPU, "1").
   615  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
   616  							Obj(),
   617  					).
   618  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   619  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   620  					Queue("user-queue").
   621  					Priority(0).
   622  					Obj(),
   623  			},
   624  			workloadCmpOpts: defaultWorkloadCmpOpts,
   625  		},
   626  		"scheduling gate is removed for all pods in the group if workload is admitted": {
   627  			initObjects: []client.Object{
   628  				utiltesting.MakeResourceFlavor("unit-test-flavor").Label("kubernetes.io/arch", "arm64").Obj(),
   629  			},
   630  			pods: []corev1.Pod{
   631  				*basePodWrapper.
   632  					Clone().
   633  					Label("kueue.x-k8s.io/managed", "true").
   634  					KueueFinalizer().
   635  					KueueSchedulingGate().
   636  					Group("test-group").
   637  					GroupTotalCount("2").
   638  					Obj(),
   639  				*basePodWrapper.
   640  					Clone().
   641  					Name("pod2").
   642  					Label("kueue.x-k8s.io/managed", "true").
   643  					KueueFinalizer().
   644  					KueueSchedulingGate().
   645  					Group("test-group").
   646  					GroupTotalCount("2").
   647  					Obj(),
   648  			},
   649  			wantPods: []corev1.Pod{
   650  				*basePodWrapper.
   651  					Clone().
   652  					Label("kueue.x-k8s.io/managed", "true").
   653  					KueueFinalizer().
   654  					Group("test-group").
   655  					GroupTotalCount("2").
   656  					NodeSelector("kubernetes.io/arch", "arm64").
   657  					Obj(),
   658  				*basePodWrapper.
   659  					Clone().
   660  					Name("pod2").
   661  					Label("kueue.x-k8s.io/managed", "true").
   662  					KueueFinalizer().
   663  					Group("test-group").
   664  					GroupTotalCount("2").
   665  					NodeSelector("kubernetes.io/arch", "arm64").
   666  					Obj(),
   667  			},
   668  			workloads: []kueue.Workload{
   669  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   670  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
   671  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   672  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   673  					ReserveQuota(
   674  						utiltesting.MakeAdmission("cq", "dc85db45").
   675  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "2").
   676  							AssignmentPodCount(2).
   677  							Obj(),
   678  					).
   679  					Admitted(true).
   680  					Obj(),
   681  			},
   682  			wantWorkloads: []kueue.Workload{
   683  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   684  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
   685  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   686  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   687  					ReserveQuota(
   688  						utiltesting.MakeAdmission("cq", "dc85db45").
   689  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "2").
   690  							AssignmentPodCount(2).
   691  							Obj(),
   692  					).
   693  					Admitted(true).
   694  					Obj(),
   695  			},
   696  			workloadCmpOpts: defaultWorkloadCmpOpts,
   697  			wantEvents: []utiltesting.EventRecord{
   698  				{
   699  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   700  					EventType: "Normal",
   701  					Reason:    "Started",
   702  					Message:   "Admitted by clusterQueue cq",
   703  				},
   704  				{
   705  					Key:       types.NamespacedName{Name: "pod2", Namespace: "ns"},
   706  					EventType: "Normal",
   707  					Reason:    "Started",
   708  					Message:   "Admitted by clusterQueue cq",
   709  				},
   710  			},
   711  		},
   712  		"workload is not finished if the pod in the group is running": {
   713  			pods: []corev1.Pod{
   714  				*basePodWrapper.
   715  					Clone().
   716  					Label("kueue.x-k8s.io/managed", "true").
   717  					KueueFinalizer().
   718  					Group("test-group").
   719  					GroupTotalCount("2").
   720  					StatusPhase(corev1.PodSucceeded).
   721  					Obj(),
   722  				*basePodWrapper.
   723  					Clone().
   724  					Name("pod2").
   725  					Label("kueue.x-k8s.io/managed", "true").
   726  					KueueFinalizer().
   727  					Group("test-group").
   728  					GroupTotalCount("2").
   729  					Obj(),
   730  			},
   731  			wantPods: []corev1.Pod{
   732  				*basePodWrapper.
   733  					Clone().
   734  					Label("kueue.x-k8s.io/managed", "true").
   735  					KueueFinalizer().
   736  					Group("test-group").
   737  					GroupTotalCount("2").
   738  					StatusPhase(corev1.PodSucceeded).
   739  					Obj(),
   740  				*basePodWrapper.
   741  					Clone().
   742  					Name("pod2").
   743  					Label("kueue.x-k8s.io/managed", "true").
   744  					KueueFinalizer().
   745  					Group("test-group").
   746  					GroupTotalCount("2").
   747  					Obj(),
   748  			},
   749  
   750  			workloads: []kueue.Workload{
   751  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   752  					PodSets(
   753  						*utiltesting.MakePodSet("dc85db45", 2).
   754  							Request(corev1.ResourceCPU, "1").
   755  							Obj(),
   756  					).
   757  					Queue("user-queue").
   758  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   759  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   760  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   761  					Admitted(true).
   762  					Obj(),
   763  			},
   764  			wantWorkloads: []kueue.Workload{
   765  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   766  					PodSets(
   767  						*utiltesting.MakePodSet("dc85db45", 2).
   768  							Request(corev1.ResourceCPU, "1").
   769  							Obj(),
   770  					).
   771  					Queue("user-queue").
   772  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   773  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   774  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   775  					Admitted(true).
   776  					ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}).
   777  					Obj(),
   778  			},
   779  			workloadCmpOpts: defaultWorkloadCmpOpts,
   780  		},
   781  		"workload is finished if all pods in the group has finished": {
   782  			pods: []corev1.Pod{
   783  				*basePodWrapper.
   784  					Clone().
   785  					Label("kueue.x-k8s.io/managed", "true").
   786  					KueueFinalizer().
   787  					Group("test-group").
   788  					GroupTotalCount("2").
   789  					StatusPhase(corev1.PodSucceeded).
   790  					Obj(),
   791  				*basePodWrapper.
   792  					Clone().
   793  					Name("pod2").
   794  					Label("kueue.x-k8s.io/managed", "true").
   795  					KueueFinalizer().
   796  					Group("test-group").
   797  					GroupTotalCount("2").
   798  					StatusPhase(corev1.PodSucceeded).
   799  					Obj(),
   800  			},
   801  			wantPods: []corev1.Pod{
   802  				*basePodWrapper.
   803  					Clone().
   804  					Label("kueue.x-k8s.io/managed", "true").
   805  					Group("test-group").
   806  					GroupTotalCount("2").
   807  					StatusPhase(corev1.PodSucceeded).
   808  					Obj(),
   809  				*basePodWrapper.
   810  					Clone().
   811  					Name("pod2").
   812  					Label("kueue.x-k8s.io/managed", "true").
   813  					Group("test-group").
   814  					GroupTotalCount("2").
   815  					StatusPhase(corev1.PodSucceeded).
   816  					Obj(),
   817  			},
   818  			workloads: []kueue.Workload{
   819  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   820  					PodSets(
   821  						*utiltesting.MakePodSet("dc85db45", 2).
   822  							Request(corev1.ResourceCPU, "1").
   823  							Obj(),
   824  					).
   825  					Queue("user-queue").
   826  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   827  					Admitted(true).
   828  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   829  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   830  					Obj(),
   831  			},
   832  			wantWorkloads: []kueue.Workload{
   833  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   834  					PodSets(
   835  						*utiltesting.MakePodSet("dc85db45", 2).
   836  							Request(corev1.ResourceCPU, "1").
   837  							Obj(),
   838  					).
   839  					Queue("user-queue").
   840  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   841  					Admitted(true).
   842  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   843  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   844  					Condition(metav1.Condition{
   845  						Type:    "Finished",
   846  						Status:  "True",
   847  						Reason:  "JobFinished",
   848  						Message: "Pods succeeded: 2/2.",
   849  					}).
   850  					Obj(),
   851  			},
   852  			workloadCmpOpts: defaultWorkloadCmpOpts,
   853  			wantEvents: []utiltesting.EventRecord{
   854  				{
   855  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
   856  					EventType: "Normal",
   857  					Reason:    "FinishedWorkload",
   858  					Message:   "Workload 'ns/test-group' is declared finished",
   859  				},
   860  			},
   861  		},
   862  		"workload is not deleted if the pod in group has been deleted after admission": {
   863  			pods: []corev1.Pod{*basePodWrapper.
   864  				Clone().
   865  				Label("kueue.x-k8s.io/managed", "true").
   866  				KueueFinalizer().
   867  				Group("test-group").
   868  				GroupTotalCount("2").
   869  				Obj()},
   870  			wantPods: []corev1.Pod{*basePodWrapper.
   871  				Clone().
   872  				Label("kueue.x-k8s.io/managed", "true").
   873  				KueueFinalizer().
   874  				Group("test-group").
   875  				GroupTotalCount("2").
   876  				Obj()},
   877  			workloads: []kueue.Workload{
   878  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   879  					PodSets(
   880  						*utiltesting.MakePodSet("dc85db45", 2).
   881  							Request(corev1.ResourceCPU, "1").
   882  							Obj(),
   883  					).
   884  					Queue("user-queue").
   885  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   886  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   887  					Admitted(true).
   888  					Obj(),
   889  			},
   890  			wantWorkloads: []kueue.Workload{
   891  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   892  					PodSets(
   893  						*utiltesting.MakePodSet("dc85db45", 2).
   894  							Request(corev1.ResourceCPU, "1").
   895  							Obj(),
   896  					).
   897  					Queue("user-queue").
   898  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   899  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
   900  					Admitted(true).
   901  					Obj(),
   902  			},
   903  			workloadCmpOpts: defaultWorkloadCmpOpts,
   904  		},
   905  		"pod group remains stopped when workload is evicted": {
   906  			pods: []corev1.Pod{
   907  				*basePodWrapper.
   908  					Clone().
   909  					Label("kueue.x-k8s.io/managed", "true").
   910  					KueueFinalizer().
   911  					KueueSchedulingGate().
   912  					Queue("test-queue").
   913  					Group("test-group").
   914  					GroupTotalCount("2").
   915  					Obj(),
   916  				*basePodWrapper.
   917  					Clone().
   918  					Name("pod2").
   919  					Label("kueue.x-k8s.io/managed", "true").
   920  					KueueFinalizer().
   921  					KueueSchedulingGate().
   922  					Queue("test-queue").
   923  					Group("test-group").
   924  					GroupTotalCount("2").
   925  					Obj(),
   926  			},
   927  			wantPods: []corev1.Pod{
   928  				*basePodWrapper.
   929  					Clone().
   930  					Label("kueue.x-k8s.io/managed", "true").
   931  					KueueFinalizer().
   932  					KueueSchedulingGate().
   933  					Queue("test-queue").
   934  					Group("test-group").
   935  					GroupTotalCount("2").
   936  					Obj(),
   937  				*basePodWrapper.
   938  					Clone().
   939  					Name("pod2").
   940  					Label("kueue.x-k8s.io/managed", "true").
   941  					KueueFinalizer().
   942  					KueueSchedulingGate().
   943  					Queue("test-queue").
   944  					Group("test-group").
   945  					GroupTotalCount("2").
   946  					Obj(),
   947  			},
   948  			workloads: []kueue.Workload{
   949  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   950  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
   951  					Queue("test-queue").
   952  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   953  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   954  					Condition(metav1.Condition{
   955  						Type:               kueue.WorkloadEvicted,
   956  						Status:             metav1.ConditionTrue,
   957  						LastTransitionTime: metav1.Now(),
   958  						Reason:             "Preempted",
   959  						Message:            "Preempted to accommodate a higher priority Workload",
   960  					}).
   961  					Obj(),
   962  			},
   963  			wantWorkloads: []kueue.Workload{
   964  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
   965  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
   966  					Queue("test-queue").
   967  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
   968  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
   969  					Condition(metav1.Condition{
   970  						Type:               kueue.WorkloadEvicted,
   971  						Status:             metav1.ConditionTrue,
   972  						LastTransitionTime: metav1.Now(),
   973  						Reason:             "Preempted",
   974  						Message:            "Preempted to accommodate a higher priority Workload",
   975  					}).
   976  					Obj(),
   977  			},
   978  			workloadCmpOpts: defaultWorkloadCmpOpts,
   979  		},
   980  		"Pods are finalized even if one of the pods in the finished group is absent": {
   981  			pods: []corev1.Pod{
   982  				*basePodWrapper.
   983  					Clone().
   984  					KueueFinalizer().
   985  					Label("kueue.x-k8s.io/managed", "true").
   986  					Group("test-group").
   987  					GroupTotalCount("2").
   988  					StatusPhase(corev1.PodSucceeded).
   989  					Obj(),
   990  			},
   991  			wantPods: []corev1.Pod{
   992  				*basePodWrapper.
   993  					Clone().
   994  					Label("kueue.x-k8s.io/managed", "true").
   995  					Group("test-group").
   996  					GroupTotalCount("2").
   997  					StatusPhase(corev1.PodSucceeded).
   998  					Obj(),
   999  			},
  1000  
  1001  			workloads: []kueue.Workload{
  1002  				*utiltesting.MakeWorkload("test-group", "ns").
  1003  					PodSets(
  1004  						*utiltesting.MakePodSet("dc85db45", 2).
  1005  							Request(corev1.ResourceCPU, "1").
  1006  							Obj(),
  1007  					).
  1008  					Queue("user-queue").
  1009  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1010  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1011  					Admitted(true).
  1012  					Condition(metav1.Condition{
  1013  						Type:    "Finished",
  1014  						Status:  "True",
  1015  						Reason:  "JobFinished",
  1016  						Message: "Pods succeeded: 1/2. Pods failed: 1/2",
  1017  					}).
  1018  					Obj(),
  1019  			},
  1020  			wantWorkloads: []kueue.Workload{
  1021  				*utiltesting.MakeWorkload("test-group", "ns").
  1022  					PodSets(
  1023  						*utiltesting.MakePodSet("dc85db45", 2).
  1024  							Request(corev1.ResourceCPU, "1").
  1025  							Obj(),
  1026  					).
  1027  					Queue("user-queue").
  1028  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1029  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1030  					Admitted(true).
  1031  					Condition(metav1.Condition{
  1032  						Type:    "Finished",
  1033  						Status:  "True",
  1034  						Reason:  "JobFinished",
  1035  						Message: "Pods succeeded: 1/2. Pods failed: 1/2",
  1036  					}).
  1037  					Obj(),
  1038  			},
  1039  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1040  			wantEvents: []utiltesting.EventRecord{
  1041  				{
  1042  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1043  					EventType: "Normal",
  1044  					Reason:    "FinishedWorkload",
  1045  					Message:   "Workload 'ns/test-group' is declared finished",
  1046  				},
  1047  			},
  1048  		},
  1049  		"workload for pod group with different queue names shouldn't be created": {
  1050  			pods: []corev1.Pod{
  1051  				*basePodWrapper.
  1052  					Clone().
  1053  					Label("kueue.x-k8s.io/managed", "true").
  1054  					KueueFinalizer().
  1055  					KueueSchedulingGate().
  1056  					Queue("test-queue").
  1057  					Group("test-group").
  1058  					GroupTotalCount("2").
  1059  					Obj(),
  1060  				*basePodWrapper.
  1061  					Clone().
  1062  					Name("pod2").
  1063  					Label("kueue.x-k8s.io/managed", "true").
  1064  					KueueFinalizer().
  1065  					KueueSchedulingGate().
  1066  					Queue("new-test-queue").
  1067  					Group("test-group").
  1068  					GroupTotalCount("2").
  1069  					Obj(),
  1070  			},
  1071  			wantPods: []corev1.Pod{
  1072  				*basePodWrapper.
  1073  					Clone().
  1074  					Label("kueue.x-k8s.io/managed", "true").
  1075  					KueueFinalizer().
  1076  					KueueSchedulingGate().
  1077  					Queue("test-queue").
  1078  					Group("test-group").
  1079  					GroupTotalCount("2").
  1080  					Obj(),
  1081  				*basePodWrapper.
  1082  					Clone().
  1083  					Name("pod2").
  1084  					Label("kueue.x-k8s.io/managed", "true").
  1085  					KueueFinalizer().
  1086  					KueueSchedulingGate().
  1087  					Queue("new-test-queue").
  1088  					Group("test-group").
  1089  					GroupTotalCount("2").
  1090  					Obj(),
  1091  			},
  1092  
  1093  			workloads:       []kueue.Workload{},
  1094  			wantWorkloads:   []kueue.Workload{},
  1095  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1096  		},
  1097  		"all pods in group should be removed if workload is deleted": {
  1098  			pods: []corev1.Pod{
  1099  				*basePodWrapper.
  1100  					Clone().
  1101  					Label("kueue.x-k8s.io/managed", "true").
  1102  					KueueFinalizer().
  1103  					Queue("test-queue").
  1104  					Group("test-group").
  1105  					GroupTotalCount("2").
  1106  					Obj(),
  1107  				*basePodWrapper.
  1108  					Clone().
  1109  					Name("pod2").
  1110  					Label("kueue.x-k8s.io/managed", "true").
  1111  					KueueFinalizer().
  1112  					Queue("test-queue").
  1113  					Group("test-group").
  1114  					GroupTotalCount("2").
  1115  					StatusPhase(corev1.PodSucceeded).
  1116  					Obj(),
  1117  			},
  1118  			wantPods: []corev1.Pod{},
  1119  			workloads: []kueue.Workload{
  1120  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1121  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
  1122  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1123  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1124  					Queue("test-queue").
  1125  					ReserveQuota(
  1126  						utiltesting.MakeAdmission("cq").
  1127  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "2").
  1128  							AssignmentPodCount(2).
  1129  							Obj(),
  1130  					).
  1131  					Admitted(true).
  1132  					Obj(),
  1133  			},
  1134  			workloadCmpOpts: append(defaultWorkloadCmpOpts, cmpopts.IgnoreFields(kueue.Workload{}, "ObjectMeta.DeletionTimestamp")),
  1135  			deleteWorkloads: true,
  1136  			wantEvents: []utiltesting.EventRecord{
  1137  				{
  1138  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1139  					EventType: "Normal",
  1140  					Reason:    "Stopped",
  1141  					Message:   "Workload is deleted",
  1142  				},
  1143  				{
  1144  					Key:       types.NamespacedName{Name: "pod2", Namespace: "ns"},
  1145  					EventType: "Normal",
  1146  					Reason:    "Stopped",
  1147  					Message:   "Workload is deleted",
  1148  				},
  1149  			},
  1150  		},
  1151  		"replacement pod should be started for pod group of size 1": {
  1152  			pods: []corev1.Pod{
  1153  				*basePodWrapper.
  1154  					Clone().
  1155  					Label("kueue.x-k8s.io/managed", "true").
  1156  					KueueFinalizer().
  1157  					Group("test-group").
  1158  					GroupTotalCount("1").
  1159  					StatusPhase(corev1.PodFailed).
  1160  					Obj(),
  1161  				*basePodWrapper.
  1162  					Clone().
  1163  					Name("pod2").
  1164  					Label("kueue.x-k8s.io/managed", "true").
  1165  					KueueFinalizer().
  1166  					KueueSchedulingGate().
  1167  					Group("test-group").
  1168  					GroupTotalCount("1").
  1169  					Obj(),
  1170  			},
  1171  			wantPods: []corev1.Pod{
  1172  				*basePodWrapper.
  1173  					Clone().
  1174  					Label("kueue.x-k8s.io/managed", "true").
  1175  					KueueFinalizer().
  1176  					Group("test-group").
  1177  					GroupTotalCount("1").
  1178  					StatusPhase(corev1.PodFailed).
  1179  					Obj(),
  1180  				*basePodWrapper.
  1181  					Clone().
  1182  					Name("pod2").
  1183  					Label("kueue.x-k8s.io/managed", "true").
  1184  					KueueFinalizer().
  1185  					Group("test-group").
  1186  					GroupTotalCount("1").
  1187  					Obj(),
  1188  			},
  1189  			workloads: []kueue.Workload{
  1190  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1191  					PodSets(
  1192  						*utiltesting.MakePodSet("dc85db45", 2).
  1193  							Request(corev1.ResourceCPU, "1").
  1194  							Obj(),
  1195  					).
  1196  					Queue("user-queue").
  1197  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1198  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1199  					ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(1).Obj()).
  1200  					Admitted(true).
  1201  					Obj(),
  1202  			},
  1203  			wantWorkloads: []kueue.Workload{
  1204  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1205  					PodSets(
  1206  						*utiltesting.MakePodSet("dc85db45", 2).
  1207  							Request(corev1.ResourceCPU, "1").
  1208  							Obj(),
  1209  					).
  1210  					Queue("user-queue").
  1211  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1212  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1213  					ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(1).Obj()).
  1214  					Admitted(true).
  1215  					Obj(),
  1216  			},
  1217  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1218  			wantEvents: []utiltesting.EventRecord{
  1219  				{
  1220  					Key:       types.NamespacedName{Name: "pod2", Namespace: "ns"},
  1221  					EventType: "Normal",
  1222  					Reason:    "Started",
  1223  					Message:   "Admitted by clusterQueue cq",
  1224  				},
  1225  			},
  1226  		},
  1227  		"replacement pod should be started for set of Running, Failed, Succeeded pods": {
  1228  			pods: []corev1.Pod{
  1229  				*basePodWrapper.
  1230  					Clone().
  1231  					Label("kueue.x-k8s.io/managed", "true").
  1232  					KueueFinalizer().
  1233  					Group("test-group").
  1234  					GroupTotalCount("3").
  1235  					StatusPhase(corev1.PodRunning).
  1236  					Obj(),
  1237  				*basePodWrapper.
  1238  					Clone().
  1239  					Name("pod2").
  1240  					Label("kueue.x-k8s.io/managed", "true").
  1241  					KueueFinalizer().
  1242  					Group("test-group").
  1243  					GroupTotalCount("3").
  1244  					StatusPhase(corev1.PodFailed).
  1245  					Obj(),
  1246  				*basePodWrapper.
  1247  					Clone().
  1248  					Name("pod3").
  1249  					Label("kueue.x-k8s.io/managed", "true").
  1250  					KueueFinalizer().
  1251  					Group("test-group").
  1252  					GroupTotalCount("3").
  1253  					StatusPhase(corev1.PodSucceeded).
  1254  					Obj(),
  1255  				*basePodWrapper.
  1256  					Clone().
  1257  					Name("replacement").
  1258  					Label("kueue.x-k8s.io/managed", "true").
  1259  					KueueFinalizer().
  1260  					KueueSchedulingGate().
  1261  					Group("test-group").
  1262  					GroupTotalCount("3").
  1263  					Obj(),
  1264  			},
  1265  			workloads: []kueue.Workload{
  1266  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1267  					PodSets(
  1268  						*utiltesting.MakePodSet("dc85db45", 3).
  1269  							Request(corev1.ResourceCPU, "1").
  1270  							Obj(),
  1271  					).
  1272  					Queue("user-queue").
  1273  					ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(3).Obj()).
  1274  					Admitted(true).
  1275  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1276  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1277  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  1278  					ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}).
  1279  					Obj(),
  1280  			},
  1281  			wantPods: []corev1.Pod{
  1282  				*basePodWrapper.
  1283  					Clone().
  1284  					Label("kueue.x-k8s.io/managed", "true").
  1285  					KueueFinalizer().
  1286  					Group("test-group").
  1287  					GroupTotalCount("3").
  1288  					StatusPhase(corev1.PodRunning).
  1289  					Obj(),
  1290  				*basePodWrapper.
  1291  					Clone().
  1292  					Name("pod2").
  1293  					Label("kueue.x-k8s.io/managed", "true").
  1294  					Group("test-group").
  1295  					GroupTotalCount("3").
  1296  					StatusPhase(corev1.PodFailed).
  1297  					Obj(),
  1298  				*basePodWrapper.
  1299  					Clone().
  1300  					Name("pod3").
  1301  					Label("kueue.x-k8s.io/managed", "true").
  1302  					KueueFinalizer().
  1303  					Group("test-group").
  1304  					GroupTotalCount("3").
  1305  					StatusPhase(corev1.PodSucceeded).
  1306  					Obj(),
  1307  				*basePodWrapper.
  1308  					Clone().
  1309  					Name("replacement").
  1310  					Label("kueue.x-k8s.io/managed", "true").
  1311  					KueueFinalizer().
  1312  					Group("test-group").
  1313  					GroupTotalCount("3").
  1314  					Obj(),
  1315  			},
  1316  			wantWorkloads: []kueue.Workload{
  1317  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1318  					PodSets(
  1319  						*utiltesting.MakePodSet("dc85db45", 3).
  1320  							Request(corev1.ResourceCPU, "1").
  1321  							Obj(),
  1322  					).
  1323  					Queue("user-queue").
  1324  					ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(3).Obj()).
  1325  					ReclaimablePods(kueue.ReclaimablePod{
  1326  						Name:  "dc85db45",
  1327  						Count: 1,
  1328  					}).
  1329  					Admitted(true).
  1330  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1331  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1332  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  1333  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement", "test-uid").
  1334  					ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}).
  1335  					Obj(),
  1336  			},
  1337  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1338  			wantEvents: []utiltesting.EventRecord{
  1339  				{
  1340  					Key:       types.NamespacedName{Name: "test-group", Namespace: "ns"},
  1341  					EventType: "Normal",
  1342  					Reason:    "OwnerReferencesAdded",
  1343  					Message:   "Added 1 owner reference(s)",
  1344  				},
  1345  				{
  1346  					Key:       types.NamespacedName{Name: "replacement", Namespace: "ns"},
  1347  					EventType: "Normal",
  1348  					Reason:    "Started",
  1349  					Message:   "Admitted by clusterQueue cq",
  1350  				},
  1351  			},
  1352  		},
  1353  		"pod group of size 2 is finished when 2 pods has succeeded and 1 pod has failed": {
  1354  			pods: []corev1.Pod{
  1355  				*basePodWrapper.
  1356  					Clone().
  1357  					Label("kueue.x-k8s.io/managed", "true").
  1358  					KueueFinalizer().
  1359  					Group("test-group").
  1360  					GroupTotalCount("2").
  1361  					StatusPhase(corev1.PodFailed).
  1362  					Obj(),
  1363  				*basePodWrapper.
  1364  					Clone().
  1365  					Name("pod2").
  1366  					Label("kueue.x-k8s.io/managed", "true").
  1367  					KueueFinalizer().
  1368  					Group("test-group").
  1369  					GroupTotalCount("2").
  1370  					StatusPhase(corev1.PodSucceeded).
  1371  					Obj(),
  1372  				*basePodWrapper.
  1373  					Clone().
  1374  					Name("pod3").
  1375  					Label("kueue.x-k8s.io/managed", "true").
  1376  					KueueFinalizer().
  1377  					Group("test-group").
  1378  					GroupTotalCount("2").
  1379  					StatusPhase(corev1.PodSucceeded).
  1380  					Obj(),
  1381  			},
  1382  			wantPods: []corev1.Pod{
  1383  				*basePodWrapper.
  1384  					Clone().
  1385  					Label("kueue.x-k8s.io/managed", "true").
  1386  					Group("test-group").
  1387  					GroupTotalCount("2").
  1388  					StatusPhase(corev1.PodFailed).
  1389  					Obj(),
  1390  				*basePodWrapper.
  1391  					Clone().
  1392  					Name("pod2").
  1393  					Label("kueue.x-k8s.io/managed", "true").
  1394  					Group("test-group").
  1395  					GroupTotalCount("2").
  1396  					StatusPhase(corev1.PodSucceeded).
  1397  					Obj(),
  1398  				*basePodWrapper.
  1399  					Clone().
  1400  					Name("pod3").
  1401  					Label("kueue.x-k8s.io/managed", "true").
  1402  					Group("test-group").
  1403  					GroupTotalCount("2").
  1404  					StatusPhase(corev1.PodSucceeded).
  1405  					Obj(),
  1406  			},
  1407  			workloads: []kueue.Workload{
  1408  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1409  					PodSets(
  1410  						*utiltesting.MakePodSet("dc85db45", 2).
  1411  							Request(corev1.ResourceCPU, "1").
  1412  							Obj(),
  1413  					).
  1414  					Queue("user-queue").
  1415  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1416  					Admitted(true).
  1417  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1418  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1419  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  1420  					Obj(),
  1421  			},
  1422  			wantWorkloads: []kueue.Workload{
  1423  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1424  					PodSets(
  1425  						*utiltesting.MakePodSet("dc85db45", 2).
  1426  							Request(corev1.ResourceCPU, "1").
  1427  							Obj(),
  1428  					).
  1429  					Queue("user-queue").
  1430  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1431  					Admitted(true).
  1432  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1433  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1434  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  1435  					Condition(metav1.Condition{
  1436  						Type:    "Finished",
  1437  						Status:  "True",
  1438  						Reason:  "JobFinished",
  1439  						Message: "Pods succeeded: 2/2.",
  1440  					}).
  1441  					Obj(),
  1442  			},
  1443  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1444  			wantEvents: []utiltesting.EventRecord{
  1445  				{
  1446  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1447  					EventType: "Normal",
  1448  					Reason:    "FinishedWorkload",
  1449  					Message:   "Workload 'ns/test-group' is declared finished",
  1450  				},
  1451  			},
  1452  		},
  1453  		"wl should not get the quota reservation cleared for a running pod group of size 1": {
  1454  			pods: []corev1.Pod{
  1455  				*basePodWrapper.
  1456  					Clone().
  1457  					Label("kueue.x-k8s.io/managed", "true").
  1458  					KueueFinalizer().
  1459  					Group("test-group").
  1460  					GroupTotalCount("1").
  1461  					StatusPhase(corev1.PodRunning).
  1462  					Delete().
  1463  					Obj(),
  1464  			},
  1465  			wantPods: []corev1.Pod{
  1466  				*basePodWrapper.
  1467  					Clone().
  1468  					Label("kueue.x-k8s.io/managed", "true").
  1469  					KueueFinalizer().
  1470  					Group("test-group").
  1471  					GroupTotalCount("1").
  1472  					StatusPhase(corev1.PodRunning).
  1473  					Delete().
  1474  					Obj(),
  1475  			},
  1476  			workloads: []kueue.Workload{
  1477  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1478  					PodSets(
  1479  						*utiltesting.MakePodSet("dc85db45", 1).
  1480  							Request(corev1.ResourceCPU, "1").
  1481  							Obj(),
  1482  					).
  1483  					Queue("user-queue").
  1484  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1485  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1486  					Admitted(true).
  1487  					Condition(metav1.Condition{
  1488  						Type:               kueue.WorkloadEvicted,
  1489  						Status:             metav1.ConditionTrue,
  1490  						LastTransitionTime: metav1.Now(),
  1491  						Reason:             "Preempted",
  1492  						Message:            "Preempted to accommodate a higher priority Workload",
  1493  					}).
  1494  					Obj(),
  1495  			},
  1496  			wantWorkloads: []kueue.Workload{
  1497  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1498  					PodSets(
  1499  						*utiltesting.MakePodSet("dc85db45", 1).
  1500  							Request(corev1.ResourceCPU, "1").
  1501  							Obj(),
  1502  					).
  1503  					Queue("user-queue").
  1504  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1505  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1506  					Admitted(true).
  1507  					Condition(metav1.Condition{
  1508  						Type:               kueue.WorkloadEvicted,
  1509  						Status:             metav1.ConditionTrue,
  1510  						LastTransitionTime: metav1.Now(),
  1511  						Reason:             "Preempted",
  1512  						Message:            "Preempted to accommodate a higher priority Workload",
  1513  					}).
  1514  					Obj(),
  1515  			},
  1516  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1517  		},
  1518  		"wl should get the quota reservation cleared for a failed pod group of size 1": {
  1519  			pods: []corev1.Pod{
  1520  				*basePodWrapper.
  1521  					Clone().
  1522  					Label("kueue.x-k8s.io/managed", "true").
  1523  					KueueFinalizer().
  1524  					Group("test-group").
  1525  					GroupTotalCount("1").
  1526  					StatusPhase(corev1.PodFailed).
  1527  					Delete().
  1528  					Obj(),
  1529  			},
  1530  			wantPods: []corev1.Pod{
  1531  				*basePodWrapper.
  1532  					Clone().
  1533  					Label("kueue.x-k8s.io/managed", "true").
  1534  					KueueFinalizer().
  1535  					Group("test-group").
  1536  					GroupTotalCount("1").
  1537  					StatusPhase(corev1.PodFailed).
  1538  					Delete().
  1539  					Obj(),
  1540  			},
  1541  			workloads: []kueue.Workload{
  1542  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1543  					PodSets(
  1544  						*utiltesting.MakePodSet("dc85db45", 1).
  1545  							Request(corev1.ResourceCPU, "1").
  1546  							Obj(),
  1547  					).
  1548  					Queue("user-queue").
  1549  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1550  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1551  					Admitted(true).
  1552  					Condition(metav1.Condition{
  1553  						Type:               kueue.WorkloadEvicted,
  1554  						Status:             metav1.ConditionTrue,
  1555  						LastTransitionTime: metav1.Now(),
  1556  						Reason:             "Preempted",
  1557  						Message:            "Preempted to accommodate a higher priority Workload",
  1558  					}).
  1559  					Obj(),
  1560  			},
  1561  			wantWorkloads: []kueue.Workload{
  1562  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1563  					PodSets(
  1564  						*utiltesting.MakePodSet("dc85db45", 1).
  1565  							Request(corev1.ResourceCPU, "1").
  1566  							Obj(),
  1567  					).
  1568  					Queue("user-queue").
  1569  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1570  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1571  					Condition(metav1.Condition{
  1572  						Type:               kueue.WorkloadAdmitted,
  1573  						Status:             metav1.ConditionFalse,
  1574  						LastTransitionTime: metav1.Now(),
  1575  						Reason:             "NoReservation",
  1576  						Message:            "The workload has no reservation",
  1577  					}).
  1578  					Condition(metav1.Condition{
  1579  						Type:               kueue.WorkloadEvicted,
  1580  						Status:             metav1.ConditionTrue,
  1581  						LastTransitionTime: metav1.Now(),
  1582  						Reason:             "Preempted",
  1583  						Message:            "Preempted to accommodate a higher priority Workload",
  1584  					}).
  1585  					SetOrReplaceCondition(metav1.Condition{
  1586  						Type:               kueue.WorkloadQuotaReserved,
  1587  						Status:             metav1.ConditionFalse,
  1588  						LastTransitionTime: metav1.Now(),
  1589  						Reason:             "Pending",
  1590  						Message:            "Preempted to accommodate a higher priority Workload",
  1591  					}).
  1592  					Obj(),
  1593  			},
  1594  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1595  		},
  1596  		"deleted pods in group should not be finalized if the workload doesn't match": {
  1597  			pods: []corev1.Pod{
  1598  				*basePodWrapper.
  1599  					Clone().
  1600  					Label("kueue.x-k8s.io/managed", "true").
  1601  					KueueFinalizer().
  1602  					Queue("test-queue").
  1603  					Group("test-group").
  1604  					GroupTotalCount("2").
  1605  					Delete().
  1606  					Obj(),
  1607  				*basePodWrapper.
  1608  					Clone().
  1609  					Name("pod2").
  1610  					Label("kueue.x-k8s.io/managed", "true").
  1611  					KueueFinalizer().
  1612  					Queue("test-queue").
  1613  					Group("test-group").
  1614  					GroupTotalCount("2").
  1615  					Delete().
  1616  					Obj(),
  1617  			},
  1618  			wantPods: []corev1.Pod{
  1619  				*basePodWrapper.
  1620  					Clone().
  1621  					Label("kueue.x-k8s.io/managed", "true").
  1622  					KueueFinalizer().
  1623  					Queue("test-queue").
  1624  					Group("test-group").
  1625  					GroupTotalCount("2").
  1626  					Delete().
  1627  					Obj(),
  1628  				*basePodWrapper.
  1629  					Clone().
  1630  					Name("pod2").
  1631  					Label("kueue.x-k8s.io/managed", "true").
  1632  					KueueFinalizer().
  1633  					Queue("test-queue").
  1634  					Group("test-group").
  1635  					GroupTotalCount("2").
  1636  					Delete().
  1637  					Obj(),
  1638  			},
  1639  			workloads: []kueue.Workload{
  1640  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1641  					PodSets(*utiltesting.MakePodSet("incorrect-role-name", 1).Request(corev1.ResourceCPU, "1").Obj()).
  1642  					Queue("test-queue").
  1643  					ReserveQuota(
  1644  						utiltesting.MakeAdmission("cq").
  1645  							Assignment(corev1.ResourceCPU, "unit-test-flavor", "2").
  1646  							AssignmentPodCount(2).
  1647  							Obj(),
  1648  					).
  1649  					Admitted(true).
  1650  					Obj(),
  1651  			},
  1652  			wantWorkloads: []kueue.Workload{
  1653  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1654  					PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()).
  1655  					Queue("test-queue").
  1656  					Priority(0).
  1657  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1658  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1659  					Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}).
  1660  					Obj(),
  1661  			},
  1662  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1663  			deleteWorkloads: true,
  1664  			wantEvents: []utiltesting.EventRecord{
  1665  				{
  1666  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1667  					EventType: "Normal",
  1668  					Reason:    "CreatedWorkload",
  1669  					Message:   "Created Workload: ns/test-group",
  1670  				},
  1671  			},
  1672  		},
  1673  		"workload is not deleted if all of the pods in the group are deleted": {
  1674  			pods: []corev1.Pod{
  1675  				*basePodWrapper.
  1676  					Clone().
  1677  					Label("kueue.x-k8s.io/managed", "true").
  1678  					KueueFinalizer().
  1679  					Group("test-group").
  1680  					GroupTotalCount("2").
  1681  					Delete().
  1682  					Obj(),
  1683  				*basePodWrapper.
  1684  					Clone().
  1685  					Name("pod2").
  1686  					Label("kueue.x-k8s.io/managed", "true").
  1687  					KueueFinalizer().
  1688  					Group("test-group").
  1689  					GroupTotalCount("2").
  1690  					Delete().
  1691  					Obj(),
  1692  			},
  1693  			wantPods: []corev1.Pod{
  1694  				*basePodWrapper.
  1695  					Clone().
  1696  					Label("kueue.x-k8s.io/managed", "true").
  1697  					KueueFinalizer().
  1698  					Group("test-group").
  1699  					GroupTotalCount("2").
  1700  					Delete().
  1701  					Obj(),
  1702  				*basePodWrapper.
  1703  					Clone().
  1704  					Name("pod2").
  1705  					Label("kueue.x-k8s.io/managed", "true").
  1706  					KueueFinalizer().
  1707  					Group("test-group").
  1708  					GroupTotalCount("2").
  1709  					Delete().
  1710  					Obj(),
  1711  			},
  1712  			workloads: []kueue.Workload{
  1713  				*utiltesting.MakeWorkload("test-group", "ns").
  1714  					PodSets(
  1715  						*utiltesting.MakePodSet("dc85db45", 2).
  1716  							Request(corev1.ResourceCPU, "1").
  1717  							Obj(),
  1718  					).
  1719  					Queue("user-queue").
  1720  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1721  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1722  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1723  					Admitted(true).
  1724  					Obj(),
  1725  			},
  1726  			wantWorkloads: []kueue.Workload{
  1727  				*utiltesting.MakeWorkload("test-group", "ns").
  1728  					PodSets(
  1729  						*utiltesting.MakePodSet("dc85db45", 2).
  1730  							Request(corev1.ResourceCPU, "1").
  1731  							Obj(),
  1732  					).
  1733  					Queue("user-queue").
  1734  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1735  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1736  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1737  					Admitted(true).
  1738  					Obj(),
  1739  			},
  1740  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1741  		},
  1742  		"workload is not deleted if one pod role is absent from the cluster": {
  1743  			pods: []corev1.Pod{
  1744  				*basePodWrapper.
  1745  					Clone().
  1746  					Label("kueue.x-k8s.io/managed", "true").
  1747  					KueueFinalizer().
  1748  					Group("test-group").
  1749  					GroupTotalCount("2").
  1750  					Delete().
  1751  					Obj(),
  1752  			},
  1753  			wantPods: []corev1.Pod{
  1754  				*basePodWrapper.
  1755  					Clone().
  1756  					Label("kueue.x-k8s.io/managed", "true").
  1757  					KueueFinalizer().
  1758  					Group("test-group").
  1759  					GroupTotalCount("2").
  1760  					Delete().
  1761  					Obj(),
  1762  			},
  1763  			workloads: []kueue.Workload{
  1764  				*utiltesting.MakeWorkload("test-group", "ns").
  1765  					PodSets(
  1766  						*utiltesting.MakePodSet("absent-pod-role", 1).
  1767  							Request(corev1.ResourceCPU, "1").
  1768  							Obj(),
  1769  						*utiltesting.MakePodSet("dc85db45", 1).
  1770  							Request(corev1.ResourceCPU, "1").
  1771  							Obj(),
  1772  					).
  1773  					Queue("user-queue").
  1774  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1775  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1776  					Admitted(true).
  1777  					Obj(),
  1778  			},
  1779  			wantWorkloads: []kueue.Workload{
  1780  				*utiltesting.MakeWorkload("test-group", "ns").
  1781  					PodSets(
  1782  						*utiltesting.MakePodSet("absent-pod-role", 1).
  1783  							Request(corev1.ResourceCPU, "1").
  1784  							Obj(),
  1785  						*utiltesting.MakePodSet("dc85db45", 1).
  1786  							Request(corev1.ResourceCPU, "1").
  1787  							Obj(),
  1788  					).
  1789  					Queue("user-queue").
  1790  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  1791  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1792  					Admitted(true).
  1793  					Obj(),
  1794  			},
  1795  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1796  		},
  1797  		"if pod group is finished and wl is deleted, new workload shouldn't be created": {
  1798  			pods: []corev1.Pod{
  1799  				*basePodWrapper.
  1800  					Clone().
  1801  					Label("kueue.x-k8s.io/managed", "true").
  1802  					KueueFinalizer().
  1803  					Group("test-group").
  1804  					GroupTotalCount("2").
  1805  					StatusPhase(corev1.PodSucceeded).
  1806  					Obj(),
  1807  				*basePodWrapper.
  1808  					Clone().
  1809  					Name("pod2").
  1810  					Label("kueue.x-k8s.io/managed", "true").
  1811  					KueueFinalizer().
  1812  					Group("test-group").
  1813  					GroupTotalCount("2").
  1814  					StatusPhase(corev1.PodSucceeded).
  1815  					Obj(),
  1816  			},
  1817  			wantPods: []corev1.Pod{
  1818  				*basePodWrapper.
  1819  					Clone().
  1820  					Label("kueue.x-k8s.io/managed", "true").
  1821  					Group("test-group").
  1822  					GroupTotalCount("2").
  1823  					StatusPhase(corev1.PodSucceeded).
  1824  					Obj(),
  1825  				*basePodWrapper.
  1826  					Clone().
  1827  					Name("pod2").
  1828  					Label("kueue.x-k8s.io/managed", "true").
  1829  					Group("test-group").
  1830  					GroupTotalCount("2").
  1831  					StatusPhase(corev1.PodSucceeded).
  1832  					Obj(),
  1833  			},
  1834  			workloads:       []kueue.Workload{},
  1835  			wantWorkloads:   []kueue.Workload{},
  1836  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1837  		},
  1838  		"if pod in group is scheduling gated and wl is deleted, workload should be recreated": {
  1839  			pods: []corev1.Pod{
  1840  				*basePodWrapper.
  1841  					Clone().
  1842  					Label("kueue.x-k8s.io/managed", "true").
  1843  					KueueFinalizer().
  1844  					KueueSchedulingGate().
  1845  					Group("test-group").
  1846  					GroupTotalCount("2").
  1847  					Obj(),
  1848  				*basePodWrapper.
  1849  					Clone().
  1850  					Name("pod2").
  1851  					Label("kueue.x-k8s.io/managed", "true").
  1852  					KueueFinalizer().
  1853  					Group("test-group").
  1854  					GroupTotalCount("2").
  1855  					StatusPhase(corev1.PodSucceeded).
  1856  					Obj(),
  1857  			},
  1858  			wantPods: []corev1.Pod{
  1859  				*basePodWrapper.
  1860  					Clone().
  1861  					Label("kueue.x-k8s.io/managed", "true").
  1862  					KueueFinalizer().
  1863  					KueueSchedulingGate().
  1864  					Group("test-group").
  1865  					GroupTotalCount("2").
  1866  					Obj(),
  1867  				*basePodWrapper.
  1868  					Clone().
  1869  					Name("pod2").
  1870  					Label("kueue.x-k8s.io/managed", "true").
  1871  					KueueFinalizer().
  1872  					Group("test-group").
  1873  					GroupTotalCount("2").
  1874  					StatusPhase(corev1.PodSucceeded).
  1875  					Obj(),
  1876  			},
  1877  			workloads: []kueue.Workload{},
  1878  			wantWorkloads: []kueue.Workload{
  1879  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  1880  					PodSets(
  1881  						*utiltesting.MakePodSet("dc85db45", 2).
  1882  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
  1883  							Request(corev1.ResourceCPU, "1").
  1884  							Obj(),
  1885  					).
  1886  					Queue("user-queue").
  1887  					Priority(0).
  1888  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  1889  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  1890  					Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}).
  1891  					Obj(),
  1892  			},
  1893  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1894  			wantEvents: []utiltesting.EventRecord{
  1895  				{
  1896  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1897  					EventType: "Normal",
  1898  					Reason:    "CreatedWorkload",
  1899  					Message:   "Created Workload: ns/test-group",
  1900  				},
  1901  			},
  1902  		},
  1903  		"if there's not enough non-failed pods in the group, workload should not be created": {
  1904  			pods: []corev1.Pod{
  1905  				*basePodWrapper.
  1906  					Clone().
  1907  					Label("kueue.x-k8s.io/managed", "true").
  1908  					KueueFinalizer().
  1909  					KueueSchedulingGate().
  1910  					Group("test-group").
  1911  					GroupTotalCount("2").
  1912  					Obj(),
  1913  				*basePodWrapper.
  1914  					Clone().
  1915  					Name("pod2").
  1916  					Label("kueue.x-k8s.io/managed", "true").
  1917  					KueueFinalizer().
  1918  					Group("test-group").
  1919  					GroupTotalCount("2").
  1920  					StatusPhase(corev1.PodFailed).
  1921  					Obj(),
  1922  			},
  1923  			wantPods: []corev1.Pod{
  1924  				*basePodWrapper.
  1925  					Clone().
  1926  					Label("kueue.x-k8s.io/managed", "true").
  1927  					KueueFinalizer().
  1928  					KueueSchedulingGate().
  1929  					Group("test-group").
  1930  					GroupTotalCount("2").
  1931  					Obj(),
  1932  				*basePodWrapper.
  1933  					Clone().
  1934  					Name("pod2").
  1935  					Label("kueue.x-k8s.io/managed", "true").
  1936  					Group("test-group").
  1937  					GroupTotalCount("2").
  1938  					StatusPhase(corev1.PodFailed).
  1939  					Obj(),
  1940  			},
  1941  			workloads:       []kueue.Workload{},
  1942  			wantWorkloads:   []kueue.Workload{},
  1943  			workloadCmpOpts: defaultWorkloadCmpOpts,
  1944  			wantEvents: []utiltesting.EventRecord{
  1945  				{
  1946  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  1947  					EventType: "Warning",
  1948  					Reason:    "ErrWorkloadCompose",
  1949  					Message:   "'test-group' group has fewer runnable pods than expected",
  1950  				},
  1951  			},
  1952  		},
  1953  		"pod group is considered finished if there is an unretriable pod and no running pods": {
  1954  			pods: []corev1.Pod{
  1955  				*basePodWrapper.
  1956  					Clone().
  1957  					Annotation("kueue.x-k8s.io/retriable-in-group", "false").
  1958  					Label("kueue.x-k8s.io/managed", "true").
  1959  					KueueFinalizer().
  1960  					Group("test-group").
  1961  					GroupTotalCount("3").
  1962  					StatusPhase(corev1.PodFailed).
  1963  					Obj(),
  1964  				*basePodWrapper.
  1965  					Clone().
  1966  					Name("pod2").
  1967  					Label("kueue.x-k8s.io/managed", "true").
  1968  					KueueFinalizer().
  1969  					Group("test-group").
  1970  					GroupTotalCount("3").
  1971  					StatusPhase(corev1.PodSucceeded).
  1972  					Obj(),
  1973  				*basePodWrapper.
  1974  					Clone().
  1975  					Name("pod3").
  1976  					Label("kueue.x-k8s.io/managed", "true").
  1977  					KueueFinalizer().
  1978  					Group("test-group").
  1979  					Request(corev1.ResourceMemory, "1Gi").
  1980  					GroupTotalCount("3").
  1981  					StatusPhase(corev1.PodFailed).
  1982  					Obj(),
  1983  			},
  1984  			wantPods: []corev1.Pod{
  1985  				*basePodWrapper.
  1986  					Clone().
  1987  					Annotation("kueue.x-k8s.io/retriable-in-group", "false").
  1988  					Label("kueue.x-k8s.io/managed", "true").
  1989  					Group("test-group").
  1990  					GroupTotalCount("3").
  1991  					StatusPhase(corev1.PodFailed).
  1992  					Obj(),
  1993  				*basePodWrapper.
  1994  					Clone().
  1995  					Name("pod2").
  1996  					Label("kueue.x-k8s.io/managed", "true").
  1997  					Group("test-group").
  1998  					GroupTotalCount("3").
  1999  					StatusPhase(corev1.PodSucceeded).
  2000  					Obj(),
  2001  				*basePodWrapper.
  2002  					Clone().
  2003  					Name("pod3").
  2004  					Label("kueue.x-k8s.io/managed", "true").
  2005  					Group("test-group").
  2006  					Request(corev1.ResourceMemory, "1Gi").
  2007  					GroupTotalCount("3").
  2008  					StatusPhase(corev1.PodFailed).
  2009  					Obj(),
  2010  			},
  2011  			workloads: []kueue.Workload{
  2012  				*utiltesting.MakeWorkload("test-group", "ns").
  2013  					PodSets(
  2014  						*utiltesting.MakePodSet("a119f908", 1).
  2015  							Request(corev1.ResourceCPU, "1").
  2016  							Request(corev1.ResourceMemory, "1Gi").
  2017  							Obj(),
  2018  						*utiltesting.MakePodSet("dc85db45", 2).
  2019  							Request(corev1.ResourceCPU, "1").
  2020  							Obj(),
  2021  					).
  2022  					Queue("user-queue").
  2023  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2024  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2025  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2026  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2027  					Admitted(true).
  2028  					Obj(),
  2029  			},
  2030  			wantWorkloads: []kueue.Workload{
  2031  				*utiltesting.MakeWorkload("test-group", "ns").
  2032  					PodSets(
  2033  						*utiltesting.MakePodSet("a119f908", 1).
  2034  							Request(corev1.ResourceCPU, "1").
  2035  							Request(corev1.ResourceMemory, "1Gi").
  2036  							Obj(),
  2037  						*utiltesting.MakePodSet("dc85db45", 2).
  2038  							Request(corev1.ResourceCPU, "1").
  2039  							Obj(),
  2040  					).
  2041  					Queue("user-queue").
  2042  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2043  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2044  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2045  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2046  					Admitted(true).
  2047  					Condition(
  2048  						metav1.Condition{
  2049  							Type:    kueue.WorkloadFinished,
  2050  							Status:  metav1.ConditionTrue,
  2051  							Reason:  "JobFinished",
  2052  							Message: "Pods succeeded: 1/3.",
  2053  						},
  2054  					).
  2055  					Obj(),
  2056  			},
  2057  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2058  			wantEvents: []utiltesting.EventRecord{
  2059  				{
  2060  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  2061  					EventType: "Normal",
  2062  					Reason:    "FinishedWorkload",
  2063  					Message:   "Workload 'ns/test-group' is declared finished",
  2064  				},
  2065  			},
  2066  		},
  2067  		"reclaimable pods updated for pod group": {
  2068  			pods: []corev1.Pod{
  2069  				*basePodWrapper.
  2070  					Clone().
  2071  					Label("kueue.x-k8s.io/managed", "true").
  2072  					KueueFinalizer().
  2073  					Group("test-group").
  2074  					GroupTotalCount("3").
  2075  					StatusPhase(corev1.PodFailed).
  2076  					Obj(),
  2077  				*basePodWrapper.
  2078  					Clone().
  2079  					Name("pod2").
  2080  					Label("kueue.x-k8s.io/managed", "true").
  2081  					KueueFinalizer().
  2082  					Group("test-group").
  2083  					GroupTotalCount("3").
  2084  					StatusPhase(corev1.PodRunning).
  2085  					Obj(),
  2086  				*basePodWrapper.
  2087  					Clone().
  2088  					Name("pod3").
  2089  					Label("kueue.x-k8s.io/managed", "true").
  2090  					KueueFinalizer().
  2091  					Group("test-group").
  2092  					Request(corev1.ResourceMemory, "1Gi").
  2093  					GroupTotalCount("3").
  2094  					StatusPhase(corev1.PodSucceeded).
  2095  					Obj(),
  2096  			},
  2097  			wantPods: []corev1.Pod{
  2098  				*basePodWrapper.
  2099  					Clone().
  2100  					Label("kueue.x-k8s.io/managed", "true").
  2101  					KueueFinalizer().
  2102  					Group("test-group").
  2103  					GroupTotalCount("3").
  2104  					StatusPhase(corev1.PodFailed).
  2105  					Obj(),
  2106  				*basePodWrapper.
  2107  					Clone().
  2108  					Name("pod2").
  2109  					Label("kueue.x-k8s.io/managed", "true").
  2110  					KueueFinalizer().
  2111  					Group("test-group").
  2112  					GroupTotalCount("3").
  2113  					StatusPhase(corev1.PodRunning).
  2114  					Obj(),
  2115  				*basePodWrapper.
  2116  					Clone().
  2117  					Name("pod3").
  2118  					Label("kueue.x-k8s.io/managed", "true").
  2119  					KueueFinalizer().
  2120  					Group("test-group").
  2121  					Request(corev1.ResourceMemory, "1Gi").
  2122  					GroupTotalCount("3").
  2123  					StatusPhase(corev1.PodSucceeded).
  2124  					Obj(),
  2125  			},
  2126  			workloads: []kueue.Workload{
  2127  				*utiltesting.MakeWorkload("test-group", "ns").
  2128  					PodSets(
  2129  						*utiltesting.MakePodSet("4ebdd4a6", 1).
  2130  							Request(corev1.ResourceCPU, "1").
  2131  							Request(corev1.ResourceMemory, "1Gi").
  2132  							Obj(),
  2133  						*utiltesting.MakePodSet("dc85db45", 2).
  2134  							Request(corev1.ResourceCPU, "1").
  2135  							Obj(),
  2136  					).
  2137  					Queue("user-queue").
  2138  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2139  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2140  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2141  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2142  					Admitted(true).
  2143  					Obj(),
  2144  			},
  2145  			wantWorkloads: []kueue.Workload{
  2146  				*utiltesting.MakeWorkload("test-group", "ns").
  2147  					PodSets(
  2148  						*utiltesting.MakePodSet("4ebdd4a6", 1).
  2149  							Request(corev1.ResourceCPU, "1").
  2150  							Request(corev1.ResourceMemory, "1Gi").
  2151  							Obj(),
  2152  						*utiltesting.MakePodSet("dc85db45", 2).
  2153  							Request(corev1.ResourceCPU, "1").
  2154  							Obj(),
  2155  					).
  2156  					Queue("user-queue").
  2157  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2158  					Admitted(true).
  2159  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2160  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2161  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2162  					ReclaimablePods(kueue.ReclaimablePod{Name: "4ebdd4a6", Count: 1}).
  2163  					Obj(),
  2164  			},
  2165  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2166  		},
  2167  		"excess pods before wl creation, youngest pods are deleted": {
  2168  			pods: []corev1.Pod{
  2169  				*basePodWrapper.
  2170  					Clone().
  2171  					Label("kueue.x-k8s.io/managed", "true").
  2172  					KueueFinalizer().
  2173  					KueueSchedulingGate().
  2174  					Group("test-group").
  2175  					GroupTotalCount("1").
  2176  					CreationTimestamp(now).
  2177  					Obj(),
  2178  				*basePodWrapper.
  2179  					Clone().
  2180  					Name("pod2").
  2181  					Label("kueue.x-k8s.io/managed", "true").
  2182  					KueueFinalizer().
  2183  					KueueSchedulingGate().
  2184  					Group("test-group").
  2185  					GroupTotalCount("1").
  2186  					CreationTimestamp(now.Add(time.Minute)).
  2187  					Obj(),
  2188  			},
  2189  			wantPods: []corev1.Pod{
  2190  				*basePodWrapper.
  2191  					Clone().
  2192  					Label("kueue.x-k8s.io/managed", "true").
  2193  					KueueFinalizer().
  2194  					KueueSchedulingGate().
  2195  					Group("test-group").
  2196  					GroupTotalCount("1").
  2197  					CreationTimestamp(now).
  2198  					Obj(),
  2199  			},
  2200  			workloads: []kueue.Workload{},
  2201  			wantWorkloads: []kueue.Workload{
  2202  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  2203  					PodSets(
  2204  						*utiltesting.MakePodSet("dc85db45", 1).
  2205  							Request(corev1.ResourceCPU, "1").
  2206  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
  2207  							Obj(),
  2208  					).
  2209  					Queue("user-queue").
  2210  					Priority(0).
  2211  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2212  					Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}).
  2213  					Obj(),
  2214  			},
  2215  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2216  			wantEvents: []utiltesting.EventRecord{
  2217  				{
  2218  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  2219  					EventType: "Normal",
  2220  					Reason:    "CreatedWorkload",
  2221  					Message:   "Created Workload: ns/test-group",
  2222  				},
  2223  				{
  2224  					Key:       types.NamespacedName{Name: "pod2", Namespace: "ns"},
  2225  					EventType: "Normal",
  2226  					Reason:    "ExcessPodDeleted",
  2227  					Message:   "Excess pod deleted",
  2228  				},
  2229  			},
  2230  		},
  2231  		"excess pods before admission, youngest pods are deleted": {
  2232  			pods: []corev1.Pod{
  2233  				*basePodWrapper.
  2234  					Clone().
  2235  					Label("kueue.x-k8s.io/managed", "true").
  2236  					KueueFinalizer().
  2237  					KueueSchedulingGate().
  2238  					Group("test-group").
  2239  					GroupTotalCount("2").
  2240  					CreationTimestamp(now).
  2241  					Obj(),
  2242  				*basePodWrapper.
  2243  					Clone().
  2244  					Name("pod2").
  2245  					Label("kueue.x-k8s.io/managed", "true").
  2246  					KueueFinalizer().
  2247  					KueueSchedulingGate().
  2248  					Group("test-group").
  2249  					GroupTotalCount("2").
  2250  					CreationTimestamp(now.Add(time.Minute)).
  2251  					Obj(),
  2252  				*basePodWrapper.
  2253  					Clone().
  2254  					Name("pod3").
  2255  					Label("kueue.x-k8s.io/managed", "true").
  2256  					KueueFinalizer().
  2257  					KueueSchedulingGate().
  2258  					Group("test-group").
  2259  					CreationTimestamp(now.Add(time.Minute * 2)).
  2260  					GroupTotalCount("2").
  2261  					Obj(),
  2262  			},
  2263  			wantPods: []corev1.Pod{
  2264  				*basePodWrapper.
  2265  					Clone().
  2266  					Label("kueue.x-k8s.io/managed", "true").
  2267  					KueueFinalizer().
  2268  					KueueSchedulingGate().
  2269  					Group("test-group").
  2270  					GroupTotalCount("2").
  2271  					CreationTimestamp(now).
  2272  					Obj(),
  2273  				*basePodWrapper.
  2274  					Clone().
  2275  					Name("pod2").
  2276  					Label("kueue.x-k8s.io/managed", "true").
  2277  					KueueFinalizer().
  2278  					KueueSchedulingGate().
  2279  					Group("test-group").
  2280  					GroupTotalCount("2").
  2281  					CreationTimestamp(now.Add(time.Minute)).
  2282  					Obj(),
  2283  			},
  2284  			workloads: []kueue.Workload{
  2285  				*utiltesting.MakeWorkload("test-group", "ns").
  2286  					PodSets(
  2287  						*utiltesting.MakePodSet("dc85db45", 2).
  2288  							Request(corev1.ResourceCPU, "1").
  2289  							Obj(),
  2290  					).
  2291  					Queue("user-queue").
  2292  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2293  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2294  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2295  					Obj(),
  2296  			},
  2297  			wantWorkloads: []kueue.Workload{
  2298  				*utiltesting.MakeWorkload("test-group", "ns").
  2299  					PodSets(
  2300  						*utiltesting.MakePodSet("dc85db45", 2).
  2301  							Request(corev1.ResourceCPU, "1").
  2302  							Obj(),
  2303  					).
  2304  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2305  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2306  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2307  					Queue("user-queue").
  2308  					Obj(),
  2309  			},
  2310  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2311  			wantEvents: []utiltesting.EventRecord{
  2312  				{
  2313  					Key:       types.NamespacedName{Name: "pod3", Namespace: "ns"},
  2314  					EventType: "Normal",
  2315  					Reason:    "ExcessPodDeleted",
  2316  					Message:   "Excess pod deleted",
  2317  				},
  2318  			},
  2319  		},
  2320  		// In this case, group-total-count is equal to the number of pods in the cluster.
  2321  		// But one of the roles is missing, and another role has an excess pod.
  2322  		"excess pods in pod set after admission, youngest pods are deleted": {
  2323  			pods: []corev1.Pod{
  2324  				*basePodWrapper.
  2325  					Clone().
  2326  					Label("kueue.x-k8s.io/managed", "true").
  2327  					KueueFinalizer().
  2328  					Group("test-group").
  2329  					GroupTotalCount("2").
  2330  					CreationTimestamp(now).
  2331  					Obj(),
  2332  				*basePodWrapper.
  2333  					Clone().
  2334  					Name("pod2").
  2335  					Label("kueue.x-k8s.io/managed", "true").
  2336  					KueueFinalizer().
  2337  					KueueSchedulingGate().
  2338  					Group("test-group").
  2339  					CreationTimestamp(now.Add(time.Minute * 2)).
  2340  					GroupTotalCount("2").
  2341  					Obj(),
  2342  			},
  2343  			wantPods: []corev1.Pod{
  2344  				*basePodWrapper.
  2345  					Clone().
  2346  					Label("kueue.x-k8s.io/managed", "true").
  2347  					KueueFinalizer().
  2348  					Group("test-group").
  2349  					GroupTotalCount("2").
  2350  					CreationTimestamp(now).
  2351  					Obj(),
  2352  			},
  2353  			workloads: []kueue.Workload{
  2354  				*utiltesting.MakeWorkload("test-group", "ns").
  2355  					PodSets(
  2356  						*utiltesting.MakePodSet("aaf269e6", 1).
  2357  							Request(corev1.ResourceCPU, "1").
  2358  							Obj(),
  2359  						*utiltesting.MakePodSet("dc85db45", 1).
  2360  							Request(corev1.ResourceCPU, "1").
  2361  							Obj(),
  2362  					).
  2363  					Queue("user-queue").
  2364  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2365  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2366  					Admitted(true).
  2367  					Obj(),
  2368  			},
  2369  			wantWorkloads: []kueue.Workload{
  2370  				*utiltesting.MakeWorkload("test-group", "ns").
  2371  					PodSets(
  2372  						*utiltesting.MakePodSet("aaf269e6", 1).
  2373  							Request(corev1.ResourceCPU, "1").
  2374  							Obj(),
  2375  						*utiltesting.MakePodSet("dc85db45", 1).
  2376  							Request(corev1.ResourceCPU, "1").
  2377  							Obj(),
  2378  					).
  2379  					Queue("user-queue").
  2380  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2381  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2382  					Admitted(true).
  2383  					Obj(),
  2384  			},
  2385  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2386  			excessPodsExpectations: []keyUIDs{{
  2387  				key:  types.NamespacedName{Name: "another-group", Namespace: "ns"},
  2388  				uids: []types.UID{"pod"},
  2389  			}},
  2390  			wantEvents: []utiltesting.EventRecord{
  2391  				{
  2392  					Key:       types.NamespacedName{Name: "pod2", Namespace: "ns"},
  2393  					EventType: "Normal",
  2394  					Reason:    "ExcessPodDeleted",
  2395  					Message:   "Excess pod deleted",
  2396  				},
  2397  			},
  2398  		},
  2399  		"waiting to observe previous deletion of excess pod, no pods are deleted": {
  2400  			pods: []corev1.Pod{
  2401  				*basePodWrapper.
  2402  					Clone().
  2403  					Label("kueue.x-k8s.io/managed", "true").
  2404  					KueueFinalizer().
  2405  					Group("test-group").
  2406  					GroupTotalCount("1").
  2407  					CreationTimestamp(now).
  2408  					Obj(),
  2409  				*basePodWrapper.
  2410  					Clone().
  2411  					Name("pod2").
  2412  					UID("pod2").
  2413  					Label("kueue.x-k8s.io/managed", "true").
  2414  					KueueFinalizer().
  2415  					KueueSchedulingGate().
  2416  					Group("test-group").
  2417  					CreationTimestamp(now.Add(time.Minute)).
  2418  					GroupTotalCount("1").
  2419  					Obj(),
  2420  				*basePodWrapper.
  2421  					Clone().
  2422  					Name("pod3").
  2423  					Label("kueue.x-k8s.io/managed", "true").
  2424  					KueueFinalizer().
  2425  					KueueSchedulingGate().
  2426  					Group("test-group").
  2427  					CreationTimestamp(now.Add(time.Minute)).
  2428  					GroupTotalCount("1").
  2429  					Obj(),
  2430  			},
  2431  			wantPods: []corev1.Pod{
  2432  				*basePodWrapper.
  2433  					Clone().
  2434  					Label("kueue.x-k8s.io/managed", "true").
  2435  					KueueFinalizer().
  2436  					Group("test-group").
  2437  					GroupTotalCount("1").
  2438  					CreationTimestamp(now).
  2439  					Obj(),
  2440  				*basePodWrapper.
  2441  					Clone().
  2442  					Name("pod2").
  2443  					UID("pod2").
  2444  					Label("kueue.x-k8s.io/managed", "true").
  2445  					KueueFinalizer().
  2446  					KueueSchedulingGate().
  2447  					Group("test-group").
  2448  					CreationTimestamp(now.Add(time.Minute)).
  2449  					GroupTotalCount("1").
  2450  					Obj(),
  2451  				*basePodWrapper.
  2452  					Clone().
  2453  					Name("pod3").
  2454  					Label("kueue.x-k8s.io/managed", "true").
  2455  					KueueFinalizer().
  2456  					KueueSchedulingGate().
  2457  					Group("test-group").
  2458  					CreationTimestamp(now.Add(time.Minute)).
  2459  					GroupTotalCount("1").
  2460  					Obj(),
  2461  			},
  2462  			workloads: []kueue.Workload{
  2463  				*utiltesting.MakeWorkload("test-group", "ns").
  2464  					PodSets(
  2465  						*utiltesting.MakePodSet("dc85db45", 1).
  2466  							Request(corev1.ResourceCPU, "1").
  2467  							Obj(),
  2468  					).
  2469  					Queue("user-queue").
  2470  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2471  					Admitted(true).
  2472  					Obj(),
  2473  			},
  2474  			wantWorkloads: []kueue.Workload{
  2475  				*utiltesting.MakeWorkload("test-group", "ns").
  2476  					PodSets(
  2477  						*utiltesting.MakePodSet("dc85db45", 1).
  2478  							Request(corev1.ResourceCPU, "1").
  2479  							Obj(),
  2480  					).
  2481  					Queue("user-queue").
  2482  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2483  					Admitted(true).
  2484  					Obj(),
  2485  			},
  2486  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2487  			excessPodsExpectations: []keyUIDs{{
  2488  				key:  types.NamespacedName{Name: "test-group", Namespace: "ns"},
  2489  				uids: []types.UID{"pod2"},
  2490  			}},
  2491  		},
  2492  		"delete excess pod that is gated": {
  2493  			pods: []corev1.Pod{
  2494  				*basePodWrapper.
  2495  					Clone().
  2496  					Label("kueue.x-k8s.io/managed", "true").
  2497  					KueueFinalizer().
  2498  					Group("test-group").
  2499  					GroupTotalCount("2").
  2500  					CreationTimestamp(now).
  2501  					Obj(),
  2502  				*basePodWrapper.
  2503  					Clone().
  2504  					Name("pod2").
  2505  					UID("pod2").
  2506  					Label("kueue.x-k8s.io/managed", "true").
  2507  					KueueFinalizer().
  2508  					Group("test-group").
  2509  					CreationTimestamp(now.Add(time.Minute)).
  2510  					GroupTotalCount("2").
  2511  					Obj(),
  2512  				*basePodWrapper.
  2513  					Clone().
  2514  					Name("pod3").
  2515  					Label("kueue.x-k8s.io/managed", "true").
  2516  					KueueFinalizer().
  2517  					KueueSchedulingGate().
  2518  					Group("test-group").
  2519  					CreationTimestamp(now.Add(time.Minute)).
  2520  					GroupTotalCount("2").
  2521  					Obj(),
  2522  			},
  2523  			wantPods: []corev1.Pod{
  2524  				*basePodWrapper.
  2525  					Clone().
  2526  					Label("kueue.x-k8s.io/managed", "true").
  2527  					KueueFinalizer().
  2528  					Group("test-group").
  2529  					GroupTotalCount("2").
  2530  					CreationTimestamp(now).
  2531  					Obj(),
  2532  				*basePodWrapper.
  2533  					Clone().
  2534  					Name("pod2").
  2535  					UID("pod2").
  2536  					Label("kueue.x-k8s.io/managed", "true").
  2537  					KueueFinalizer().
  2538  					Group("test-group").
  2539  					CreationTimestamp(now.Add(time.Minute)).
  2540  					GroupTotalCount("2").
  2541  					Obj(),
  2542  			},
  2543  			workloads: []kueue.Workload{
  2544  				*utiltesting.MakeWorkload("test-group", "ns").
  2545  					PodSets(
  2546  						*utiltesting.MakePodSet("dc85db45", 2).
  2547  							Request(corev1.ResourceCPU, "1").
  2548  							Obj(),
  2549  					).
  2550  					Queue("user-queue").
  2551  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2552  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "pod2").
  2553  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2554  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2555  					Admitted(true).
  2556  					Obj(),
  2557  			},
  2558  			wantWorkloads: []kueue.Workload{
  2559  				*utiltesting.MakeWorkload("test-group", "ns").
  2560  					PodSets(
  2561  						*utiltesting.MakePodSet("dc85db45", 2).
  2562  							Request(corev1.ResourceCPU, "1").
  2563  							Obj(),
  2564  					).
  2565  					Queue("user-queue").
  2566  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2567  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "pod2").
  2568  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2569  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2570  					Admitted(true).
  2571  					Obj(),
  2572  			},
  2573  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2574  			wantEvents: []utiltesting.EventRecord{
  2575  				{
  2576  					Key:       types.NamespacedName{Name: "pod3", Namespace: "ns"},
  2577  					EventType: "Normal",
  2578  					Reason:    "ExcessPodDeleted",
  2579  					Message:   "Excess pod deleted",
  2580  				},
  2581  			},
  2582  		},
  2583  		// If an excess pod is already deleted and finalized, but an external finalizer blocks
  2584  		// pod deletion, kueue should ignore such a pod, when creating a workload.
  2585  		"deletion of excess pod is blocked by another controller": {
  2586  			pods: []corev1.Pod{
  2587  				*basePodWrapper.
  2588  					Clone().
  2589  					Label("kueue.x-k8s.io/managed", "true").
  2590  					KueueFinalizer().
  2591  					KueueSchedulingGate().
  2592  					Group("test-group").
  2593  					GroupTotalCount("1").
  2594  					CreationTimestamp(now).
  2595  					Obj(),
  2596  				*basePodWrapper.
  2597  					Clone().
  2598  					Name("pod2").
  2599  					Label("kueue.x-k8s.io/managed", "true").
  2600  					KueueSchedulingGate().
  2601  					Finalizer("kubernetes").
  2602  					Group("test-group").
  2603  					GroupTotalCount("1").
  2604  					CreationTimestamp(now.Add(time.Minute)).
  2605  					Delete().
  2606  					Obj(),
  2607  			},
  2608  			wantPods: []corev1.Pod{
  2609  				*basePodWrapper.
  2610  					Clone().
  2611  					Label("kueue.x-k8s.io/managed", "true").
  2612  					KueueFinalizer().
  2613  					KueueSchedulingGate().
  2614  					Group("test-group").
  2615  					GroupTotalCount("1").
  2616  					CreationTimestamp(now).
  2617  					Obj(),
  2618  				*basePodWrapper.
  2619  					Clone().
  2620  					Name("pod2").
  2621  					Label("kueue.x-k8s.io/managed", "true").
  2622  					KueueSchedulingGate().
  2623  					Finalizer("kubernetes").
  2624  					Group("test-group").
  2625  					GroupTotalCount("1").
  2626  					CreationTimestamp(now.Add(time.Minute)).
  2627  					Delete().
  2628  					Obj(),
  2629  			},
  2630  			workloads: []kueue.Workload{},
  2631  			wantWorkloads: []kueue.Workload{
  2632  				*utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  2633  					PodSets(
  2634  						*utiltesting.MakePodSet("dc85db45", 1).
  2635  							Request(corev1.ResourceCPU, "1").
  2636  							SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}).
  2637  							Obj(),
  2638  					).
  2639  					Queue("user-queue").
  2640  					Priority(0).
  2641  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  2642  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2643  					Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}).
  2644  					Obj(),
  2645  			},
  2646  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2647  			wantEvents: []utiltesting.EventRecord{
  2648  				{
  2649  					Key:       types.NamespacedName{Name: "pod", Namespace: "ns"},
  2650  					EventType: "Normal",
  2651  					Reason:    "CreatedWorkload",
  2652  					Message:   "Created Workload: ns/test-group",
  2653  				},
  2654  			},
  2655  		},
  2656  		"deleted pods in incomplete group are finalized": {
  2657  			pods: []corev1.Pod{
  2658  				*basePodWrapper.
  2659  					Clone().
  2660  					Name("p1").
  2661  					Label("kueue.x-k8s.io/managed", "true").
  2662  					KueueFinalizer().
  2663  					KueueSchedulingGate().
  2664  					Group("group").
  2665  					GroupTotalCount("3").
  2666  					StatusPhase(corev1.PodPending).
  2667  					Delete().
  2668  					Obj(),
  2669  				*basePodWrapper.
  2670  					Clone().
  2671  					Name("p2").
  2672  					Label("kueue.x-k8s.io/managed", "true").
  2673  					KueueFinalizer().
  2674  					KueueSchedulingGate().
  2675  					Group("group").
  2676  					GroupTotalCount("3").
  2677  					StatusPhase(corev1.PodPending).
  2678  					Delete().
  2679  					Obj(),
  2680  			},
  2681  			wantEvents: []utiltesting.EventRecord{
  2682  				{
  2683  					Key:       types.NamespacedName{Name: "p1", Namespace: "ns"},
  2684  					EventType: "Warning",
  2685  					Reason:    "ErrWorkloadCompose",
  2686  					Message:   "'group' group has fewer runnable pods than expected",
  2687  				},
  2688  			},
  2689  		},
  2690  		"finalize workload for non existent pod": {
  2691  			reconcileKey: &types.NamespacedName{Namespace: "ns", Name: "deleted_pod"},
  2692  			workloads: []kueue.Workload{
  2693  				*utiltesting.MakeWorkload("test-group", "ns").
  2694  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted_pod", "").
  2695  					Finalizers(kueue.ResourceInUseFinalizerName).
  2696  					Obj(),
  2697  			},
  2698  			wantWorkloads: []kueue.Workload{
  2699  				*utiltesting.MakeWorkload("test-group", "ns").
  2700  					ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted_pod", "").
  2701  					Obj(),
  2702  			},
  2703  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2704  		},
  2705  		"replacement pods are owning the workload": {
  2706  			pods: []corev1.Pod{
  2707  				*basePodWrapper.
  2708  					Clone().
  2709  					Name("pod1").
  2710  					Label("kueue.x-k8s.io/managed", "true").
  2711  					Group("test-group").
  2712  					GroupTotalCount("2").
  2713  					StatusPhase(corev1.PodFailed).
  2714  					Obj(),
  2715  				*basePodWrapper.
  2716  					Clone().
  2717  					Name("pod2").
  2718  					Label("kueue.x-k8s.io/managed", "true").
  2719  					KueueFinalizer().
  2720  					Delete().
  2721  					Group("test-group").
  2722  					GroupTotalCount("2").
  2723  					Obj(),
  2724  				*basePodWrapper.
  2725  					Clone().
  2726  					Name("replacement-for-pod1").
  2727  					Label("kueue.x-k8s.io/managed", "true").
  2728  					KueueFinalizer().
  2729  					Group("test-group").
  2730  					GroupTotalCount("2").
  2731  					Obj(),
  2732  			},
  2733  			wantPods: []corev1.Pod{
  2734  				*basePodWrapper.
  2735  					Clone().
  2736  					Name("pod1").
  2737  					Label("kueue.x-k8s.io/managed", "true").
  2738  					Group("test-group").
  2739  					GroupTotalCount("2").
  2740  					StatusPhase(corev1.PodFailed).
  2741  					Obj(),
  2742  				*basePodWrapper.
  2743  					Clone().
  2744  					Name("pod2").
  2745  					Label("kueue.x-k8s.io/managed", "true").
  2746  					KueueFinalizer().
  2747  					Delete().
  2748  					Group("test-group").
  2749  					GroupTotalCount("2").
  2750  					Obj(),
  2751  				*basePodWrapper.
  2752  					Clone().
  2753  					Name("replacement-for-pod1").
  2754  					Label("kueue.x-k8s.io/managed", "true").
  2755  					KueueFinalizer().
  2756  					Group("test-group").
  2757  					GroupTotalCount("2").
  2758  					Obj(),
  2759  			},
  2760  			workloads: []kueue.Workload{
  2761  				*utiltesting.MakeWorkload("test-group", "ns").
  2762  					PodSets(
  2763  						*utiltesting.MakePodSet("dc85db45", 3).
  2764  							Request(corev1.ResourceCPU, "1").
  2765  							Obj(),
  2766  					).
  2767  					Queue("user-queue").
  2768  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid").
  2769  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2770  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2771  					Admitted(true).
  2772  					Obj(),
  2773  			},
  2774  			wantWorkloads: []kueue.Workload{
  2775  				*utiltesting.MakeWorkload("test-group", "ns").
  2776  					PodSets(
  2777  						*utiltesting.MakePodSet("dc85db45", 3).
  2778  							Request(corev1.ResourceCPU, "1").
  2779  							Obj(),
  2780  					).
  2781  					Queue("user-queue").
  2782  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid").
  2783  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2784  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement-for-pod1", "test-uid").
  2785  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  2786  					Admitted(true).
  2787  					Obj(),
  2788  			},
  2789  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2790  			wantEvents: []utiltesting.EventRecord{
  2791  				{
  2792  					Key:       types.NamespacedName{Name: "test-group", Namespace: "ns"},
  2793  					EventType: "Normal",
  2794  					Reason:    "OwnerReferencesAdded",
  2795  					Message:   "Added 1 owner reference(s)",
  2796  				},
  2797  			},
  2798  		},
  2799  		"all pods in a group should receive the event about preemption, unless already terminating": {
  2800  			pods: []corev1.Pod{
  2801  				*basePodWrapper.
  2802  					Clone().
  2803  					Name("pod1").
  2804  					Label("kueue.x-k8s.io/managed", "true").
  2805  					KueueFinalizer().
  2806  					Group("test-group").
  2807  					GroupTotalCount("3").
  2808  					Obj(),
  2809  				*basePodWrapper.
  2810  					Clone().
  2811  					Name("pod2").
  2812  					Label("kueue.x-k8s.io/managed", "true").
  2813  					KueueFinalizer().
  2814  					Delete().
  2815  					Group("test-group").
  2816  					GroupTotalCount("3").
  2817  					Obj(),
  2818  				*basePodWrapper.
  2819  					Clone().
  2820  					Name("pod3").
  2821  					Label("kueue.x-k8s.io/managed", "true").
  2822  					KueueFinalizer().
  2823  					Group("test-group").
  2824  					GroupTotalCount("3").
  2825  					Obj(),
  2826  			},
  2827  			wantPods: []corev1.Pod{
  2828  				*basePodWrapper.
  2829  					Clone().
  2830  					Name("pod1").
  2831  					Label("kueue.x-k8s.io/managed", "true").
  2832  					KueueFinalizer().
  2833  					Group("test-group").
  2834  					GroupTotalCount("3").
  2835  					StatusConditions(corev1.PodCondition{
  2836  						Type:    "TerminationTarget",
  2837  						Status:  corev1.ConditionTrue,
  2838  						Reason:  "StoppedByKueue",
  2839  						Message: "Preempted to accommodate a higher priority Workload",
  2840  					}).
  2841  					Obj(),
  2842  				*basePodWrapper.
  2843  					Clone().
  2844  					Name("pod2").
  2845  					Label("kueue.x-k8s.io/managed", "true").
  2846  					KueueFinalizer().
  2847  					Delete().
  2848  					Group("test-group").
  2849  					GroupTotalCount("3").
  2850  					Obj(),
  2851  				*basePodWrapper.
  2852  					Clone().
  2853  					Name("pod3").
  2854  					Label("kueue.x-k8s.io/managed", "true").
  2855  					KueueFinalizer().
  2856  					Group("test-group").
  2857  					GroupTotalCount("3").
  2858  					StatusConditions(corev1.PodCondition{
  2859  						Type:    "TerminationTarget",
  2860  						Status:  corev1.ConditionTrue,
  2861  						Reason:  "StoppedByKueue",
  2862  						Message: "Preempted to accommodate a higher priority Workload",
  2863  					}).
  2864  					Obj(),
  2865  			},
  2866  			workloads: []kueue.Workload{
  2867  				*utiltesting.MakeWorkload("test-group", "ns").
  2868  					PodSets(
  2869  						*utiltesting.MakePodSet("dc85db45", 3).
  2870  							Request(corev1.ResourceCPU, "1").
  2871  							Obj(),
  2872  					).
  2873  					Queue("user-queue").
  2874  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid").
  2875  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2876  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2877  					Condition(metav1.Condition{
  2878  						Type:               kueue.WorkloadEvicted,
  2879  						Status:             metav1.ConditionTrue,
  2880  						LastTransitionTime: metav1.Now(),
  2881  						Reason:             "Preempted",
  2882  						Message:            "Preempted to accommodate a higher priority Workload",
  2883  					}).
  2884  					Obj(),
  2885  			},
  2886  			wantWorkloads: []kueue.Workload{
  2887  				*utiltesting.MakeWorkload("test-group", "ns").
  2888  					PodSets(
  2889  						*utiltesting.MakePodSet("dc85db45", 3).
  2890  							Request(corev1.ResourceCPU, "1").
  2891  							Obj(),
  2892  					).
  2893  					Queue("user-queue").
  2894  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid").
  2895  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid").
  2896  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid").
  2897  					Condition(metav1.Condition{
  2898  						Type:               kueue.WorkloadEvicted,
  2899  						Status:             metav1.ConditionTrue,
  2900  						LastTransitionTime: metav1.Now(),
  2901  						Reason:             "Preempted",
  2902  						Message:            "Preempted to accommodate a higher priority Workload",
  2903  					}).
  2904  					Obj(),
  2905  			},
  2906  			workloadCmpOpts: defaultWorkloadCmpOpts,
  2907  			wantEvents: []utiltesting.EventRecord{
  2908  				{
  2909  					Key:       types.NamespacedName{Name: "pod1", Namespace: "ns"},
  2910  					EventType: "Normal",
  2911  					Reason:    "Stopped",
  2912  					Message:   "Preempted to accommodate a higher priority Workload",
  2913  				},
  2914  				{
  2915  					Key:       types.NamespacedName{Name: "pod3", Namespace: "ns"},
  2916  					EventType: "Normal",
  2917  					Reason:    "Stopped",
  2918  					Message:   "Preempted to accommodate a higher priority Workload",
  2919  				},
  2920  			},
  2921  		},
  2922  		"the failed pods are finalized in order": {
  2923  			pods: []corev1.Pod{
  2924  				*basePodWrapper.
  2925  					Clone().
  2926  					Name("active-pod").
  2927  					Label("kueue.x-k8s.io/managed", "true").
  2928  					KueueFinalizer().
  2929  					Group("test-group").
  2930  					GroupTotalCount("4").
  2931  					Obj(),
  2932  				*basePodWrapper.
  2933  					Clone().
  2934  					Name("finished-with-error").
  2935  					Label("kueue.x-k8s.io/managed", "true").
  2936  					KueueFinalizer().
  2937  					Group("test-group").
  2938  					GroupTotalCount("4").
  2939  					StatusPhase(corev1.PodFailed).
  2940  					StatusConditions(corev1.PodCondition{
  2941  						Type:               corev1.ContainersReady,
  2942  						Status:             corev1.ConditionFalse,
  2943  						Reason:             string(corev1.PodFailed),
  2944  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  2945  					}).
  2946  					Obj(),
  2947  				*basePodWrapper.
  2948  					Clone().
  2949  					Name("deleted").
  2950  					Label("kueue.x-k8s.io/managed", "true").
  2951  					KueueFinalizer().
  2952  					Group("test-group").
  2953  					GroupTotalCount("4").
  2954  					StatusPhase(corev1.PodFailed).
  2955  					DeletionTimestamp(now.Add(-4 * time.Minute)).
  2956  					StatusConditions(corev1.PodCondition{
  2957  						Type:               corev1.ContainersReady,
  2958  						Status:             corev1.ConditionFalse,
  2959  						Reason:             string(corev1.PodFailed),
  2960  						LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(),
  2961  					}).
  2962  					Obj(),
  2963  				*basePodWrapper.
  2964  					Clone().
  2965  					Name("finished-with-error2").
  2966  					Label("kueue.x-k8s.io/managed", "true").
  2967  					KueueFinalizer().
  2968  					Group("test-group").
  2969  					GroupTotalCount("4").
  2970  					StatusPhase(corev1.PodFailed).
  2971  					StatusConditions(corev1.PodCondition{
  2972  						Type:               corev1.ContainersReady,
  2973  						Status:             corev1.ConditionFalse,
  2974  						Reason:             string(corev1.PodFailed),
  2975  						LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(),
  2976  					}).
  2977  					Obj(),
  2978  				*basePodWrapper.
  2979  					Clone().
  2980  					Name("replacement1").
  2981  					Label("kueue.x-k8s.io/managed", "true").
  2982  					KueueFinalizer().
  2983  					Group("test-group").
  2984  					GroupTotalCount("4").
  2985  					Obj(),
  2986  				*basePodWrapper.
  2987  					Clone().
  2988  					Name("replacement2").
  2989  					Label("kueue.x-k8s.io/managed", "true").
  2990  					KueueFinalizer().
  2991  					Group("test-group").
  2992  					GroupTotalCount("4").
  2993  					Obj(),
  2994  			},
  2995  			wantPods: []corev1.Pod{
  2996  				*basePodWrapper.
  2997  					Clone().
  2998  					Name("active-pod").
  2999  					Label("kueue.x-k8s.io/managed", "true").
  3000  					KueueFinalizer().
  3001  					Group("test-group").
  3002  					GroupTotalCount("4").
  3003  					Obj(),
  3004  				*basePodWrapper.
  3005  					Clone().
  3006  					Name("finished-with-error").
  3007  					Label("kueue.x-k8s.io/managed", "true").
  3008  					Group("test-group").
  3009  					GroupTotalCount("4").
  3010  					StatusPhase(corev1.PodFailed).
  3011  					StatusConditions(corev1.PodCondition{
  3012  						Type:               corev1.ContainersReady,
  3013  						Status:             corev1.ConditionFalse,
  3014  						Reason:             string(corev1.PodFailed),
  3015  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  3016  					}).
  3017  					Obj(),
  3018  				*basePodWrapper.
  3019  					Clone().
  3020  					Name("finished-with-error2").
  3021  					Label("kueue.x-k8s.io/managed", "true").
  3022  					KueueFinalizer().
  3023  					Group("test-group").
  3024  					GroupTotalCount("4").
  3025  					StatusPhase(corev1.PodFailed).
  3026  					StatusConditions(corev1.PodCondition{
  3027  						Type:               corev1.ContainersReady,
  3028  						Status:             corev1.ConditionFalse,
  3029  						Reason:             string(corev1.PodFailed),
  3030  						LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(),
  3031  					}).
  3032  					Obj(),
  3033  				*basePodWrapper.
  3034  					Clone().
  3035  					Name("replacement1").
  3036  					Label("kueue.x-k8s.io/managed", "true").
  3037  					KueueFinalizer().
  3038  					Group("test-group").
  3039  					GroupTotalCount("4").
  3040  					Obj(),
  3041  				*basePodWrapper.
  3042  					Clone().
  3043  					Name("replacement2").
  3044  					Label("kueue.x-k8s.io/managed", "true").
  3045  					KueueFinalizer().
  3046  					Group("test-group").
  3047  					GroupTotalCount("4").
  3048  					Obj(),
  3049  			},
  3050  			workloads: []kueue.Workload{
  3051  				*utiltesting.MakeWorkload("test-group", "ns").
  3052  					PodSets(
  3053  						*utiltesting.MakePodSet("dc85db45", 4).
  3054  							Request(corev1.ResourceCPU, "1").
  3055  							Obj(),
  3056  					).
  3057  					Queue("user-queue").
  3058  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid").
  3059  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3060  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted", "test-uid").
  3061  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error2", "test-uid").
  3062  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3063  					Admitted(true).
  3064  					Obj(),
  3065  			},
  3066  			wantWorkloads: []kueue.Workload{
  3067  				*utiltesting.MakeWorkload("test-group", "ns").
  3068  					PodSets(
  3069  						*utiltesting.MakePodSet("dc85db45", 4).
  3070  							Request(corev1.ResourceCPU, "1").
  3071  							Obj(),
  3072  					).
  3073  					Queue("user-queue").
  3074  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid").
  3075  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3076  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted", "test-uid").
  3077  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error2", "test-uid").
  3078  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement1", "test-uid").
  3079  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement2", "test-uid").
  3080  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3081  					Admitted(true).
  3082  					Obj(),
  3083  			},
  3084  			workloadCmpOpts: defaultWorkloadCmpOpts,
  3085  			wantEvents: []utiltesting.EventRecord{
  3086  				{
  3087  					Key:       types.NamespacedName{Name: "test-group", Namespace: "ns"},
  3088  					EventType: "Normal",
  3089  					Reason:    "OwnerReferencesAdded",
  3090  					Message:   "Added 2 owner reference(s)",
  3091  				},
  3092  			},
  3093  		},
  3094  		"no failed pods are finalized while waiting for expectations": {
  3095  			pods: []corev1.Pod{
  3096  				*basePodWrapper.
  3097  					Clone().
  3098  					Name("active-pod").
  3099  					Label("kueue.x-k8s.io/managed", "true").
  3100  					KueueFinalizer().
  3101  					Group("test-group").
  3102  					GroupTotalCount("2").
  3103  					Obj(),
  3104  				*basePodWrapper.
  3105  					Clone().
  3106  					Name("finished-with-error").
  3107  					Label("kueue.x-k8s.io/managed", "true").
  3108  					KueueFinalizer().
  3109  					Group("test-group").
  3110  					GroupTotalCount("2").
  3111  					StatusPhase(corev1.PodFailed).
  3112  					StatusConditions(corev1.PodCondition{
  3113  						Type:               corev1.ContainersReady,
  3114  						Status:             corev1.ConditionFalse,
  3115  						Reason:             string(corev1.PodFailed),
  3116  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  3117  					}).
  3118  					Obj(),
  3119  				*basePodWrapper.
  3120  					Clone().
  3121  					Name("replacement").
  3122  					Label("kueue.x-k8s.io/managed", "true").
  3123  					KueueFinalizer().
  3124  					Group("test-group").
  3125  					GroupTotalCount("2").
  3126  					Obj(),
  3127  			},
  3128  			wantPods: []corev1.Pod{
  3129  				*basePodWrapper.
  3130  					Clone().
  3131  					Name("active-pod").
  3132  					Label("kueue.x-k8s.io/managed", "true").
  3133  					KueueFinalizer().
  3134  					Group("test-group").
  3135  					GroupTotalCount("2").
  3136  					Obj(),
  3137  				*basePodWrapper.
  3138  					Clone().
  3139  					Name("finished-with-error").
  3140  					Label("kueue.x-k8s.io/managed", "true").
  3141  					KueueFinalizer().
  3142  					Group("test-group").
  3143  					GroupTotalCount("2").
  3144  					StatusPhase(corev1.PodFailed).
  3145  					StatusConditions(corev1.PodCondition{
  3146  						Type:               corev1.ContainersReady,
  3147  						Status:             corev1.ConditionFalse,
  3148  						Reason:             string(corev1.PodFailed),
  3149  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  3150  					}).
  3151  					Obj(),
  3152  				*basePodWrapper.
  3153  					Clone().
  3154  					Name("replacement").
  3155  					Label("kueue.x-k8s.io/managed", "true").
  3156  					KueueFinalizer().
  3157  					Group("test-group").
  3158  					GroupTotalCount("2").
  3159  					Obj(),
  3160  			},
  3161  			workloads: []kueue.Workload{
  3162  				*utiltesting.MakeWorkload("test-group", "ns").
  3163  					PodSets(
  3164  						*utiltesting.MakePodSet("dc85db45", 2).
  3165  							Request(corev1.ResourceCPU, "1").
  3166  							Obj(),
  3167  					).
  3168  					Queue("user-queue").
  3169  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid").
  3170  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3171  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3172  					Admitted(true).
  3173  					Obj(),
  3174  			},
  3175  			wantWorkloads: []kueue.Workload{
  3176  				*utiltesting.MakeWorkload("test-group", "ns").
  3177  					PodSets(
  3178  						*utiltesting.MakePodSet("dc85db45", 2).
  3179  							Request(corev1.ResourceCPU, "1").
  3180  							Obj(),
  3181  					).
  3182  					Queue("user-queue").
  3183  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid").
  3184  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3185  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3186  					Admitted(true).
  3187  					Obj(),
  3188  			},
  3189  			workloadCmpOpts: defaultWorkloadCmpOpts,
  3190  			excessPodsExpectations: []keyUIDs{{
  3191  				key:  types.NamespacedName{Name: "test-group", Namespace: "ns"},
  3192  				uids: []types.UID{"some-other-pod"},
  3193  			}},
  3194  		},
  3195  		"no unnecessary additional failed pods are finalized": {
  3196  			pods: []corev1.Pod{
  3197  				*basePodWrapper.
  3198  					Clone().
  3199  					Name("finished-with-error").
  3200  					Label("kueue.x-k8s.io/managed", "true").
  3201  					KueueFinalizer().
  3202  					Group("test-group").
  3203  					GroupTotalCount("2").
  3204  					StatusPhase(corev1.PodFailed).
  3205  					StatusConditions(corev1.PodCondition{
  3206  						Type:               corev1.ContainersReady,
  3207  						Status:             corev1.ConditionFalse,
  3208  						Reason:             string(corev1.PodFailed),
  3209  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  3210  					}).
  3211  					Obj(),
  3212  				*basePodWrapper.
  3213  					Clone().
  3214  					Name("finished-with-error-no-finalizer").
  3215  					Label("kueue.x-k8s.io/managed", "true").
  3216  					Group("test-group").
  3217  					GroupTotalCount("2").
  3218  					StatusPhase(corev1.PodFailed).
  3219  					StatusConditions(corev1.PodCondition{
  3220  						Type:               corev1.ContainersReady,
  3221  						Status:             corev1.ConditionFalse,
  3222  						Reason:             string(corev1.PodFailed),
  3223  						LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(),
  3224  					}).
  3225  					Obj(),
  3226  				*basePodWrapper.
  3227  					Clone().
  3228  					Name("replacement").
  3229  					Label("kueue.x-k8s.io/managed", "true").
  3230  					KueueFinalizer().
  3231  					Group("test-group").
  3232  					GroupTotalCount("2").
  3233  					Obj(),
  3234  			},
  3235  			wantPods: []corev1.Pod{
  3236  				*basePodWrapper.
  3237  					Clone().
  3238  					Name("finished-with-error").
  3239  					Label("kueue.x-k8s.io/managed", "true").
  3240  					KueueFinalizer().
  3241  					Group("test-group").
  3242  					GroupTotalCount("2").
  3243  					StatusPhase(corev1.PodFailed).
  3244  					StatusConditions(corev1.PodCondition{
  3245  						Type:               corev1.ContainersReady,
  3246  						Status:             corev1.ConditionFalse,
  3247  						Reason:             string(corev1.PodFailed),
  3248  						LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(),
  3249  					}).
  3250  					Obj(),
  3251  				*basePodWrapper.
  3252  					Clone().
  3253  					Name("finished-with-error-no-finalizer").
  3254  					Label("kueue.x-k8s.io/managed", "true").
  3255  					Group("test-group").
  3256  					GroupTotalCount("2").
  3257  					StatusPhase(corev1.PodFailed).
  3258  					StatusConditions(corev1.PodCondition{
  3259  						Type:               corev1.ContainersReady,
  3260  						Status:             corev1.ConditionFalse,
  3261  						Reason:             string(corev1.PodFailed),
  3262  						LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(),
  3263  					}).
  3264  					Obj(),
  3265  				*basePodWrapper.
  3266  					Clone().
  3267  					Name("replacement").
  3268  					Label("kueue.x-k8s.io/managed", "true").
  3269  					KueueFinalizer().
  3270  					Group("test-group").
  3271  					GroupTotalCount("2").
  3272  					Obj(),
  3273  			},
  3274  			workloads: []kueue.Workload{
  3275  				*utiltesting.MakeWorkload("test-group", "ns").
  3276  					PodSets(
  3277  						*utiltesting.MakePodSet("dc85db45", 4).
  3278  							Request(corev1.ResourceCPU, "1").
  3279  							Obj(),
  3280  					).
  3281  					Queue("user-queue").
  3282  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3283  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error-no-finalizer", "test-uid").
  3284  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3285  					Admitted(true).
  3286  					Obj(),
  3287  			},
  3288  			wantWorkloads: []kueue.Workload{
  3289  				*utiltesting.MakeWorkload("test-group", "ns").
  3290  					PodSets(
  3291  						*utiltesting.MakePodSet("dc85db45", 4).
  3292  							Request(corev1.ResourceCPU, "1").
  3293  							Obj(),
  3294  					).
  3295  					Queue("user-queue").
  3296  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid").
  3297  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error-no-finalizer", "test-uid").
  3298  					OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement", "test-uid").
  3299  					ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3300  					Admitted(true).
  3301  					Obj(),
  3302  			},
  3303  			workloadCmpOpts: defaultWorkloadCmpOpts,
  3304  			wantEvents: []utiltesting.EventRecord{
  3305  				{
  3306  					Key:       types.NamespacedName{Name: "test-group", Namespace: "ns"},
  3307  					EventType: "Normal",
  3308  					Reason:    "OwnerReferencesAdded",
  3309  					Message:   "Added 1 owner reference(s)",
  3310  				},
  3311  			},
  3312  		},
  3313  	}
  3314  
  3315  	for name, tc := range testCases {
  3316  		t.Run(name, func(t *testing.T) {
  3317  			ctx, log := utiltesting.ContextWithLog(t)
  3318  			clientBuilder := utiltesting.NewClientBuilder()
  3319  			if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil {
  3320  				t.Fatalf("Could not setup indexes: %v", err)
  3321  			}
  3322  
  3323  			kcBuilder := clientBuilder.WithObjects(tc.initObjects...)
  3324  			for i := range tc.pods {
  3325  				kcBuilder = kcBuilder.WithObjects(&tc.pods[i])
  3326  			}
  3327  
  3328  			for i := range tc.workloads {
  3329  				kcBuilder = kcBuilder.WithStatusSubresource(&tc.workloads[i])
  3330  			}
  3331  
  3332  			kClient := kcBuilder.Build()
  3333  			for i := range tc.workloads {
  3334  				if err := kClient.Create(ctx, &tc.workloads[i]); err != nil {
  3335  					t.Fatalf("Could not create workload: %v", err)
  3336  				}
  3337  
  3338  				if tc.deleteWorkloads {
  3339  					if err := kClient.Delete(ctx, &tc.workloads[i]); err != nil {
  3340  						t.Fatalf("Could not delete workload: %v", err)
  3341  					}
  3342  				}
  3343  			}
  3344  			recorder := &utiltesting.EventRecorder{}
  3345  			reconciler := NewReconciler(kClient, recorder)
  3346  			pReconciler := reconciler.(*Reconciler)
  3347  			for _, e := range tc.excessPodsExpectations {
  3348  				pReconciler.expectationsStore.ExpectUIDs(log, e.key, e.uids)
  3349  			}
  3350  
  3351  			var reconcileRequest reconcile.Request
  3352  			if tc.reconcileKey != nil {
  3353  				reconcileRequest.NamespacedName = *tc.reconcileKey
  3354  			} else {
  3355  				reconcileRequest = reconcileRequestForPod(&tc.pods[0])
  3356  			}
  3357  			_, err := reconciler.Reconcile(ctx, reconcileRequest)
  3358  
  3359  			if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" {
  3360  				t.Errorf("Reconcile returned error (-want,+got):\n%s", diff)
  3361  			}
  3362  
  3363  			var gotPods corev1.PodList
  3364  			if err := kClient.List(ctx, &gotPods); err != nil {
  3365  				if tc.wantPods != nil || !apierrors.IsNotFound(err) {
  3366  					t.Fatalf("Could not get Pod after reconcile: %v", err)
  3367  				}
  3368  			}
  3369  			if tc.wantPods != nil {
  3370  				if diff := cmp.Diff(tc.wantPods, gotPods.Items, podCmpOpts...); diff != "" && tc.wantPods != nil {
  3371  					t.Errorf("Pods after reconcile (-want,+got):\n%s", diff)
  3372  				}
  3373  			}
  3374  
  3375  			var gotWorkloads kueue.WorkloadList
  3376  			if err := kClient.List(ctx, &gotWorkloads); err != nil {
  3377  				t.Fatalf("Could not get Workloads after reconcile: %v", err)
  3378  			}
  3379  
  3380  			if diff := cmp.Diff(tc.wantWorkloads, gotWorkloads.Items, tc.workloadCmpOpts...); diff != "" {
  3381  				for i, p := range tc.pods {
  3382  					// Make life easier when changing the hashing function.
  3383  					hash, _ := getRoleHash(p)
  3384  					t.Logf("note, the hash for pod[%v] = %s", i, hash)
  3385  
  3386  				}
  3387  				t.Errorf("Workloads after reconcile (-want,+got):\n%s", diff)
  3388  			}
  3389  
  3390  			if diff := cmp.Diff(tc.wantEvents, recorder.RecordedEvents, cmpopts.SortSlices(utiltesting.SortEvents)); diff != "" {
  3391  				t.Errorf("unexpected events (-want/+got):\n%s", diff)
  3392  			}
  3393  		})
  3394  	}
  3395  }
  3396  
  3397  func TestReconciler_ErrorFinalizingPod(t *testing.T) {
  3398  	ctx, _ := utiltesting.ContextWithLog(t)
  3399  
  3400  	clientBuilder := utiltesting.NewClientBuilder()
  3401  	if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil {
  3402  		t.Fatalf("Could not setup indexes: %v", err)
  3403  	}
  3404  
  3405  	basePodWrapper := testingpod.MakePod("pod", "ns").
  3406  		UID("test-uid").
  3407  		Queue("user-queue").
  3408  		Request(corev1.ResourceCPU, "1").
  3409  		Image("", nil)
  3410  
  3411  	pod := *basePodWrapper.
  3412  		Clone().
  3413  		Label("kueue.x-k8s.io/managed", "true").
  3414  		KueueFinalizer().
  3415  		StatusPhase(corev1.PodSucceeded).
  3416  		Obj()
  3417  
  3418  	wl := *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName).
  3419  		PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
  3420  		ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3421  		Admitted(true).
  3422  		Obj()
  3423  
  3424  	reqcount := 0
  3425  	errMock := fmt.Errorf("connection refused: %w", syscall.ECONNREFUSED)
  3426  
  3427  	kcBuilder := clientBuilder.
  3428  		WithObjects(&pod).
  3429  		WithStatusSubresource(&wl).
  3430  		WithInterceptorFuncs(interceptor.Funcs{
  3431  			Update: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error {
  3432  				_, isPod := obj.(*corev1.Pod)
  3433  				if isPod {
  3434  					defer func() { reqcount++ }()
  3435  					if reqcount == 0 {
  3436  						// return a connection refused error for the first update request.
  3437  						return errMock
  3438  					}
  3439  					if reqcount == 1 {
  3440  						// Exec a regular update operation for the second request
  3441  						return client.Update(ctx, obj, opts...)
  3442  					}
  3443  				}
  3444  				return client.Update(ctx, obj, opts...)
  3445  			},
  3446  		})
  3447  
  3448  	kClient := kcBuilder.Build()
  3449  	if err := ctrl.SetControllerReference(&pod, &wl, kClient.Scheme()); err != nil {
  3450  		t.Fatalf("Could not setup owner reference in Workloads: %v", err)
  3451  	}
  3452  	if err := kClient.Create(ctx, &wl); err != nil {
  3453  		t.Fatalf("Could not create workload: %v", err)
  3454  	}
  3455  	recorder := record.NewBroadcaster().NewRecorder(kClient.Scheme(), corev1.EventSource{Component: "test"})
  3456  
  3457  	reconciler := NewReconciler(kClient, recorder)
  3458  
  3459  	podKey := client.ObjectKeyFromObject(&pod)
  3460  	_, err := reconciler.Reconcile(ctx, reconcile.Request{
  3461  		NamespacedName: podKey,
  3462  	})
  3463  
  3464  	if diff := cmp.Diff(errMock, err, cmpopts.EquateErrors()); diff != "" {
  3465  		t.Errorf("Expected reconcile error (-want,+got):\n%s", diff)
  3466  	}
  3467  
  3468  	// Reconcile for the second time
  3469  	_, err = reconciler.Reconcile(ctx, reconcile.Request{
  3470  		NamespacedName: podKey,
  3471  	})
  3472  	if err != nil {
  3473  		t.Errorf("Got unexpected error while running reconcile:\n%v", err)
  3474  	}
  3475  
  3476  	var gotPod corev1.Pod
  3477  	if err := kClient.Get(ctx, podKey, &gotPod); err != nil {
  3478  		t.Fatalf("Could not get Pod after second reconcile: %v", err)
  3479  	}
  3480  	// Validate that pod has no finalizer after the second reconcile
  3481  	wantPod := *basePodWrapper.
  3482  		Clone().
  3483  		Label("kueue.x-k8s.io/managed", "true").
  3484  		StatusPhase(corev1.PodSucceeded).
  3485  		Obj()
  3486  	if diff := cmp.Diff(wantPod, gotPod, podCmpOpts...); diff != "" {
  3487  		t.Errorf("Pod after second reconcile (-want,+got):\n%s", diff)
  3488  	}
  3489  
  3490  	var gotWorkloads kueue.WorkloadList
  3491  	if err := kClient.List(ctx, &gotWorkloads); err != nil {
  3492  		t.Fatalf("Could not get Workloads after second reconcile: %v", err)
  3493  	}
  3494  
  3495  	// Workload should be finished after the second reconcile
  3496  	wantWl := *utiltesting.MakeWorkload("unit-test", "ns").
  3497  		PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()).
  3498  		ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()).
  3499  		ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid").
  3500  		Admitted(true).
  3501  		Condition(
  3502  			metav1.Condition{
  3503  				Type:    kueue.WorkloadFinished,
  3504  				Status:  metav1.ConditionTrue,
  3505  				Reason:  "JobFinished",
  3506  				Message: "Job finished successfully",
  3507  			},
  3508  		).
  3509  		Obj()
  3510  	if diff := cmp.Diff([]kueue.Workload{wantWl}, gotWorkloads.Items, defaultWorkloadCmpOpts...); diff != "" {
  3511  		t.Errorf("Workloads after second reconcile (-want,+got):\n%s", diff)
  3512  	}
  3513  }
  3514  
  3515  func TestIsPodOwnerManagedByQueue(t *testing.T) {
  3516  	testCases := map[string]struct {
  3517  		ownerReference metav1.OwnerReference
  3518  		wantRes        bool
  3519  	}{
  3520  		"batch/v1/Job": {
  3521  			ownerReference: metav1.OwnerReference{
  3522  				APIVersion: "batch/v1",
  3523  				Controller: ptr.To(true),
  3524  				Kind:       "Job",
  3525  			},
  3526  			wantRes: true,
  3527  		},
  3528  		"apps/v1/ReplicaSet": {
  3529  			ownerReference: metav1.OwnerReference{
  3530  				APIVersion: "apps/v1",
  3531  				Controller: ptr.To(true),
  3532  				Kind:       "ReplicaSet",
  3533  			},
  3534  			wantRes: false,
  3535  		},
  3536  		"ray.io/v1alpha1/RayCluster": {
  3537  			ownerReference: metav1.OwnerReference{
  3538  				APIVersion: "ray.io/v1alpha1",
  3539  				Controller: ptr.To(true),
  3540  				Kind:       "RayCluster",
  3541  			},
  3542  			wantRes: true,
  3543  		},
  3544  	}
  3545  
  3546  	for name, tc := range testCases {
  3547  		t.Run(name, func(t *testing.T) {
  3548  			pod := testingpod.MakePod("pod", "ns").
  3549  				UID("test-uid").
  3550  				Request(corev1.ResourceCPU, "1").
  3551  				Image("", nil).
  3552  				Obj()
  3553  
  3554  			pod.OwnerReferences = append(pod.OwnerReferences, tc.ownerReference)
  3555  
  3556  			if tc.wantRes != IsPodOwnerManagedByKueue(fromObject(pod)) {
  3557  				t.Errorf("Unexpected 'IsPodOwnerManagedByKueue' result\n want: %t\n got: %t)",
  3558  					tc.wantRes, IsPodOwnerManagedByKueue(fromObject(pod)))
  3559  			}
  3560  		})
  3561  	}
  3562  }
  3563  
  3564  func TestGetWorkloadNameForPod(t *testing.T) {
  3565  	wantWlName := "pod-unit-test-7bb47"
  3566  	wlName := GetWorkloadNameForPod("unit-test")
  3567  
  3568  	if wantWlName != wlName {
  3569  		t.Errorf("Expected different workload name\n want: %s\n got: %s", wantWlName, wlName)
  3570  	}
  3571  }