sigs.k8s.io/kueue@v0.6.2/pkg/controller/jobframework/reconciler_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 jobframework_test
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/google/go-cmp/cmp/cmpopts"
    25  	kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1"
    26  	batchv1 "k8s.io/api/batch/v1"
    27  	corev1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  
    31  	configapi "sigs.k8s.io/kueue/apis/config/v1beta1"
    32  	_ "sigs.k8s.io/kueue/pkg/controller/jobs"
    33  	"sigs.k8s.io/kueue/pkg/util/kubeversion"
    34  	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
    35  	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
    36  	testingmpijob "sigs.k8s.io/kueue/pkg/util/testingjobs/mpijob"
    37  
    38  	. "sigs.k8s.io/kueue/pkg/controller/jobframework"
    39  )
    40  
    41  func TestIsParentJobManaged(t *testing.T) {
    42  	parentJobName := "test-job-parent"
    43  	childJobName := "test-job-child"
    44  	jobNamespace := "default"
    45  	cases := map[string]struct {
    46  		parentJob   client.Object
    47  		job         client.Object
    48  		wantManaged bool
    49  		wantErr     error
    50  	}{
    51  		"child job doesn't have ownerReference": {
    52  			parentJob: testingmpijob.MakeMPIJob(parentJobName, jobNamespace).
    53  				UID(parentJobName).
    54  				Obj(),
    55  			job: testingjob.MakeJob(childJobName, jobNamespace).
    56  				Obj(),
    57  			wantErr: ErrChildJobOwnerNotFound,
    58  		},
    59  		"child job has ownerReference with unknown workload owner": {
    60  			parentJob: testingjob.MakeJob(parentJobName, jobNamespace).
    61  				UID(parentJobName).
    62  				Obj(),
    63  			job: testingjob.MakeJob(childJobName, jobNamespace).
    64  				OwnerReference(parentJobName, batchv1.SchemeGroupVersion.WithKind("CronJob")).
    65  				Obj(),
    66  			wantErr: ErrUnknownWorkloadOwner,
    67  		},
    68  		"child job has ownerReference with known non-existing workload owner": {
    69  			job: testingjob.MakeJob(childJobName, jobNamespace).
    70  				OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind).
    71  				Obj(),
    72  			wantErr: ErrWorkloadOwnerNotFound,
    73  		},
    74  		"child job has ownerReference with known existing workload owner, and the parent job has queue-name label": {
    75  			parentJob: testingmpijob.MakeMPIJob(parentJobName, jobNamespace).
    76  				UID(parentJobName).
    77  				Queue("test-q").
    78  				Obj(),
    79  			job: testingjob.MakeJob(childJobName, jobNamespace).
    80  				OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind).
    81  				Obj(),
    82  			wantManaged: true,
    83  		},
    84  		"child job has ownerReference with known existing workload owner, and the parent job doesn't has queue-name label": {
    85  			parentJob: testingmpijob.MakeMPIJob(parentJobName, jobNamespace).
    86  				UID(parentJobName).
    87  				Obj(),
    88  			job: testingjob.MakeJob(childJobName, jobNamespace).
    89  				OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind).
    90  				Obj(),
    91  		},
    92  	}
    93  	for name, tc := range cases {
    94  		t.Run(name, func(t *testing.T) {
    95  			builder := utiltesting.NewClientBuilder(kubeflow.AddToScheme)
    96  			if tc.parentJob != nil {
    97  				builder = builder.WithObjects(tc.parentJob)
    98  			}
    99  			cl := builder.Build()
   100  			r := NewReconciler(cl, nil)
   101  			got, gotErr := r.IsParentJobManaged(context.Background(), tc.job, jobNamespace)
   102  			if tc.wantManaged != got {
   103  				t.Errorf("Unexpected response from isParentManaged want: %v,got: %v", tc.wantManaged, got)
   104  			}
   105  			if diff := cmp.Diff(tc.wantErr, gotErr, cmpopts.EquateErrors()); len(diff) != 0 {
   106  				t.Errorf("Unexpected error (-want,+got):\n%s", diff)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  func TestProcessOptions(t *testing.T) {
   113  	cases := map[string]struct {
   114  		inputOpts []Option
   115  		wantOpts  Options
   116  	}{
   117  		"all options are passed": {
   118  			inputOpts: []Option{
   119  				WithManageJobsWithoutQueueName(true),
   120  				WithWaitForPodsReady(&configapi.WaitForPodsReady{Enable: true}),
   121  				WithKubeServerVersion(&kubeversion.ServerVersionFetcher{}),
   122  				WithIntegrationOptions(corev1.SchemeGroupVersion.WithKind("Pod").String(), &configapi.PodIntegrationOptions{
   123  					PodSelector: &metav1.LabelSelector{},
   124  				}),
   125  			},
   126  			wantOpts: Options{
   127  				ManageJobsWithoutQueueName: true,
   128  				WaitForPodsReady:           true,
   129  				KubeServerVersion:          &kubeversion.ServerVersionFetcher{},
   130  				IntegrationOptions: map[string]any{
   131  					corev1.SchemeGroupVersion.WithKind("Pod").String(): &configapi.PodIntegrationOptions{
   132  						PodSelector: &metav1.LabelSelector{},
   133  					},
   134  				},
   135  			},
   136  		},
   137  		"a single option is passed": {
   138  			inputOpts: []Option{
   139  				WithManageJobsWithoutQueueName(true),
   140  			},
   141  			wantOpts: Options{
   142  				ManageJobsWithoutQueueName: true,
   143  				WaitForPodsReady:           false,
   144  				KubeServerVersion:          nil,
   145  				IntegrationOptions:         nil,
   146  			},
   147  		},
   148  		"no options are passed": {
   149  			wantOpts: Options{
   150  				ManageJobsWithoutQueueName: false,
   151  				WaitForPodsReady:           false,
   152  				KubeServerVersion:          nil,
   153  				IntegrationOptions:         nil,
   154  			},
   155  		},
   156  	}
   157  	for name, tc := range cases {
   158  		t.Run(name, func(t *testing.T) {
   159  			gotOpts := ProcessOptions(tc.inputOpts...)
   160  			if diff := cmp.Diff(tc.wantOpts, gotOpts,
   161  				cmpopts.IgnoreUnexported(kubeversion.ServerVersionFetcher{})); len(diff) != 0 {
   162  				t.Errorf("Unexpected error from ProcessOptions (-want,+got):\n%s", diff)
   163  			}
   164  		})
   165  	}
   166  }