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

smiklosovic pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new a3c40f1a67 ninja: skip AsyncProfiler tests in CI when kernel 
parameters are not right
a3c40f1a67 is described below

commit a3c40f1a67b27262b9e0bd67dead76402c5aa9bb
Author: Stefan Miklosovic <[email protected]>
AuthorDate: Mon Jan 12 18:47:22 2026 +0100

    ninja: skip AsyncProfiler tests in CI when kernel parameters are not right
    
    Based on the official documentation here (1), AsyncProfiler works best with 
these kernel parameters.
    Not all CI environments have them set. That would fail the tests which run 
the startup check
    if kernel parameters are not like that.
    
    It might be empirically observed that some AsyncProfiler functionality 
works even without these
    kernel parameters, it might be investigated in follow-up work if we should 
not relax these conditions a bit.
    
    (1) 
https://github.com/async-profiler/async-profiler/blob/master/docs/GettingStarted.md#before-profiling
---
 .../apache/cassandra/service/StartupChecks.java    | 14 ++++++-
 .../distributed/test/AsyncProfilerTest.java        | 23 ++---------
 .../service/AsyncProfilerServiceTest.java          | 48 ++++++++++++++--------
 3 files changed, 46 insertions(+), 39 deletions(-)

diff --git a/src/java/org/apache/cassandra/service/StartupChecks.java 
b/src/java/org/apache/cassandra/service/StartupChecks.java
index daf0dc8ebe..6de0158a9c 100644
--- a/src/java/org/apache/cassandra/service/StartupChecks.java
+++ b/src/java/org/apache/cassandra/service/StartupChecks.java
@@ -766,7 +766,8 @@ public class StartupChecks
                                               "Try 'sysctl 
kernel.perf_event_paranoid=1' and 'sysctl kernel.kptr_restrict=0' or its " +
                                               "variation on your system to 
resolve the issue.";
 
-        protected int readPerfEventParanoid()
+        @VisibleForTesting
+        public int readPerfEventParanoid()
         {
             List<String> lines = FileUtils.readLines(new 
File("/proc/sys/kernel/perf_event_paranoid"));
             if (!lines.isEmpty())
@@ -774,7 +775,8 @@ public class StartupChecks
             return Integer.MIN_VALUE;
         }
 
-        protected int readKptrRestrict()
+        @VisibleForTesting
+        public int readKptrRestrict()
         {
             List<String> lines = FileUtils.readLines(new 
File("/proc/sys/kernel/kptr_restrict"));
             if (!lines.isEmpty())
@@ -782,6 +784,14 @@ public class StartupChecks
             return Integer.MIN_VALUE;
         }
 
+        public boolean hasCorrectKernelParams()
+        {
+            int perfEventParanoid = readPerfEventParanoid();
+            int kptrRestrict = readKptrRestrict();
+
+            return perfEventParanoid <= 1 && kptrRestrict == 0;
+        }
+
         public void execute(StartupChecksOptions startupChecksOptions, boolean 
shouldThrow)
         {
             try
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/AsyncProfilerTest.java 
b/test/distributed/org/apache/cassandra/distributed/test/AsyncProfilerTest.java
index 9032effb5f..5bddac87ed 100644
--- 
a/test/distributed/org/apache/cassandra/distributed/test/AsyncProfilerTest.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/test/AsyncProfilerTest.java
@@ -22,6 +22,7 @@ import java.nio.file.StandardOpenOption;
 import java.util.List;
 import java.util.UUID;
 
+import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -48,27 +49,11 @@ public class AsyncProfilerTest extends TestBaseImpl
 
     private Cluster cluster;
 
-    /**
-     * Test-friendly kernel params check that returns valid values without 
reading from /proc
-     */
-    public static class TestAsyncProfilerKernelParamsCheck extends 
StartupChecks.AsyncProfilerKernelParamsCheck
-    {
-        @Override
-        protected int readPerfEventParanoid()
-        {
-            return 1; // Valid value (must be <= 1)
-        }
-
-        @Override
-        protected int readKptrRestrict()
-        {
-            return 0; // Valid value (must be == 0)
-        }
-    }
-
     @Test
     public void testNodetoolCommands() throws Throwable
     {
+        Assume.assumeTrue(new 
StartupChecks.AsyncProfilerKernelParamsCheck().hasCorrectKernelParams());
+
         File newTmpDir = new File(tmpDir.newFolder());
 
         try (WithProperties withProperties = new WithProperties()
@@ -127,7 +112,7 @@ public class AsyncProfilerTest extends TestBaseImpl
             // Initialize AsyncProfilerService instance in the cluster node 
context with the test directory
             String tmpDirPath = newTmpDir.absolutePath();
             cluster.get(1).runOnInstance(() -> {
-                AsyncProfilerService.instance(tmpDirPath, true, new 
TestAsyncProfilerKernelParamsCheck());
+                AsyncProfilerService.instance(tmpDirPath, true);
             });
 
             // fetch
diff --git 
a/test/unit/org/apache/cassandra/service/AsyncProfilerServiceTest.java 
b/test/unit/org/apache/cassandra/service/AsyncProfilerServiceTest.java
index fc94a3de26..a05b3a6108 100644
--- a/test/unit/org/apache/cassandra/service/AsyncProfilerServiceTest.java
+++ b/test/unit/org/apache/cassandra/service/AsyncProfilerServiceTest.java
@@ -24,6 +24,7 @@ import java.util.Optional;
 import java.util.UUID;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -62,13 +63,13 @@ public class AsyncProfilerServiceTest
     private static class TestAsyncProfilerKernelParamsCheck extends 
StartupChecks.AsyncProfilerKernelParamsCheck
     {
         @Override
-        protected int readPerfEventParanoid()
+        public int readPerfEventParanoid()
         {
             return 1; // Valid value (must be <= 1)
         }
 
         @Override
-        protected int readKptrRestrict()
+        public int readKptrRestrict()
         {
             return 0; // Valid value (must be == 0)
         }
@@ -105,15 +106,24 @@ public class AsyncProfilerServiceTest
         profiler = null;
     }
 
-    private AsyncProfilerService getProfiler()
+    private AsyncProfilerService getProfiler(boolean skipCheck)
     {
         AsyncProfilerService.reset();
-        return AsyncProfilerService.instance(testOutputPath, false, new 
TestAsyncProfilerKernelParamsCheck());
+        if (skipCheck)
+        {
+            return AsyncProfilerService.instance(testOutputPath, false, new 
TestAsyncProfilerKernelParamsCheck());
+        }
+        else
+        {
+            return AsyncProfilerService.instance(testOutputPath, false);
+        }
     }
 
     @Test
     public void testStartAndStopProfiling() throws Throwable
     {
+        Assume.assumeTrue(new 
StartupChecks.AsyncProfilerKernelParamsCheck().hasCorrectKernelParams());
+
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, false))
         {
             Map<String, String> startParameters = 
Map.of(ASYNC_PROFILER_START_EVENTS_PARAM, cpu.name(),
@@ -122,7 +132,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
 
             Map<String, String> stopParameters = 
Map.of(ASYNC_PROFILER_STOP_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
-            AsyncProfilerService profiler = getProfiler();
+            AsyncProfilerService profiler = getProfiler(false);
             profiler.start(startParameters);
             Thread.sleep(5000);
             profiler.stop(stopParameters);
@@ -148,7 +158,7 @@ public class AsyncProfilerServiceTest
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, false))
         {
             Map<String, String> startParameters = Map.of();
-            assertThatThrownBy(() -> getProfiler().start(startParameters))
+            assertThatThrownBy(() -> getProfiler(true).start(startParameters))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Wrong parameters passed to start async 
profiler method. Passed parameters " +
                                   "should be:");
@@ -165,7 +175,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_DURATION_PARAM, "60s",
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
 
-            assertThatThrownBy(() -> getProfiler().start(startParameters))
+            assertThatThrownBy(() -> getProfiler(true).start(startParameters))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Event must be one or a combination of [cpu, 
alloc, lock, wall, nativemem, cache_misses]");
         }
@@ -180,7 +190,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_OUTPUT_FORMAT_PARAM, flamegraph.name(),
                                                          
ASYNC_PROFILER_START_DURATION_PARAM, "13h",
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
-            assertThatThrownBy(() -> getProfiler().start(startParameters))
+            assertThatThrownBy(() -> getProfiler(true).start(startParameters))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Max profiling duration is 43200 seconds. If 
you need longer profiling, use execute command instead");
         }
@@ -195,7 +205,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_OUTPUT_FORMAT_PARAM, "not_a_real_format",
                                                          
ASYNC_PROFILER_START_DURATION_PARAM, "60s",
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
-            assertThatThrownBy(() -> getProfiler().start(startParameters))
+            assertThatThrownBy(() -> getProfiler(true).start(startParameters))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Format must be one of [flat, traces, 
collapsed, flamegraph, tree, jfr]");
         }
@@ -210,7 +220,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_OUTPUT_FORMAT_PARAM, flamegraph.name(),
                                                          
ASYNC_PROFILER_START_DURATION_PARAM, "60s",
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, "| grep test");
-            assertThatThrownBy(() -> getProfiler().start(startParameters))
+            assertThatThrownBy(() -> getProfiler(true).start(startParameters))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Output file name must match pattern 
^[a-zA-Z0-9-]*\\.?[a-zA-Z0-9-]*$");
         }
@@ -226,7 +236,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_DURATION_PARAM, "10abc",
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, "abc");
             assertThatThrownBy(() -> {
-                getProfiler().start(startParameters);
+                getProfiler(true).start(startParameters);
             })
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining("Invalid duration: 10abc Accepted 
units:[SECONDS, MINUTES, HOURS, DAYS] where case matters and only non-negative 
values.");
@@ -236,6 +246,8 @@ public class AsyncProfilerServiceTest
     @Test
     public void testSecondStartNotExecuted()
     {
+        Assume.assumeTrue(new 
StartupChecks.AsyncProfilerKernelParamsCheck().hasCorrectKernelParams());
+
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, false))
         {
             Map<String, String> startParameters = 
Map.of(ASYNC_PROFILER_START_EVENTS_PARAM, cpu.name(),
@@ -244,7 +256,7 @@ public class AsyncProfilerServiceTest
                                                          
ASYNC_PROFILER_START_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
             Map<String, String> stopParameters = 
Map.of(ASYNC_PROFILER_STOP_OUTPUT_FILE_NAME_PARAM, testOutputFile.name());
 
-            AsyncProfilerService profiler = getProfiler();
+            AsyncProfilerService profiler = getProfiler(false);
             assertTrue(profiler.start(startParameters));
             assertFalse(profiler.start(startParameters));
             profiler.stop(stopParameters);
@@ -257,7 +269,7 @@ public class AsyncProfilerServiceTest
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, 
true).set(ASYNC_PROFILER_ENABLED, false))
         {
             assertThatThrownBy(() -> {
-                AsyncProfilerService profiler = getProfiler();
+                AsyncProfilerService profiler = getProfiler(true);
                 profiler.status();
             }).hasMessageContaining("Async Profiler is not enabled. Enable it 
by setting cassandra.async_profiler.enabled property to true.");
         }
@@ -268,7 +280,7 @@ public class AsyncProfilerServiceTest
     {
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, true))
         {
-            AsyncProfilerService profiler = getProfiler();
+            AsyncProfilerService profiler = getProfiler(false);
 
             profiler.execute("start,event=" + cpu.name() + ",file=" + 
testOutputFile.absolutePath());
             Thread.sleep(5000);
@@ -284,18 +296,18 @@ public class AsyncProfilerServiceTest
     {
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, true))
         {
-            getProfiler().execute("foo");
+            getProfiler(true).execute("foo");
         }
     }
 
     @Test
     public void testFetchIllegalFile()
     {
-        assertThatThrownBy(() -> getProfiler().fetch("../abc"))
+        assertThatThrownBy(() -> getProfiler(true).fetch("../abc"))
         .isInstanceOf(IllegalArgumentException.class)
         .hasMessage("Illegal file to fetch: ../abc");
 
-        assertThatThrownBy(() -> getProfiler().fetch("/etc/abc"))
+        assertThatThrownBy(() -> getProfiler(true).fetch("/etc/abc"))
         .isInstanceOf(IllegalArgumentException.class)
         .hasMessage("Illegal file to fetch: /etc/abc");
     }
@@ -305,7 +317,7 @@ public class AsyncProfilerServiceTest
     {
         try (WithProperties properties = new 
WithProperties().set(ASYNC_PROFILER_UNSAFE_MODE, false))
         {
-            assertThatThrownBy(() -> getProfiler().execute("foo"))
+            assertThatThrownBy(() -> getProfiler(true).execute("foo"))
             .isInstanceOf(SecurityException.class)
             .hasMessageContaining("The arbitrary command execution is not 
permitted with org.apache.cassandra.profiler:type=AsyncProfiler " +
                                   "MBean. If unsafe command execution is 
required, start Cassandra with " + ASYNC_PROFILER_UNSAFE_MODE.getKey() + ' ' +


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to