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 }