This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 5eb0cbdd8f minor refactor: reduce CI flakiness for JMX (cont'd)
5eb0cbdd8f is described below

commit 5eb0cbdd8f4fd6190912b77cbaf5e03e544b7ebe
Author: Paul King <[email protected]>
AuthorDate: Tue May 12 08:27:39 2026 +1000

    minor refactor: reduce CI flakiness for JMX (cont'd)
---
 .../jmx/builder/JmxListenerFactoryTest.groovy      | 94 +++++++++++++++-------
 1 file changed, 65 insertions(+), 29 deletions(-)

diff --git 
a/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxListenerFactoryTest.groovy
 
b/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxListenerFactoryTest.groovy
index 5e6e562bd3..208621853b 100644
--- 
a/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxListenerFactoryTest.groovy
+++ 
b/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxListenerFactoryTest.groovy
@@ -18,27 +18,37 @@
  */
 package groovy.jmx.builder
 
+import org.junit.jupiter.api.Assumptions
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 
 import javax.management.ObjectName
+import java.lang.management.ManagementFactory
 import java.util.logging.Level
 import java.util.logging.Logger
 
 import static groovy.test.GroovyAssert.shouldFail
 
 class JmxListenerFactoryTest {
+    private static final Logger LOGGER = 
Logger.getLogger(JmxListenerFactoryTest.name)
+
     static {
-        // Prime java.util.Timer's first-use init to absorb a JDK cgroup-v2 
NPE that
-        // sporadically surfaces (CgroupV2Subsystem.getInstance) on 
containerized CI
-        // when the JMX timer test spins up its housekeeper thread. The trip is
-        // environmental and one-shot — after the JVM stashes whatever cgroup 
state
-        // it managed to resolve, later calls succeed.
+        // Prime the code paths that sporadically NPE on first use in 
containerized
+        // CI environments — JDK cgroup-v2 detection (CgroupV2Subsystem / 
CgroupInfo).
+        // JMX MBean registration walks the platform OS MXBean, which on Linux
+        // consults cgroup state. Where the trip is a one-shot first-use race,
+        // priming here absorbs it. Where the trip is deterministic (the JDK 
bug
+        // fires on every call in this env), the per-test guard below converts 
it
+        // into a skipped assumption instead of a failure.
+        try {
+            ManagementFactory.getOperatingSystemMXBean().toString()
+        } catch (Throwable t) {
+            LOGGER.log(Level.FINE, 'Primed OS MXBean init absorbed exception 
(likely JDK cgroup-v2)', t)
+        }
         try {
-            new java.util.Timer(true).cancel()
+            new JmxBuilder().timer(name: 'prime:type=timer-prime', period: 
60000)
         } catch (Throwable t) {
-            Logger.getLogger(JmxListenerFactoryTest.name).log(Level.FINE,
-                'Primed java.util.Timer init absorbed exception (likely JDK 
cgroup-v2)', t)
+            LOGGER.log(Level.FINE, 'Primed JmxBuilder.timer absorbed exception 
(likely JDK cgroup-v2)', t)
         }
     }
 
@@ -51,36 +61,62 @@ class JmxListenerFactoryTest {
 
     @Test
     void testRequiredAttributeFrom() {
-        builder.timer(name: "test:type=timer")
-        def lstr = builder.listener(from: "test:type=timer")
-        assert lstr
-        assert lstr.type == "eventListener"
-        assert lstr.from instanceof ObjectName
-        assert lstr.from == new ObjectName("test:type=timer")
+        try {
+            builder.timer(name: "test:type=timer")
+            def lstr = builder.listener(from: "test:type=timer")
+            assert lstr
+            assert lstr.type == "eventListener"
+            assert lstr.from instanceof ObjectName
+            assert lstr.from == new ObjectName("test:type=timer")
 
-        shouldFail {
-            lstr = builder.listener(event: "someEvent")
-            lstr = builder.listener(from: "test:type=nonExistingObject")
+            shouldFail {
+                lstr = builder.listener(event: "someEvent")
+                lstr = builder.listener(from: "test:type=nonExistingObject")
+            }
+        } catch (Throwable t) {
+            skipIfKnownCgroupNpe(t)
+            throw t
         }
     }
 
     @Test
     void testListenerEvent() {
-        def eventCount = 0
-        builder.timer(name: "test:type=timer", period: 200).start()
-        builder.listener(from: "test:type=timer", call: {event ->
-            eventCount = eventCount + 1
-        })
-        sleep 1300
-        assert eventCount > 1
-
-        shouldFail {
-            eventCount = 0
+        try {
+            def eventCount = 0
+            builder.timer(name: "test:type=timer", period: 200).start()
             builder.listener(from: "test:type=timer", call: {event ->
                 eventCount = eventCount + 1
             })
-            sleep 700
-            assert eventCount == 0
+            sleep 1300
+            assert eventCount > 1
+
+            shouldFail {
+                eventCount = 0
+                builder.listener(from: "test:type=timer", call: {event ->
+                    eventCount = eventCount + 1
+                })
+                sleep 700
+                assert eventCount == 0
+            }
+        } catch (Throwable t) {
+            skipIfKnownCgroupNpe(t)
+            throw t
+        }
+    }
+
+    /**
+     * If the given throwable (or any of its causes) is the known JDK cgroup-v2
+     * NPE — {@code CgroupInfo.getMountPoint()} on a null controller — abort 
the
+     * test with an assumption (reported as skipped, not failed). Any other
+     * failure propagates unchanged.
+     */
+    private static void skipIfKnownCgroupNpe(Throwable t) {
+        for (Throwable c = t; c != null; c = c.cause) {
+            String msg = c.message
+            if (c instanceof NullPointerException && msg != null &&
+                (msg.contains('CgroupInfo.getMountPoint') || 
msg.contains('anyController') && msg.contains('null'))) {
+                Assumptions.abort("Skipped: known JDK cgroup-v2 NPE in this CI 
environment: ${msg}")
+            }
         }
     }
 }

Reply via email to