github.com/kubeflow/training-operator@v1.7.0/pkg/apis/kubeflow.org/v1/xgboost_validation_test.go (about)

     1  // Copyright 2021 The Kubeflow Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package v1
    16  
    17  import (
    18  	"testing"
    19  
    20  	corev1 "k8s.io/api/core/v1"
    21  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    22  	"k8s.io/utils/pointer"
    23  )
    24  
    25  func TestValidateV1XGBoostJob(t *testing.T) {
    26  	validXGBoostReplicaSpecs := map[ReplicaType]*ReplicaSpec{
    27  		XGBoostJobReplicaTypeMaster: {
    28  			Replicas:      pointer.Int32(1),
    29  			RestartPolicy: RestartPolicyNever,
    30  			Template: corev1.PodTemplateSpec{
    31  				Spec: corev1.PodSpec{
    32  					Containers: []corev1.Container{{
    33  						Name:  "xgboost",
    34  						Image: "docker.io/merlintang/xgboost-dist-iris:1.1",
    35  						Ports: []corev1.ContainerPort{{
    36  							Name:          "xgboostjob-port",
    37  							ContainerPort: 9991,
    38  						}},
    39  						ImagePullPolicy: corev1.PullAlways,
    40  						Args: []string{
    41  							"--job_type=Train",
    42  							"--xgboost_parameter=objective:multi:softprob,num_class:3",
    43  							"--n_estimators=10",
    44  							"--learning_rate=0.1",
    45  							"--model_path=/tmp/xgboost-model",
    46  							"--model_storage_type=local",
    47  						},
    48  					}},
    49  				},
    50  			},
    51  		},
    52  		XGBoostJobReplicaTypeWorker: {
    53  			Replicas:      pointer.Int32(2),
    54  			RestartPolicy: RestartPolicyExitCode,
    55  			Template: corev1.PodTemplateSpec{
    56  				Spec: corev1.PodSpec{
    57  					Containers: []corev1.Container{{
    58  						Name:  "xgboost",
    59  						Image: "docker.io/merlintang/xgboost-dist-iris:1.",
    60  						Ports: []corev1.ContainerPort{{
    61  							Name:          "xgboostjob-port",
    62  							ContainerPort: 9991,
    63  						}},
    64  						ImagePullPolicy: corev1.PullAlways,
    65  						Args: []string{
    66  							"--job_type=Train",
    67  							"--xgboost_parameter=objective:multi:softprob,num_class:3",
    68  							"--n_estimators=10",
    69  							"--learning_rate=0.1",
    70  						},
    71  					}},
    72  				},
    73  			},
    74  		},
    75  	}
    76  
    77  	testCases := map[string]struct {
    78  		xgboostJob *XGBoostJob
    79  		wantErr    bool
    80  	}{
    81  		"valid XGBoostJob": {
    82  			xgboostJob: &XGBoostJob{
    83  				ObjectMeta: metav1.ObjectMeta{
    84  					Name: "test",
    85  				},
    86  				Spec: XGBoostJobSpec{
    87  					XGBReplicaSpecs: validXGBoostReplicaSpecs,
    88  				},
    89  			},
    90  			wantErr: false,
    91  		},
    92  		"XGBoostJob name does not meet DNS1035": {
    93  			xgboostJob: &XGBoostJob{
    94  				ObjectMeta: metav1.ObjectMeta{
    95  					Name: "-test",
    96  				},
    97  				Spec: XGBoostJobSpec{
    98  					XGBReplicaSpecs: validXGBoostReplicaSpecs,
    99  				},
   100  			},
   101  			wantErr: true,
   102  		},
   103  		"empty containers": {
   104  			xgboostJob: &XGBoostJob{
   105  				ObjectMeta: metav1.ObjectMeta{
   106  					Name: "test",
   107  				},
   108  				Spec: XGBoostJobSpec{
   109  					XGBReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   110  						XGBoostJobReplicaTypeWorker: {
   111  							Template: corev1.PodTemplateSpec{
   112  								Spec: corev1.PodSpec{
   113  									Containers: []corev1.Container{},
   114  								},
   115  							},
   116  						},
   117  					},
   118  				},
   119  			},
   120  			wantErr: true,
   121  		},
   122  		"image is empty": {
   123  			xgboostJob: &XGBoostJob{
   124  				ObjectMeta: metav1.ObjectMeta{
   125  					Name: "test",
   126  				},
   127  				Spec: XGBoostJobSpec{
   128  					XGBReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   129  						XGBoostJobReplicaTypeWorker: {
   130  							Template: corev1.PodTemplateSpec{
   131  								Spec: corev1.PodSpec{
   132  									Containers: []corev1.Container{{
   133  										Name:  "xgboost",
   134  										Image: "",
   135  									}},
   136  								},
   137  							},
   138  						},
   139  					},
   140  				},
   141  			},
   142  			wantErr: true,
   143  		},
   144  		"xgboostJob default container name doesn't present": {
   145  			xgboostJob: &XGBoostJob{
   146  				ObjectMeta: metav1.ObjectMeta{
   147  					Name: "test",
   148  				},
   149  				Spec: XGBoostJobSpec{
   150  					XGBReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   151  						XGBoostJobReplicaTypeWorker: {
   152  							Template: corev1.PodTemplateSpec{
   153  								Spec: corev1.PodSpec{
   154  									Containers: []corev1.Container{{
   155  										Name:  "",
   156  										Image: "gcr.io/kubeflow-ci/xgboost-dist-mnist_test:1.0",
   157  									}},
   158  								},
   159  							},
   160  						},
   161  					},
   162  				},
   163  			},
   164  			wantErr: true,
   165  		},
   166  		"the number of replicas in masterReplica is other than 1": {
   167  			xgboostJob: &XGBoostJob{
   168  				ObjectMeta: metav1.ObjectMeta{
   169  					Name: "test",
   170  				},
   171  				Spec: XGBoostJobSpec{
   172  					XGBReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   173  						XGBoostJobReplicaTypeMaster: {
   174  							Replicas: pointer.Int32(2),
   175  							Template: corev1.PodTemplateSpec{
   176  								Spec: corev1.PodSpec{
   177  									Containers: []corev1.Container{{
   178  										Name:  "xgboost",
   179  										Image: "gcr.io/kubeflow-ci/xgboost-dist-mnist_test:1.0",
   180  									}},
   181  								},
   182  							},
   183  						},
   184  					},
   185  				},
   186  			},
   187  			wantErr: true,
   188  		},
   189  		"masterReplica does not exist": {
   190  			xgboostJob: &XGBoostJob{
   191  				ObjectMeta: metav1.ObjectMeta{
   192  					Name: "test",
   193  				},
   194  				Spec: XGBoostJobSpec{
   195  					XGBReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   196  						XGBoostJobReplicaTypeWorker: {
   197  							Replicas: pointer.Int32(1),
   198  							Template: corev1.PodTemplateSpec{
   199  								Spec: corev1.PodSpec{
   200  									Containers: []corev1.Container{{
   201  										Name:  "xgboost",
   202  										Image: "gcr.io/kubeflow-ci/xgboost-dist-mnist_test:1.0",
   203  									}},
   204  								},
   205  							},
   206  						},
   207  					},
   208  				},
   209  			},
   210  			wantErr: true,
   211  		},
   212  	}
   213  
   214  	for name, tc := range testCases {
   215  		t.Run(name, func(t *testing.T) {
   216  			got := ValidateV1XGBoostJob(tc.xgboostJob)
   217  			if (got != nil) != tc.wantErr {
   218  				t.Fatalf("ValidateV1XGBoostJob() error = %v, wantErr %v", got, tc.wantErr)
   219  			}
   220  		})
   221  	}
   222  }