@@ -39,8 +39,7 @@ const (
39
39
interval = time .Millisecond * 250
40
40
)
41
41
42
- var _ = ginkgo .Describe ("JobSet controller" , func () {
43
-
42
+ var _ = ginkgo .Describe ("JobSet validation" , func () {
44
43
// Each test runs in a separate namespace.
45
44
var ns * corev1.Namespace
46
45
@@ -71,18 +70,17 @@ var _ = ginkgo.Describe("JobSet controller", func() {
71
70
// jobSetUpdate contains the mutations to perform on the jobset and the
72
71
// checks to perform afterwards.
73
72
type jobSetUpdate struct {
74
- jobUpdateFn func (* batchv1.JobList )
75
- checkJobSetState func (* jobset.JobSet )
76
- expectedJobSetCondition jobset.JobSetConditionType
73
+ fn func (* jobset.JobSet )
74
+ shouldSucceed bool
77
75
}
78
76
79
77
type testCase struct {
80
- makeJobSet func (* corev1.Namespace ) * testing.JobSetWrapper
81
- jobSetCreationShouldFail bool
82
- updates []* jobSetUpdate
78
+ makeJobSet func (* corev1.Namespace ) * testing.JobSetWrapper
79
+ jobSetCreationShouldSucceed bool
80
+ updates []* jobSetUpdate
83
81
}
84
82
85
- ginkgo .DescribeTable ("jobset is created and its jobs go through a series of updates" ,
83
+ ginkgo .DescribeTable ("validation on jobset creation and updates" ,
86
84
func (tc * testCase ) {
87
85
ctx := context .Background ()
88
86
@@ -91,7 +89,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
91
89
js := tc .makeJobSet (ns ).Obj ()
92
90
93
91
// If we are expected a validation error creating the jobset, end the test early.
94
- if tc .jobSetCreationShouldFail {
92
+ if ! tc .jobSetCreationShouldSucceed {
95
93
ginkgo .By ("checking that jobset creation fails" )
96
94
gomega .Expect (k8sClient .Create (ctx , js )).Should (gomega .Not (gomega .Succeed ()))
97
95
return
@@ -104,6 +102,118 @@ var _ = ginkgo.Describe("JobSet controller", func() {
104
102
// We'll need to retry getting this newly created jobset, given that creation may not immediately happen.
105
103
gomega .Eventually (k8sClient .Get (ctx , types.NamespacedName {Name : js .Name , Namespace : js .Namespace }, & jobset.JobSet {}), timeout , interval ).Should (gomega .Succeed ())
106
104
105
+ // Perform updates to the jobset and verify the validation is working correctly.
106
+ for _ , update := range tc .updates {
107
+
108
+ // Update jobset if specified.
109
+ if update .fn != nil {
110
+ update .fn (js )
111
+
112
+ // If we are expecting a validation error, we can skip the rest of the checks.
113
+ if ! update .shouldSucceed {
114
+ gomega .Expect (k8sClient .Update (ctx , js )).Should (gomega .Not (gomega .Succeed ()))
115
+ continue
116
+ }
117
+ // Verify a valid jobset update succeeded.
118
+ gomega .Expect (k8sClient .Update (ctx , js )).Should (gomega .Succeed ())
119
+ }
120
+ }
121
+ },
122
+ ginkgo .Entry ("validate enableDNSHostnames can't be set if job is not Indexed" , & testCase {
123
+ makeJobSet : func (ns * corev1.Namespace ) * testing.JobSetWrapper {
124
+ return testing .MakeJobSet ("js-hostnames-non-indexed" , ns .Name ).
125
+ ReplicatedJob (testing .MakeReplicatedJob ("test-job" ).
126
+ Job (testing .MakeJobTemplate ("test-job" , ns .Name ).PodSpec (testing .TestPodSpec ).Obj ()).
127
+ EnableDNSHostnames (true ).
128
+ Obj ())
129
+ },
130
+ }),
131
+ ginkgo .Entry ("validate jobset spec is immutable" , & testCase {
132
+ makeJobSet : testJobSet ,
133
+ jobSetCreationShouldSucceed : true ,
134
+ updates : []* jobSetUpdate {
135
+ {
136
+ fn : func (js * jobset.JobSet ) {
137
+ // Try mutating jobs list.
138
+ js .Spec .Jobs = append (js .Spec .Jobs , testing .MakeReplicatedJob ("test-job" ).
139
+ Job (testing .MakeJobTemplate ("test-job" , ns .Name ).PodSpec (testing .TestPodSpec ).Obj ()).
140
+ EnableDNSHostnames (true ).
141
+ Obj ())
142
+ },
143
+ },
144
+ {
145
+ fn : func (js * jobset.JobSet ) {
146
+ // Try mutating failure policy.
147
+ js .Spec .FailurePolicy = & jobset.FailurePolicy {
148
+ Operator : jobset .TerminationPolicyTargetAny ,
149
+ RestartPolicy : jobset .RestartPolicyRecreateAll ,
150
+ MaxRestarts : 3 ,
151
+ }
152
+ },
153
+ },
154
+ },
155
+ }),
156
+ ) // end of DescribeTable
157
+ }) // end of Describe
158
+
159
+ var _ = ginkgo .Describe ("JobSet controller" , func () {
160
+
161
+ // Each test runs in a separate namespace.
162
+ var ns * corev1.Namespace
163
+
164
+ ginkgo .BeforeEach (func () {
165
+ // Create test namespace before each test.
166
+ ns = & corev1.Namespace {
167
+ ObjectMeta : metav1.ObjectMeta {
168
+ GenerateName : "test-ns-" ,
169
+ },
170
+ }
171
+ gomega .Expect (k8sClient .Create (ctx , ns )).To (gomega .Succeed ())
172
+
173
+ // Wait for namespace to exist before proceeding with test.
174
+ gomega .Eventually (func () bool {
175
+ err := k8sClient .Get (ctx , types.NamespacedName {Namespace : ns .Namespace , Name : ns .Name }, ns )
176
+ if err != nil {
177
+ return false
178
+ }
179
+ return true
180
+ }, timeout , interval ).Should (gomega .BeTrue ())
181
+ })
182
+
183
+ ginkgo .AfterEach (func () {
184
+ // Delete test namespace after each test.
185
+ gomega .Expect (k8sClient .Delete (ctx , ns )).To (gomega .Succeed ())
186
+ })
187
+
188
+ // jobUpdate contains the mutations to perform on the jobs and the
189
+ // checks to perform afterwards.
190
+ type jobUpdate struct {
191
+ jobUpdateFn func (* batchv1.JobList )
192
+ checkJobSetState func (* jobset.JobSet )
193
+ expectedJobSetCondition jobset.JobSetConditionType
194
+ }
195
+
196
+ type testCase struct {
197
+ makeJobSet func (* corev1.Namespace ) * testing.JobSetWrapper
198
+ jobSetCreationShouldFail bool
199
+ updates []* jobUpdate
200
+ }
201
+
202
+ ginkgo .DescribeTable ("jobset is created and its jobs go through a series of updates" ,
203
+ func (tc * testCase ) {
204
+ ctx := context .Background ()
205
+
206
+ // Create JobSet.
207
+ ginkgo .By ("creating jobset" )
208
+ js := tc .makeJobSet (ns ).Obj ()
209
+
210
+ // Verify jobset created successfully.
211
+ ginkgo .By ("checking that jobset creation succeeds" )
212
+ gomega .Expect (k8sClient .Create (ctx , js )).Should (gomega .Succeed ())
213
+
214
+ // We'll need to retry getting this newly created jobset, given that creation may not immediately happen.
215
+ gomega .Eventually (k8sClient .Get (ctx , types.NamespacedName {Name : js .Name , Namespace : js .Namespace }, & jobset.JobSet {}), timeout , interval ).Should (gomega .Succeed ())
216
+
107
217
ginkgo .By ("checking all jobs were created successfully" )
108
218
gomega .Eventually (checkNumJobs , timeout , interval ).WithArguments (ctx , js ).Should (gomega .Equal (numExpectedJobs (js )))
109
219
@@ -131,20 +241,9 @@ var _ = ginkgo.Describe("JobSet controller", func() {
131
241
}
132
242
}
133
243
},
134
- // TODO: move validation tests to separate Describe + DescribeTable
135
- ginkgo .Entry ("validate enableDNSHostnames can't be set if job is not Indexed" , & testCase {
136
- makeJobSet : func (ns * corev1.Namespace ) * testing.JobSetWrapper {
137
- return testing .MakeJobSet ("js-hostnames-non-indexed" , ns .Name ).
138
- ReplicatedJob (testing .MakeReplicatedJob ("test-job" ).
139
- Job (testing .MakeJobTemplate ("test-job" , ns .Name ).Obj ()).
140
- EnableDNSHostnames (true ).
141
- Obj ())
142
- },
143
- jobSetCreationShouldFail : true ,
144
- }),
145
244
ginkgo .Entry ("jobset should succeed after all jobs succeed" , & testCase {
146
245
makeJobSet : testJobSet ,
147
- updates : []* jobSetUpdate {
246
+ updates : []* jobUpdate {
148
247
{
149
248
jobUpdateFn : completeAllJobs ,
150
249
expectedJobSetCondition : jobset .JobSetCompleted ,
@@ -153,7 +252,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
153
252
}),
154
253
ginkgo .Entry ("jobset with no failure policy should fail if any jobs fail" , & testCase {
155
254
makeJobSet : testJobSet ,
156
- updates : []* jobSetUpdate {
255
+ updates : []* jobUpdate {
157
256
{
158
257
jobUpdateFn : func (jobList * batchv1.JobList ) {
159
258
failJob (& jobList .Items [0 ])
@@ -164,7 +263,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
164
263
}),
165
264
ginkgo .Entry ("jobset with DNS hostnames enabled should created 1 headless service per job and succeed when all jobs succeed" , & testCase {
166
265
makeJobSet : testJobSet ,
167
- updates : []* jobSetUpdate {
266
+ updates : []* jobUpdate {
168
267
{
169
268
checkJobSetState : checkExpectedServices ,
170
269
},
@@ -176,7 +275,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
176
275
}),
177
276
ginkgo .Entry ("succeeds from first run" , & testCase {
178
277
makeJobSet : testJobSet ,
179
- updates : []* jobSetUpdate {
278
+ updates : []* jobUpdate {
180
279
{
181
280
checkJobSetState : checkExpectedServices ,
182
281
},
@@ -188,7 +287,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
188
287
}),
189
288
ginkgo .Entry ("fails from first run, no restarts" , & testCase {
190
289
makeJobSet : testJobSet ,
191
- updates : []* jobSetUpdate {
290
+ updates : []* jobUpdate {
192
291
{
193
292
checkJobSetState : checkExpectedServices ,
194
293
},
@@ -209,7 +308,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
209
308
MaxRestarts : 1 ,
210
309
})
211
310
},
212
- updates : []* jobSetUpdate {
311
+ updates : []* jobUpdate {
213
312
{
214
313
jobUpdateFn : func (jobList * batchv1.JobList ) {
215
314
failJob (& jobList .Items [0 ])
@@ -236,7 +335,7 @@ var _ = ginkgo.Describe("JobSet controller", func() {
236
335
MaxRestarts : 1 ,
237
336
})
238
337
},
239
- updates : []* jobSetUpdate {
338
+ updates : []* jobUpdate {
240
339
{
241
340
jobUpdateFn : func (jobList * batchv1.JobList ) {
242
341
completeJob (& jobList .Items [0 ])
0 commit comments