diff --git a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java index a08375fd67..a832679422 100644 --- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java +++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java @@ -35,6 +35,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.junit.Test; @@ -172,6 +173,7 @@ public class DatabaseDescriptorRefTest static final Set checkedClasses = new HashSet<>(Arrays.asList(validClasses)); @Test + @SuppressWarnings({"DynamicRegexReplaceableByCompiledPattern", "UseOfSystemOutOrSystemErr"}) public void testDatabaseDescriptorRef() throws Throwable { PrintStream out = System.out; @@ -179,6 +181,7 @@ public class DatabaseDescriptorRefTest ThreadMXBean threads = ManagementFactory.getThreadMXBean(); int threadCount = threads.getThreadCount(); + List existingThreadIDs = Arrays.stream(threads.getAllThreadIds()).boxed().collect(Collectors.toList()); ClassLoader delegate = Thread.currentThread().getContextClassLoader(); @@ -252,7 +255,29 @@ public class DatabaseDescriptorRefTest assertEquals("thread started", threadCount, threads.getThreadCount()); - Class cDatabaseDescriptor = Class.forName("org.apache.cassandra.config.DatabaseDescriptor", true, cl); + Class databaseDescriptorClass = Class.forName("org.apache.cassandra.config.DatabaseDescriptor", true, cl); + + // During DatabaseDescriptor instantiation some threads are spawned. We need to take them into account in + // threadCount variable, otherwise they will be considered as new threads spawned by methods below. There is a + // trick: in case of multiple runs of this test in the same JVM the number of such threads will be multiplied by + // the number of runs. That's because DatabaseDescriptor is instantiated via a different class loader. So in + // order to keep calculation logic correct, we ignore existing threads that were spawned during the previous + // runs and change threadCount variable for the new threads only (if they have some specific names). + for (ThreadInfo threadInfo : threads.getThreadInfo(threads.getAllThreadIds())) + { + // All existing threads have been already taken into account in threadCount variable, so we ignore them + if (existingThreadIDs.contains(threadInfo.getThreadId())) + continue; + // Logback AsyncAppender thread needs to be taken into account + if (threadInfo.getThreadName().equals("AsyncAppender-Worker-ASYNC")) + threadCount++; + // Logback basic threads need to be taken into account + if (threadInfo.getThreadName().matches("logback-\\d+")) + threadCount++; + // Dynamic Attach thread needs to be taken into account, generally it is spawned by IDE + if (threadInfo.getThreadName().equals("Attach Listener")) + threadCount++; + } for (String methodName : new String[]{ "clientInitialization", @@ -268,16 +293,9 @@ public class DatabaseDescriptorRefTest // starts "REQUEST-SCHEDULER" thread via RoundRobinScheduler }) { - Method method = cDatabaseDescriptor.getDeclaredMethod(methodName); + Method method = databaseDescriptorClass.getDeclaredMethod(methodName); method.invoke(null); - - if ("clientInitialization".equals(methodName) && - threadCount + 2 == threads.getThreadCount()) - { - // ignore the "AsyncAppender-Worker-ASYNC" and "logback-1" threads - threadCount = threadCount + 2; - } - + if (threadCount != threads.getThreadCount()) { for (ThreadInfo threadInfo : threads.getThreadInfo(threads.getAllThreadIds()))