github.com/kubeflow/training-operator@v1.7.0/pkg/apis/kubeflow.org/v1/mxnet_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 TestValidateV1MXJob(t *testing.T) {
    26  	validMXReplicaSpecs := map[ReplicaType]*ReplicaSpec{
    27  		MXJobReplicaTypeScheduler: {
    28  			Replicas:      pointer.Int32(1),
    29  			RestartPolicy: RestartPolicyNever,
    30  			Template: corev1.PodTemplateSpec{
    31  				Spec: corev1.PodSpec{
    32  					Containers: []corev1.Container{{
    33  						Name:  "mxnet",
    34  						Image: "mxjob/mxnet",
    35  					}},
    36  				},
    37  			},
    38  		},
    39  		MXJobReplicaTypeServer: {
    40  			Replicas:      pointer.Int32(1),
    41  			RestartPolicy: RestartPolicyNever,
    42  			Template: corev1.PodTemplateSpec{
    43  				Spec: corev1.PodSpec{
    44  					Containers: []corev1.Container{{
    45  						Name:  "mxnet",
    46  						Image: "mxjob/mxnet",
    47  					}},
    48  				},
    49  			},
    50  		},
    51  		MXJobReplicaTypeWorker: {
    52  			Replicas:      pointer.Int32(1),
    53  			RestartPolicy: RestartPolicyNever,
    54  			Template: corev1.PodTemplateSpec{
    55  				Spec: corev1.PodSpec{
    56  					Containers: []corev1.Container{{
    57  						Name:    "mxnet",
    58  						Image:   "mxjob/mxnet",
    59  						Command: []string{"python"},
    60  						Args: []string{
    61  							"/incubator-mxnet/example/image-classification/train_mnist.py",
    62  							"--num-epochs=10",
    63  							"--num-layers=2",
    64  							"--kv-store=dist_device_sync",
    65  						},
    66  					}},
    67  				},
    68  			},
    69  		},
    70  	}
    71  
    72  	testCases := map[string]struct {
    73  		MXJob   *MXJob
    74  		wantErr bool
    75  	}{
    76  		"valid mxJob": {
    77  			MXJob: &MXJob{
    78  				ObjectMeta: metav1.ObjectMeta{
    79  					Name: "test",
    80  				},
    81  				Spec: MXJobSpec{
    82  					MXReplicaSpecs: validMXReplicaSpecs,
    83  				},
    84  			},
    85  			wantErr: false,
    86  		},
    87  		"mxReplicaSpecs is nil": {
    88  			MXJob: &MXJob{
    89  				ObjectMeta: metav1.ObjectMeta{
    90  					Name: "test",
    91  				},
    92  			},
    93  			wantErr: true,
    94  		},
    95  		"mxJob name does not meet DNS1035": {
    96  			MXJob: &MXJob{
    97  				ObjectMeta: metav1.ObjectMeta{
    98  					Name: "10test",
    99  				},
   100  				Spec: MXJobSpec{
   101  					MXReplicaSpecs: validMXReplicaSpecs,
   102  				},
   103  			},
   104  			wantErr: true,
   105  		},
   106  		"no containers": {
   107  			MXJob: &MXJob{
   108  				ObjectMeta: metav1.ObjectMeta{
   109  					Name: "test",
   110  				},
   111  				Spec: MXJobSpec{
   112  					MXReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   113  						MXJobReplicaTypeWorker: {
   114  							Template: corev1.PodTemplateSpec{
   115  								Spec: corev1.PodSpec{
   116  									Containers: []corev1.Container{},
   117  								},
   118  							},
   119  						},
   120  					},
   121  				},
   122  			},
   123  			wantErr: true,
   124  		},
   125  		"image is empty": {
   126  			MXJob: &MXJob{
   127  				ObjectMeta: metav1.ObjectMeta{
   128  					Name: "test",
   129  				},
   130  				Spec: MXJobSpec{
   131  					MXReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   132  						MXJobReplicaTypeWorker: {
   133  							Template: corev1.PodTemplateSpec{
   134  								Spec: corev1.PodSpec{
   135  									Containers: []corev1.Container{{
   136  										Name:  "mxnet",
   137  										Image: "",
   138  									}},
   139  								},
   140  							},
   141  						},
   142  					},
   143  				},
   144  			},
   145  			wantErr: true,
   146  		},
   147  		"mxnet default container name doesn't find": {
   148  			MXJob: &MXJob{
   149  				ObjectMeta: metav1.ObjectMeta{
   150  					Name: "test",
   151  				},
   152  				Spec: MXJobSpec{
   153  					MXReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   154  						MXJobReplicaTypeWorker: {
   155  							Template: corev1.PodTemplateSpec{
   156  								Spec: corev1.PodSpec{
   157  									Containers: []corev1.Container{{
   158  										Name:  "",
   159  										Image: "mxjob/mxnet:gpu",
   160  									}},
   161  								},
   162  							},
   163  						},
   164  					},
   165  				},
   166  			},
   167  			wantErr: true,
   168  		},
   169  		"replicaSpec is nil": {
   170  			MXJob: &MXJob{
   171  				ObjectMeta: metav1.ObjectMeta{
   172  					Name: "test",
   173  				},
   174  				Spec: MXJobSpec{
   175  					MXReplicaSpecs: map[ReplicaType]*ReplicaSpec{
   176  						MXJobReplicaTypeScheduler: nil,
   177  					},
   178  				},
   179  			},
   180  			wantErr: true,
   181  		},
   182  	}
   183  
   184  	for name, tc := range testCases {
   185  		t.Run(name, func(t *testing.T) {
   186  			got := ValidateV1MXJob(tc.MXJob)
   187  			if (got != nil) != tc.wantErr {
   188  				t.Fatalf("ValidateV1MXJob() error = %v, wantErr %v", got, tc.wantErr)
   189  			}
   190  		})
   191  	}
   192  }