test: reset ExternalIDGenServiceMock between tests to fix flaky external-state ITs#3387
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds explicit reset hooks to a JVM-lifetime singleton test mock and invokes them before each test to prevent cross-test state leakage.
Changes:
- Added
reset()toExternalIDGenServiceMockto clear internal state. - Added
@BeforeEachsetup in external-state tests to reset the singleton before every test run.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalIDGenServiceMock.java | Adds a reset() method to clear the singleton mock’s internal state between tests. |
| operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent/ExternalStateBulkIT.java | Resets the singleton mock before each test to avoid state leakage. |
| operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalStateTestBase.java | Resets the singleton mock before each test in the shared base test class. |
| @BeforeEach | ||
| void resetExternalService() { | ||
| externalService.reset(); | ||
| } |
There was a problem hiding this comment.
Centralised the reset into ExternalServiceResetExtension (BeforeEachCallback) and dropped the duplicated @BeforeEach blocks. Both ExternalStateTestBase and ExternalStateBulkIT now declare @ExtendWith(ExternalServiceResetExtension.class).
|
Hi @Dennis-Mircea, thank you for the PR. Please run the spotless plugin to format the code in order for CI to pass. |
Resolved! |
…nal-state ITs Signed-off-by: Dennis-Mircea Ciupitu <dennis.mircea.ciupitu@gmail.com>
Signed-off-by: Dennis-Mircea Ciupitu <dennis.mircea.ciupitu@gmail.com>
0a6a5fe to
233cb9f
Compare
csviri
left a comment
There was a problem hiding this comment.
LGTM!
thank you @Dennis-Mircea
Summary
Fixes an intermittent CI failure in three integration tests (an example can be found here: https://github.com/operator-framework/java-operator-sdk/actions/runs/26563951370/job/78253684721?pr=3383):
ExternalStateIT.reconcilesResourceWithPersistentStateExternalStateDependentIT.reconcilesResourceWithPersistentState(extendsExternalStateTestBase)ExternalStateBulkIT.reconcilesResourceWithPersistentStateSymptoms in CI:
The same
ExternalResource@3370ff56instance hash showed up in all three failures, which is the giveaway: anExternalResourceobject was outliving the test that created it.Root cause
operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalIDGenServiceMock.javais a JVM-lifetime singleton with a mutableConcurrentHashMapfield:Each external-state test creates resources through
getInstance().create(...)(entered intoresourceMap) and expects the reconciler's cleanup path to remove them after the custom resource is deleted. Cleanup is asynchronous, so when the next test runs there is a race window in which the previous test'sExternalResourceis still in the map. The next test creates its own resource, sees two entries, andAwaitilitytimes out after 10 s.Fix
Three small, test-only changes:
reset()method toExternalIDGenServiceMockthat clears the internal map.@BeforeEachinExternalStateTestBase(covers bothExternalStateITandExternalStateDependentIT).@BeforeEachinExternalStateBulkIT(which does not extend the base).Concurrency note
JOSDK does not enable JUnit 5 parallel execution (no
junit-platform.properties, nojunit.jupiter.execution.parallel.*properties in anypom.xml). The flake addressed here is a sequential test-ordering issue, not a parallel-execution one, and theBeforeEachCallbackis sufficient given that constraint. If parallel execution is ever enabled, the singleton would need to be replaced by per-test instances rather than relying onreset().Test plan
mvn -pl operator-framework verify -Dit.test=ExternalStateIT,ExternalStateDependentIT,ExternalStateBulkITpasses locally on a clean checkout.ExternalIDGenServiceMock.