Skip to content

Commit eff75af

Browse files
csviriclaude
andcommitted
test: de-flake DynamicGenericEventSourceRegistrationIT
The test captured the reconcile execution count while the create-triggered reconcile cascade was still running (the first await only checked that the ConfigMap and Secret existed, not that the system had quiesced), and asserted an exact +2 executions after the external replace. The reconciler re-writes the ConfigMap/Secret on every execution, so the number of self-induced reconciles is timing-dependent, and after the read-after-write filtering rework (#3414) the reconciler's own follow-up write is filtered, so a deterministic +2 no longer holds. Wait for the execution count to stabilize before capturing the baseline, and assert only a lower bound (at least one more execution) after the replace. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent 2b02207 commit eff75af

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationIT.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.javaoperatorsdk.operator.baseapi.dynamicgenericeventsourceregistration;
1717

1818
import java.time.Duration;
19+
import java.util.concurrent.atomic.AtomicInteger;
1920

2021
import org.junit.jupiter.api.Test;
2122
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -62,22 +63,41 @@ void registersEventSourcesDynamically() {
6263
var secret = extension.get(Secret.class, TEST_RESOURCE_NAME);
6364
assertThat(cm).isNotNull();
6465
assertThat(secret).isNotNull();
66+
assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2);
6567
});
66-
var executions = reconciler.getNumberOfExecutions();
68+
69+
// The reconciler creates/updates the ConfigMap and Secret on every execution, which produces
70+
// further watch events. Wait for that self-induced cascade to settle before capturing the
71+
// execution count, otherwise the captured value (and any delta we assert on it) is racy.
72+
var executions = awaitStableExecutionCount(reconciler);
6773
assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2);
68-
assertThat(executions).isLessThanOrEqualTo(3);
6974

7075
var cm = extension.get(ConfigMap.class, TEST_RESOURCE_NAME);
7176
cm.getData().put("key2", "val2");
7277

7378
extension.replace(cm); // triggers the reconciliation
7479

80+
// The external change triggers at least one reconciliation. We only assert a lower bound: the
81+
// reconciler's own subsequent write of the ConfigMap is filtered by read-after-write
82+
// consistency, so the exact number of follow-up executions is not deterministic.
7583
await()
84+
.untilAsserted(
85+
() -> assertThat(reconciler.getNumberOfExecutions()).isGreaterThan(executions));
86+
assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2);
87+
}
88+
89+
/** Waits until the execution count stops changing and returns the stable value. */
90+
private static int awaitStableExecutionCount(
91+
DynamicGenericEventSourceRegistrationReconciler reconciler) {
92+
var previous = new AtomicInteger(-1);
93+
await()
94+
.pollInterval(Duration.ofMillis(300))
7695
.untilAsserted(
7796
() -> {
78-
assertThat(reconciler.getNumberOfExecutions() - executions).isEqualTo(2);
97+
var current = reconciler.getNumberOfExecutions();
98+
assertThat(current).isEqualTo(previous.getAndSet(current));
7999
});
80-
assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2);
100+
return reconciler.getNumberOfExecutions();
81101
}
82102

83103
DynamicGenericEventSourceRegistrationCustomResource testResource() {

0 commit comments

Comments
 (0)