This is an automated email from the ASF dual-hosted git repository. jamesfredley pushed a commit to branch fix/flaky-ersatz-listener-test in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit f59f9371af0725842673e0ff177c60c82e5c92e9 Author: James Fredley <[email protected]> AuthorDate: Wed Feb 25 12:29:25 2026 -0500 fix: flaky ersatz listener test due to async race condition The 'ersatz listener captures request details' test in MicronautErsatzAdvancedSpec intermittently fails because the Ersatz listener callback executes asynchronously on a server thread while the test assertion runs immediately on the test thread. Use a thread-safe CopyOnWriteArrayList and Spock PollingConditions to wait for the listener to populate before asserting. Assisted-by: OpenCode <[email protected]> --- .../groovy/micronaut/MicronautErsatzAdvancedSpec.groovy | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautErsatzAdvancedSpec.groovy b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautErsatzAdvancedSpec.groovy index d5f036c152..21c1c760cc 100644 --- a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautErsatzAdvancedSpec.groovy +++ b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautErsatzAdvancedSpec.groovy @@ -31,10 +31,13 @@ import micronaut.client.MicronautHeaderClient import micronaut.client.MicronautTestClient import spock.lang.AutoCleanup import spock.lang.Specification +import spock.util.concurrent.PollingConditions import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value +import java.util.concurrent.CopyOnWriteArrayList + import grails.testing.mixin.integration.Integration @Integration @@ -556,7 +559,7 @@ class MicronautErsatzAdvancedSpec extends Specification { void "ersatz listener captures request details"() { given: 'ersatz captures request details' - List<Object> captured = [] + CopyOnWriteArrayList<Object> captured = new CopyOnWriteArrayList<>() ersatz.expectations({ expect -> expect.GET('/micronaut-test/listen', { req -> req.listener({ captured << it }) @@ -579,7 +582,11 @@ class MicronautErsatzAdvancedSpec extends Specification { then: 'a request was captured' response.status.code == 200 - captured.size() == 1 + + and: 'the listener eventually captures the request' + new PollingConditions(timeout: 5).eventually { + assert captured.size() == 1 + } and: 'ersatz verifies the call' ersatz.verify()
