|
17 | 17 | import static org.mockito.Mockito.*; |
18 | 18 |
|
19 | 19 | import io.fabric8.kubernetes.api.model.ObjectMeta; |
| 20 | +import io.fabric8.kubernetes.api.model.Toleration; |
| 21 | +import io.fabric8.kubernetes.api.model.TolerationBuilder; |
20 | 22 | import io.fabric8.kubernetes.client.KubernetesClient; |
21 | 23 | import io.fabric8.kubernetes.client.dsl.MixedOperation; |
22 | 24 | import io.fabric8.kubernetes.client.dsl.NamespaceableResource; |
23 | 25 | import io.fabric8.kubernetes.client.dsl.Resource; |
24 | 26 | import io.javaoperatorsdk.operator.api.reconciler.Context; |
25 | 27 | import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; |
26 | 28 | import java.time.Instant; |
| 29 | +import java.util.List; |
27 | 30 | import java.util.Map; |
28 | 31 | import org.junit.jupiter.api.BeforeEach; |
29 | 32 | import org.junit.jupiter.api.Test; |
30 | 33 | import org.junit.jupiter.api.extension.ExtendWith; |
| 34 | +import org.mockito.ArgumentCaptor; |
31 | 35 | import org.mockito.Mock; |
32 | 36 | import org.mockito.junit.jupiter.MockitoExtension; |
33 | 37 | import org.openmetadata.operator.controller.CronOMJobReconciler; |
34 | 38 | import org.openmetadata.operator.model.CronOMJobResource; |
35 | 39 | import org.openmetadata.operator.model.CronOMJobSpec; |
36 | 40 | import org.openmetadata.operator.model.CronOMJobStatus; |
| 41 | +import org.openmetadata.operator.model.OMJobResource; |
37 | 42 | import org.openmetadata.operator.model.OMJobSpec; |
38 | 43 |
|
39 | 44 | @ExtendWith(MockitoExtension.class) |
@@ -158,6 +163,79 @@ void testReconcileWithNullSpec() { |
158 | 163 | assertEquals("Missing schedule", cronOMJob.getStatus().getMessage()); |
159 | 164 | } |
160 | 165 |
|
| 166 | + @Test |
| 167 | + @SuppressWarnings("unchecked") |
| 168 | + void testReconcilePropagatesTolerationsFromCronOMJobToScheduledOMJob() { |
| 169 | + List<Toleration> tolerations = |
| 170 | + List.of( |
| 171 | + new TolerationBuilder() |
| 172 | + .withKey("dedicated") |
| 173 | + .withOperator("Equal") |
| 174 | + .withValue("ingestion") |
| 175 | + .withEffect("NoSchedule") |
| 176 | + .build(), |
| 177 | + new TolerationBuilder() |
| 178 | + .withKey("gpu") |
| 179 | + .withOperator("Exists") |
| 180 | + .withEffect("NoExecute") |
| 181 | + .withTolerationSeconds(300L) |
| 182 | + .build()); |
| 183 | + |
| 184 | + cronOMJob.getSpec().getOmJobSpec().getMainPodSpec().setTolerations(tolerations); |
| 185 | + cronOMJob.getSpec().getOmJobSpec().getExitHandlerSpec().setTolerations(tolerations); |
| 186 | + |
| 187 | + cronOMJob.getSpec().setSchedule("* * * * *"); |
| 188 | + cronOMJob.getSpec().setStartingDeadlineSeconds(86400); |
| 189 | + |
| 190 | + reconciler.reconcile(cronOMJob, context); |
| 191 | + |
| 192 | + ArgumentCaptor<OMJobResource> captor = ArgumentCaptor.forClass(OMJobResource.class); |
| 193 | + verify(mixedOp).resource(captor.capture()); |
| 194 | + OMJobResource scheduled = captor.getValue(); |
| 195 | + |
| 196 | + assertNotNull(scheduled.getSpec(), "Scheduled OMJob spec must not be null"); |
| 197 | + assertNotNull( |
| 198 | + scheduled.getSpec().getMainPodSpec().getTolerations(), |
| 199 | + "Main pod tolerations must be propagated from CronOMJob template"); |
| 200 | + assertEquals(2, scheduled.getSpec().getMainPodSpec().getTolerations().size()); |
| 201 | + assertEquals( |
| 202 | + "dedicated", scheduled.getSpec().getMainPodSpec().getTolerations().get(0).getKey()); |
| 203 | + assertEquals( |
| 204 | + "NoSchedule", scheduled.getSpec().getMainPodSpec().getTolerations().get(0).getEffect()); |
| 205 | + assertEquals("gpu", scheduled.getSpec().getMainPodSpec().getTolerations().get(1).getKey()); |
| 206 | + assertEquals( |
| 207 | + Long.valueOf(300L), |
| 208 | + scheduled.getSpec().getMainPodSpec().getTolerations().get(1).getTolerationSeconds()); |
| 209 | + |
| 210 | + assertNotNull( |
| 211 | + scheduled.getSpec().getExitHandlerSpec().getTolerations(), |
| 212 | + "Exit handler tolerations must be propagated from CronOMJob template"); |
| 213 | + assertEquals(2, scheduled.getSpec().getExitHandlerSpec().getTolerations().size()); |
| 214 | + } |
| 215 | + |
| 216 | + @Test |
| 217 | + @SuppressWarnings("unchecked") |
| 218 | + void testReconcileLeavesTolerationsNullWhenSourceHasNone() { |
| 219 | + cronOMJob.getSpec().getOmJobSpec().getMainPodSpec().setTolerations(null); |
| 220 | + cronOMJob.getSpec().getOmJobSpec().getExitHandlerSpec().setTolerations(null); |
| 221 | + |
| 222 | + cronOMJob.getSpec().setSchedule("* * * * *"); |
| 223 | + cronOMJob.getSpec().setStartingDeadlineSeconds(86400); |
| 224 | + |
| 225 | + reconciler.reconcile(cronOMJob, context); |
| 226 | + |
| 227 | + ArgumentCaptor<OMJobResource> captor = ArgumentCaptor.forClass(OMJobResource.class); |
| 228 | + verify(mixedOp).resource(captor.capture()); |
| 229 | + OMJobResource scheduled = captor.getValue(); |
| 230 | + |
| 231 | + assertNull( |
| 232 | + scheduled.getSpec().getMainPodSpec().getTolerations(), |
| 233 | + "Main pod tolerations must remain null when CronOMJob has none"); |
| 234 | + assertNull( |
| 235 | + scheduled.getSpec().getExitHandlerSpec().getTolerations(), |
| 236 | + "Exit handler tolerations must remain null when CronOMJob has none"); |
| 237 | + } |
| 238 | + |
161 | 239 | private CronOMJobResource createTestCronOMJob(String name, String schedule) { |
162 | 240 | CronOMJobResource cronOMJob = new CronOMJobResource(); |
163 | 241 |
|
|
0 commit comments