From 6ac8daa9e66b4b975c298c784a0d005f9a602a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 18 Sep 2025 13:43:40 +0200 Subject: [PATCH 1/2] improve: PrimaryToSecondayMapper test improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../baseapi/primarytosecondary/Cluster.java | 2 +- .../primarytosecondary/ClusterSpec.java | 14 ++++++++ .../baseapi/primarytosecondary/Job.java | 2 +- .../primarytosecondary/JobReconciler.java | 33 ++++++++++++------- .../baseapi/primarytosecondary/JobStatus.java | 14 ++++++++ .../PrimaryToSecondaryIT.java | 18 +++++++--- 6 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/ClusterSpec.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobStatus.java diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Cluster.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Cluster.java index d0be7738a6..1d154cd6a8 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Cluster.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Cluster.java @@ -9,4 +9,4 @@ @Group("sample.javaoperatorsdk") @Version("v1") @ShortNames("clu") -public class Cluster extends CustomResource implements Namespaced {} +public class Cluster extends CustomResource implements Namespaced {} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/ClusterSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/ClusterSpec.java new file mode 100644 index 0000000000..b948bea6b4 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/ClusterSpec.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.baseapi.primarytosecondary; + +public class ClusterSpec { + + private String clusterValue; + + public String getClusterValue() { + return clusterValue; + } + + public void setClusterValue(String clusterValue) { + this.clusterValue = clusterValue; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Job.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Job.java index 611898bd52..bec3598e73 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Job.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/Job.java @@ -9,4 +9,4 @@ @Group("sample.javaoperatorsdk") @Version("v1") @ShortNames("cjo") -public class Job extends CustomResource implements Namespaced {} +public class Job extends CustomResource implements Namespaced {} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java index 1855f89b77..37617ac054 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java @@ -38,26 +38,37 @@ public JobReconciler(boolean addPrimaryToSecondaryMapper) { @Override public UpdateControl reconcile(Job resource, Context context) { - + Cluster cluster; if (!getResourceDirectlyFromCache) { // this is only possible when there is primary to secondary mapper - context - .getSecondaryResource(Cluster.class) - .orElseThrow(() -> new IllegalStateException("Secondary resource should be present")); + cluster = + context + .getSecondaryResource(Cluster.class) + .orElseThrow(() -> new IllegalStateException("Secondary resource should be present")); } else { // reading the resource from cache as alternative, works without primary to secondary mapper var informerEventSource = (InformerEventSource) context.eventSourceRetriever().getEventSourceFor(Cluster.class); - informerEventSource - .get( - new ResourceID( - resource.getSpec().getClusterName(), resource.getMetadata().getNamespace())) - .orElseThrow( - () -> new IllegalStateException("Secondary resource cannot be read from cache")); + cluster = + informerEventSource + .get( + new ResourceID( + resource.getSpec().getClusterName(), resource.getMetadata().getNamespace())) + .orElseThrow( + () -> new IllegalStateException("Secondary resource cannot be read from cache")); + } + if (resource.getStatus() == null) { + resource.setStatus(new JobStatus()); } numberOfExecutions.addAndGet(1); - return UpdateControl.noUpdate(); + // copy a value to job status, to we can test triggering + if (!cluster.getSpec().getClusterValue().equals(resource.getStatus().getValueFromCluster())) { + resource.getStatus().setValueFromCluster(cluster.getSpec().getClusterValue()); + return UpdateControl.patchStatus(resource); + } else { + return UpdateControl.noUpdate(); + } } @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobStatus.java new file mode 100644 index 0000000000..d59634b295 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobStatus.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.baseapi.primarytosecondary; + +public class JobStatus { + + private String valueFromCluster; + + public String getValueFromCluster() { + return valueFromCluster; + } + + public void setValueFromCluster(String valueFromCluster) { + this.valueFromCluster = valueFromCluster; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java index 9344cc787f..059afcb736 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java @@ -16,6 +16,9 @@ class PrimaryToSecondaryIT { public static final String CLUSTER_NAME = "cluster1"; public static final int MIN_DELAY = 150; + public static final String CLUSTER_VALUE = "clusterValue"; + public static final String JOB_1 = "job1"; + @RegisterExtension LocallyRunOperatorExtension operator = LocallyRunOperatorExtension.builder() @@ -32,15 +35,18 @@ void readsSecondaryInManyToOneCases() throws InterruptedException { await() .pollDelay(Duration.ofMillis(300)) .untilAsserted( - () -> - assertThat( - operator.getReconcilerOfType(JobReconciler.class).getNumberOfExecutions()) - .isEqualTo(1)); + () -> { + assertThat(operator.getReconcilerOfType(JobReconciler.class).getNumberOfExecutions()) + .isEqualTo(1); + var job = operator.get(Job.class, JOB_1); + assertThat(job.getStatus()).isNotNull(); + assertThat(job.getStatus().getValueFromCluster()).isEqualTo(CLUSTER_VALUE); + }); } public static Job job() { var job = new Job(); - job.setMetadata(new ObjectMetaBuilder().withName("job1").build()); + job.setMetadata(new ObjectMetaBuilder().withName(JOB_1).build()); job.setSpec(new JobSpec()); job.getSpec().setClusterName(CLUSTER_NAME); return job; @@ -49,6 +55,8 @@ public static Job job() { public static Cluster cluster() { Cluster cluster = new Cluster(); cluster.setMetadata(new ObjectMetaBuilder().withName(CLUSTER_NAME).build()); + cluster.setSpec(new ClusterSpec()); + cluster.getSpec().setClusterValue(CLUSTER_VALUE); return cluster; } } From 226607f0ed71d228e21ed3c74ddb4f7e4573d39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 18 Sep 2025 15:13:55 +0200 Subject: [PATCH 2/2] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../primarytosecondary/JobReconciler.java | 2 +- .../PrimaryToSecondaryIT.java | 23 +++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java index 37617ac054..6c51a06b1c 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/JobReconciler.java @@ -17,7 +17,7 @@ * needed, and to show the use cases when some mechanisms would not work without that. It's not * intended to be a reusable code as it is, rather serves for deeper understanding of the problem. */ -@ControllerConfiguration() +@ControllerConfiguration public class JobReconciler implements Reconciler { private static final String JOB_CLUSTER_INDEX = "job-cluster-index"; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java index 059afcb736..d82c24a55f 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary/PrimaryToSecondaryIT.java @@ -18,9 +18,10 @@ class PrimaryToSecondaryIT { public static final String CLUSTER_VALUE = "clusterValue"; public static final String JOB_1 = "job1"; + public static final String CHANGED_VALUE = "CHANGED_VALUE"; @RegisterExtension - LocallyRunOperatorExtension operator = + LocallyRunOperatorExtension extension = LocallyRunOperatorExtension.builder() .withAdditionalCustomResourceDefinition(Cluster.class) .withReconciler(new JobReconciler()) @@ -28,20 +29,32 @@ class PrimaryToSecondaryIT { @Test void readsSecondaryInManyToOneCases() throws InterruptedException { - operator.create(cluster()); + var cluster = extension.create(cluster()); Thread.sleep(MIN_DELAY); - operator.create(job()); + extension.create(job()); await() .pollDelay(Duration.ofMillis(300)) .untilAsserted( () -> { - assertThat(operator.getReconcilerOfType(JobReconciler.class).getNumberOfExecutions()) + assertThat(extension.getReconcilerOfType(JobReconciler.class).getNumberOfExecutions()) .isEqualTo(1); - var job = operator.get(Job.class, JOB_1); + var job = extension.get(Job.class, JOB_1); assertThat(job.getStatus()).isNotNull(); assertThat(job.getStatus().getValueFromCluster()).isEqualTo(CLUSTER_VALUE); }); + + cluster.getSpec().setClusterValue(CHANGED_VALUE); + extension.replace(cluster); + + // cluster change triggers job reconciliations + await() + .pollDelay(Duration.ofMillis(300)) + .untilAsserted( + () -> { + var job = extension.get(Job.class, JOB_1); + assertThat(job.getStatus().getValueFromCluster()).isEqualTo(CHANGED_VALUE); + }); } public static Job job() {