volcano.sh/volcano@v1.9.0/pkg/controllers/job/job_controller_util_test.go (about)

     1  /*
     2  Copyright 2019 The Volcano 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 job
    18  
    19  import (
    20  	"testing"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  
    25  	"volcano.sh/apis/pkg/apis/batch/v1alpha1"
    26  	busv1alpha1 "volcano.sh/apis/pkg/apis/bus/v1alpha1"
    27  	"volcano.sh/volcano/pkg/controllers/apis"
    28  )
    29  
    30  func TestMakePodName(t *testing.T) {
    31  	testcases := []struct {
    32  		Name      string
    33  		TaskName  string
    34  		JobName   string
    35  		Index     int
    36  		ReturnVal string
    37  	}{
    38  		{
    39  			Name:      "Test MakePodName function",
    40  			TaskName:  "task1",
    41  			JobName:   "job1",
    42  			Index:     1,
    43  			ReturnVal: "job1-task1-1",
    44  		},
    45  	}
    46  
    47  	for i, testcase := range testcases {
    48  
    49  		t.Run(testcase.Name, func(t *testing.T) {
    50  			podName := MakePodName(testcase.JobName, testcase.TaskName, testcase.Index)
    51  
    52  			if podName != testcase.ReturnVal {
    53  				t.Errorf("Expected Return value to be: %s, but got: %s in case %d", testcase.ReturnVal, podName, i)
    54  			}
    55  		})
    56  
    57  	}
    58  }
    59  
    60  func TestCreateJobPod(t *testing.T) {
    61  	namespace := "test"
    62  
    63  	testcases := []struct {
    64  		Name        string
    65  		Job         *v1alpha1.Job
    66  		PodTemplate *v1.PodTemplateSpec
    67  		Index       int
    68  		ReturnVal   *v1.Pod
    69  	}{
    70  		{
    71  			Name: "Test Create Job Pod",
    72  			Job: &v1alpha1.Job{
    73  				ObjectMeta: metav1.ObjectMeta{
    74  					Name:      "job1",
    75  					Namespace: namespace,
    76  				},
    77  				Spec: v1alpha1.JobSpec{
    78  					Tasks: []v1alpha1.TaskSpec{
    79  						{
    80  							Name:     "task1",
    81  							Replicas: 6,
    82  							Template: v1.PodTemplateSpec{
    83  								ObjectMeta: metav1.ObjectMeta{
    84  									Name:      "pods",
    85  									Namespace: namespace,
    86  								},
    87  								Spec: v1.PodSpec{
    88  									Containers: []v1.Container{
    89  										{
    90  											Name: "Containers",
    91  										},
    92  									},
    93  								},
    94  							},
    95  						},
    96  					},
    97  				},
    98  			},
    99  			PodTemplate: &v1.PodTemplateSpec{
   100  				ObjectMeta: metav1.ObjectMeta{
   101  					Namespace: namespace,
   102  				},
   103  				Spec: v1.PodSpec{
   104  					Containers: []v1.Container{
   105  						{
   106  							Name: "Containers",
   107  						},
   108  					},
   109  				},
   110  			},
   111  			Index: 0,
   112  			ReturnVal: &v1.Pod{
   113  				ObjectMeta: metav1.ObjectMeta{
   114  					Name:      "job1-task1-0",
   115  					Namespace: namespace,
   116  				},
   117  			},
   118  		},
   119  		{
   120  			Name: "Test Create Job Pod with volumes",
   121  			Job: &v1alpha1.Job{
   122  				ObjectMeta: metav1.ObjectMeta{
   123  					Name:      "job1",
   124  					Namespace: namespace,
   125  				},
   126  				Spec: v1alpha1.JobSpec{
   127  					Volumes: []v1alpha1.VolumeSpec{
   128  						{
   129  							VolumeClaimName: "vc1",
   130  						},
   131  						{
   132  							VolumeClaimName: "vc2",
   133  						},
   134  					},
   135  					Tasks: []v1alpha1.TaskSpec{
   136  						{
   137  							Name:     "task1",
   138  							Replicas: 6,
   139  							Template: v1.PodTemplateSpec{
   140  								ObjectMeta: metav1.ObjectMeta{
   141  									Name:      "pods",
   142  									Namespace: namespace,
   143  								},
   144  								Spec: v1.PodSpec{
   145  									Containers: []v1.Container{
   146  										{
   147  											Name: "Containers",
   148  										},
   149  									},
   150  								},
   151  							},
   152  						},
   153  					},
   154  				},
   155  			},
   156  			PodTemplate: &v1.PodTemplateSpec{
   157  				ObjectMeta: metav1.ObjectMeta{
   158  					Namespace: namespace,
   159  				},
   160  				Spec: v1.PodSpec{
   161  					Containers: []v1.Container{
   162  						{
   163  							Name: "Containers",
   164  						},
   165  					},
   166  				},
   167  			},
   168  			Index: 0,
   169  			ReturnVal: &v1.Pod{
   170  				ObjectMeta: metav1.ObjectMeta{
   171  					Name:      "job1-task1-0",
   172  					Namespace: namespace,
   173  				},
   174  			},
   175  		},
   176  		{
   177  			Name: "Test Create Job Pod with volumes added to controlled resources",
   178  			Job: &v1alpha1.Job{
   179  				ObjectMeta: metav1.ObjectMeta{
   180  					Name:      "job1",
   181  					Namespace: namespace,
   182  				},
   183  				Spec: v1alpha1.JobSpec{
   184  					SchedulerName: "volcano",
   185  					Volumes: []v1alpha1.VolumeSpec{
   186  						{
   187  							VolumeClaimName: "vc1",
   188  							VolumeClaim: &v1.PersistentVolumeClaimSpec{
   189  								VolumeName: "v1",
   190  							},
   191  						},
   192  						{
   193  							VolumeClaimName: "vc2",
   194  						},
   195  					},
   196  					Tasks: []v1alpha1.TaskSpec{
   197  						{
   198  							Name:     "task1",
   199  							Replicas: 6,
   200  							Template: v1.PodTemplateSpec{
   201  								ObjectMeta: metav1.ObjectMeta{
   202  									Name:      "pods",
   203  									Namespace: namespace,
   204  								},
   205  								Spec: v1.PodSpec{
   206  									Containers: []v1.Container{
   207  										{
   208  											Name: "Containers",
   209  										},
   210  									},
   211  								},
   212  							},
   213  						},
   214  					},
   215  				},
   216  			},
   217  			PodTemplate: &v1.PodTemplateSpec{
   218  				ObjectMeta: metav1.ObjectMeta{
   219  					Namespace: namespace,
   220  				},
   221  				Spec: v1.PodSpec{
   222  					Containers: []v1.Container{
   223  						{
   224  							Name: "Containers",
   225  						},
   226  					},
   227  				},
   228  			},
   229  			Index: 0,
   230  			ReturnVal: &v1.Pod{
   231  				ObjectMeta: metav1.ObjectMeta{
   232  					Name:      "job1-task1-0",
   233  					Namespace: namespace,
   234  				},
   235  			},
   236  		},
   237  	}
   238  
   239  	for i, testcase := range testcases {
   240  
   241  		t.Run(testcase.Name, func(t *testing.T) {
   242  			pod := createJobPod(testcase.Job, testcase.PodTemplate, "", testcase.Index, false)
   243  
   244  			if testcase.ReturnVal != nil && pod != nil && pod.Name != testcase.ReturnVal.Name && pod.Namespace != testcase.ReturnVal.Namespace {
   245  				t.Errorf("Expected Return Value to be %v but got %v in case %d", testcase.ReturnVal, pod, i)
   246  			}
   247  		})
   248  	}
   249  }
   250  
   251  func TestApplyPolicies(t *testing.T) {
   252  	namespace := "test"
   253  	errorCode0 := int32(0)
   254  
   255  	testcases := []struct {
   256  		Name      string
   257  		Job       *v1alpha1.Job
   258  		Request   *apis.Request
   259  		ReturnVal busv1alpha1.Action
   260  	}{
   261  		{
   262  			Name: "Test Apply policies where Action is not empty",
   263  			Job: &v1alpha1.Job{
   264  				ObjectMeta: metav1.ObjectMeta{
   265  					Name:      "job1",
   266  					Namespace: namespace,
   267  				},
   268  				Spec: v1alpha1.JobSpec{
   269  					SchedulerName: "volcano",
   270  					Tasks: []v1alpha1.TaskSpec{
   271  						{
   272  							Name:     "task1",
   273  							Replicas: 6,
   274  							Template: v1.PodTemplateSpec{
   275  								ObjectMeta: metav1.ObjectMeta{
   276  									Name:      "pods",
   277  									Namespace: namespace,
   278  								},
   279  								Spec: v1.PodSpec{
   280  									Containers: []v1.Container{
   281  										{
   282  											Name: "Containers",
   283  										},
   284  									},
   285  								},
   286  							},
   287  						},
   288  					},
   289  				},
   290  			},
   291  			Request: &apis.Request{
   292  				Action: busv1alpha1.EnqueueAction,
   293  			},
   294  			ReturnVal: busv1alpha1.EnqueueAction,
   295  		},
   296  		{
   297  			Name: "Test Apply policies where event is OutOfSync",
   298  			Job: &v1alpha1.Job{
   299  				ObjectMeta: metav1.ObjectMeta{
   300  					Name:      "job1",
   301  					Namespace: namespace,
   302  				},
   303  				Spec: v1alpha1.JobSpec{
   304  					SchedulerName: "volcano",
   305  					Tasks: []v1alpha1.TaskSpec{
   306  						{
   307  							Name:     "task1",
   308  							Replicas: 6,
   309  							Template: v1.PodTemplateSpec{
   310  								ObjectMeta: metav1.ObjectMeta{
   311  									Name:      "pods",
   312  									Namespace: namespace,
   313  								},
   314  								Spec: v1.PodSpec{
   315  									Containers: []v1.Container{
   316  										{
   317  											Name: "Containers",
   318  										},
   319  									},
   320  								},
   321  							},
   322  						},
   323  					},
   324  				},
   325  			},
   326  			Request: &apis.Request{
   327  				Event: busv1alpha1.OutOfSyncEvent,
   328  			},
   329  			ReturnVal: busv1alpha1.SyncJobAction,
   330  		},
   331  		{
   332  			Name: "Test Apply policies where version is outdated",
   333  			Job: &v1alpha1.Job{
   334  				ObjectMeta: metav1.ObjectMeta{
   335  					Name:      "job1",
   336  					Namespace: namespace,
   337  				},
   338  				Spec: v1alpha1.JobSpec{
   339  					SchedulerName: "volcano",
   340  					Tasks: []v1alpha1.TaskSpec{
   341  						{
   342  							Name:     "task1",
   343  							Replicas: 6,
   344  							Template: v1.PodTemplateSpec{
   345  								ObjectMeta: metav1.ObjectMeta{
   346  									Name:      "pods",
   347  									Namespace: namespace,
   348  								},
   349  								Spec: v1.PodSpec{
   350  									Containers: []v1.Container{
   351  										{
   352  											Name: "Containers",
   353  										},
   354  									},
   355  								},
   356  							},
   357  						},
   358  					},
   359  				},
   360  			},
   361  			Request: &apis.Request{
   362  				JobVersion: 1,
   363  			},
   364  			ReturnVal: busv1alpha1.SyncJobAction,
   365  		},
   366  		{
   367  			Name: "Test Apply policies where overriding job level policies and with exitcode",
   368  			Job: &v1alpha1.Job{
   369  				ObjectMeta: metav1.ObjectMeta{
   370  					Name:      "job1",
   371  					Namespace: namespace,
   372  				},
   373  				Spec: v1alpha1.JobSpec{
   374  					SchedulerName: "volcano",
   375  					Tasks: []v1alpha1.TaskSpec{
   376  						{
   377  							Name:     "task1",
   378  							Replicas: 6,
   379  							Template: v1.PodTemplateSpec{
   380  								ObjectMeta: metav1.ObjectMeta{
   381  									Name:      "pods",
   382  									Namespace: namespace,
   383  								},
   384  								Spec: v1.PodSpec{
   385  									Containers: []v1.Container{
   386  										{
   387  											Name: "Containers",
   388  										},
   389  									},
   390  								},
   391  							},
   392  							Policies: []v1alpha1.LifecyclePolicy{
   393  								{
   394  									Action:   busv1alpha1.SyncJobAction,
   395  									Event:    busv1alpha1.CommandIssuedEvent,
   396  									ExitCode: &errorCode0,
   397  								},
   398  							},
   399  						},
   400  					},
   401  				},
   402  			},
   403  			Request: &apis.Request{
   404  				TaskName: "task1",
   405  			},
   406  			ReturnVal: busv1alpha1.SyncJobAction,
   407  		},
   408  		{
   409  			Name: "Test Apply policies where overriding job level policies and without exitcode",
   410  			Job: &v1alpha1.Job{
   411  				ObjectMeta: metav1.ObjectMeta{
   412  					Name:      "job1",
   413  					Namespace: namespace,
   414  				},
   415  				Spec: v1alpha1.JobSpec{
   416  					SchedulerName: "volcano",
   417  					Tasks: []v1alpha1.TaskSpec{
   418  						{
   419  							Name:     "task1",
   420  							Replicas: 6,
   421  							Template: v1.PodTemplateSpec{
   422  								ObjectMeta: metav1.ObjectMeta{
   423  									Name:      "pods",
   424  									Namespace: namespace,
   425  								},
   426  								Spec: v1.PodSpec{
   427  									Containers: []v1.Container{
   428  										{
   429  											Name: "Containers",
   430  										},
   431  									},
   432  								},
   433  							},
   434  							Policies: []v1alpha1.LifecyclePolicy{
   435  								{
   436  									Action: busv1alpha1.SyncJobAction,
   437  									Event:  busv1alpha1.CommandIssuedEvent,
   438  								},
   439  							},
   440  						},
   441  					},
   442  				},
   443  			},
   444  			Request: &apis.Request{
   445  				TaskName: "task1",
   446  				Event:    busv1alpha1.CommandIssuedEvent,
   447  			},
   448  			ReturnVal: busv1alpha1.SyncJobAction,
   449  		},
   450  		{
   451  			Name: "Test Apply policies with job level policies",
   452  			Job: &v1alpha1.Job{
   453  				ObjectMeta: metav1.ObjectMeta{
   454  					Name:      "job1",
   455  					Namespace: namespace,
   456  				},
   457  				Spec: v1alpha1.JobSpec{
   458  					SchedulerName: "volcano",
   459  					Tasks: []v1alpha1.TaskSpec{
   460  						{
   461  							Name:     "task1",
   462  							Replicas: 6,
   463  							Template: v1.PodTemplateSpec{
   464  								ObjectMeta: metav1.ObjectMeta{
   465  									Name:      "pods",
   466  									Namespace: namespace,
   467  								},
   468  								Spec: v1.PodSpec{
   469  									Containers: []v1.Container{
   470  										{
   471  											Name: "Containers",
   472  										},
   473  									},
   474  								},
   475  							},
   476  						},
   477  					},
   478  				},
   479  			},
   480  			Request: &apis.Request{
   481  				TaskName: "task1",
   482  				Event:    busv1alpha1.CommandIssuedEvent,
   483  			},
   484  			ReturnVal: busv1alpha1.SyncJobAction,
   485  		},
   486  		{
   487  			Name: "Test Apply policies with job level policies",
   488  			Job: &v1alpha1.Job{
   489  				ObjectMeta: metav1.ObjectMeta{
   490  					Name:      "job1",
   491  					Namespace: namespace,
   492  				},
   493  				Spec: v1alpha1.JobSpec{
   494  					SchedulerName: "volcano",
   495  					Tasks: []v1alpha1.TaskSpec{
   496  						{
   497  							Name:     "task1",
   498  							Replicas: 6,
   499  							Template: v1.PodTemplateSpec{
   500  								ObjectMeta: metav1.ObjectMeta{
   501  									Name:      "pods",
   502  									Namespace: namespace,
   503  								},
   504  								Spec: v1.PodSpec{
   505  									Containers: []v1.Container{
   506  										{
   507  											Name: "Containers",
   508  										},
   509  									},
   510  								},
   511  							},
   512  						},
   513  					},
   514  					Policies: []v1alpha1.LifecyclePolicy{
   515  						{
   516  							Action: busv1alpha1.SyncJobAction,
   517  							Event:  busv1alpha1.CommandIssuedEvent,
   518  						},
   519  					},
   520  				},
   521  			},
   522  			Request: &apis.Request{
   523  				Event: busv1alpha1.CommandIssuedEvent,
   524  			},
   525  			ReturnVal: busv1alpha1.SyncJobAction,
   526  		},
   527  		{
   528  			Name: "Test Apply policies with job level policies with exitcode",
   529  			Job: &v1alpha1.Job{
   530  				ObjectMeta: metav1.ObjectMeta{
   531  					Name:      "job1",
   532  					Namespace: namespace,
   533  				},
   534  				Spec: v1alpha1.JobSpec{
   535  					SchedulerName: "volcano",
   536  					Tasks: []v1alpha1.TaskSpec{
   537  						{
   538  							Name:     "task1",
   539  							Replicas: 6,
   540  							Template: v1.PodTemplateSpec{
   541  								ObjectMeta: metav1.ObjectMeta{
   542  									Name:      "pods",
   543  									Namespace: namespace,
   544  								},
   545  								Spec: v1.PodSpec{
   546  									Containers: []v1.Container{
   547  										{
   548  											Name: "Containers",
   549  										},
   550  									},
   551  								},
   552  							},
   553  						},
   554  					},
   555  					Policies: []v1alpha1.LifecyclePolicy{
   556  						{
   557  							Action:   busv1alpha1.SyncJobAction,
   558  							Event:    busv1alpha1.CommandIssuedEvent,
   559  							ExitCode: &errorCode0,
   560  						},
   561  					},
   562  				},
   563  			},
   564  			Request:   &apis.Request{},
   565  			ReturnVal: busv1alpha1.SyncJobAction,
   566  		},
   567  	}
   568  
   569  	for i, testcase := range testcases {
   570  
   571  		t.Run(testcase.Name, func(t *testing.T) {
   572  			action := applyPolicies(testcase.Job, testcase.Request)
   573  
   574  			if testcase.ReturnVal != "" && action != "" && testcase.ReturnVal != action {
   575  				t.Errorf("Expected return value to be %s but got %s in case %d", testcase.ReturnVal, action, i)
   576  			}
   577  		})
   578  	}
   579  }
   580  
   581  func TestTasksPriority_Less(t *testing.T) {
   582  	testcases := []struct {
   583  		Name          string
   584  		TasksPriority TasksPriority
   585  		Task1Index    int
   586  		Task2Index    int
   587  		ReturnVal     bool
   588  	}{
   589  		{
   590  			Name: "False Case",
   591  			TasksPriority: []TaskPriority{
   592  				{
   593  					priority: 1,
   594  				},
   595  				{
   596  					priority: 2,
   597  				},
   598  				{
   599  					priority: 3,
   600  				},
   601  			},
   602  			Task1Index: 1,
   603  			Task2Index: 2,
   604  			ReturnVal:  false,
   605  		},
   606  		{
   607  			Name: "True Case",
   608  			TasksPriority: []TaskPriority{
   609  				{
   610  					priority: 1,
   611  				},
   612  				{
   613  					priority: 2,
   614  				},
   615  				{
   616  					priority: 3,
   617  				},
   618  			},
   619  			Task1Index: 2,
   620  			Task2Index: 1,
   621  			ReturnVal:  true,
   622  		},
   623  	}
   624  
   625  	for i, testcase := range testcases {
   626  
   627  		t.Run(testcase.Name, func(t *testing.T) {
   628  			less := testcase.TasksPriority.Less(testcase.Task1Index, testcase.Task2Index)
   629  
   630  			if less != testcase.ReturnVal {
   631  				t.Errorf("Expected Return Value to be %t, but got %t in case %d", testcase.ReturnVal, less, i)
   632  			}
   633  		})
   634  	}
   635  }
   636  
   637  func TestTasksPriority_Swap(t *testing.T) {
   638  	testcases := []struct {
   639  		Name          string
   640  		TasksPriority TasksPriority
   641  		Task1Index    int
   642  		Task2Index    int
   643  		ReturnVal     bool
   644  	}{
   645  		{
   646  			Name: "False Case",
   647  			TasksPriority: []TaskPriority{
   648  				{
   649  					priority: 1,
   650  				},
   651  				{
   652  					priority: 2,
   653  				},
   654  				{
   655  					priority: 3,
   656  				},
   657  			},
   658  			Task1Index: 1,
   659  			Task2Index: 2,
   660  		},
   661  		{
   662  			Name: "True Case",
   663  			TasksPriority: []TaskPriority{
   664  				{
   665  					priority: 1,
   666  				},
   667  				{
   668  					priority: 2,
   669  				},
   670  				{
   671  					priority: 3,
   672  				},
   673  			},
   674  			Task1Index: 2,
   675  			Task2Index: 1,
   676  		},
   677  	}
   678  
   679  	for _, testcase := range testcases {
   680  		t.Run(testcase.Name, func(_ *testing.T) {
   681  			testcase.TasksPriority.Swap(testcase.Task1Index, testcase.Task2Index)
   682  		})
   683  	}
   684  }