diff --git a/CHANGES.txt b/CHANGES.txt
index 025f710a4a..b486d00ef2 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -13,6 +13,7 @@
Merged from 3.11:
* Fix Splitter sometimes creating more splits than requested (CASSANDRA-18013)
Merged from 3.0:
+ * Introduce check for names of test classes (CASSANDRA-17964)
* Suppress CVE-2021-1471, CVE-2021-3064, CVE-2021-4235 (CASSANDRA-18149)
* Switch to snakeyaml's SafeConstructor (CASSANDRA-18150)
* Expand build.dir property in rat targets (CASSANDRA-18183)
diff --git a/build.xml b/build.xml
index 963761b230..a8b21b61f0 100644
--- a/build.xml
+++ b/build.xml
@@ -63,6 +63,7 @@
+
@@ -544,7 +545,7 @@
-
+
@@ -1292,6 +1293,7 @@
+
@@ -1300,12 +1302,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/anttasks/org/apache/cassandra/anttasks/TestNameCheckTask.java b/test/anttasks/org/apache/cassandra/anttasks/TestNameCheckTask.java
new file mode 100644
index 0000000000..a5222261f2
--- /dev/null
+++ b/test/anttasks/org/apache/cassandra/anttasks/TestNameCheckTask.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.anttasks;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import org.reflections.util.ConfigurationBuilder;
+
+import static java.util.stream.Collectors.toList;
+
+public class TestNameCheckTask extends Task
+{
+ private static final Reflections reflections = new Reflections(new ConfigurationBuilder()
+ .forPackage("org.apache.cassandra")
+ .setScanners(Scanners.MethodsAnnotated, Scanners.SubTypes)
+ .setExpandSuperTypes(true)
+ .setParallel(true));
+
+ public TestNameCheckTask()
+ {
+ }
+
+ @Override
+ public void execute() throws BuildException
+ {
+ Set methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Test.class);
+ List testFiles = methodsAnnotatedWith.stream().map(Method::getDeclaringClass).distinct()
+ .flatMap(TestNameCheckTask::expand)
+ .map(TestNameCheckTask::normalize)
+ .map(Class::getCanonicalName)
+ .filter(s -> !s.endsWith("Test"))
+ .distinct().sorted()
+ .collect(toList());
+
+ if (!testFiles.isEmpty())
+ throw new BuildException("Detected tests that have a bad naming convention. All tests have to end on 'Test': \n" + String.join("\n", testFiles));
+ }
+
+ private static Class> normalize(Class> klass)
+ {
+ for (; klass.getEnclosingClass() != null; klass = klass.getEnclosingClass())
+ {
+ }
+ return klass;
+ }
+
+ private static Stream> expand(Class> klass)
+ {
+ Set extends Class>> subTypes = reflections.getSubTypesOf(klass);
+ if (subTypes == null || subTypes.isEmpty())
+ return Stream.of(klass);
+ Stream> subs = (Stream>) subTypes.stream();
+ // assume we include if not abstract
+ if (!Modifier.isAbstract(klass.getModifiers()))
+ subs = Stream.concat(Stream.of(klass), subs);
+ return subs;
+ }
+
+
+}
diff --git a/test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamples.java b/test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamplesTest.java
similarity index 98%
rename from test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamples.java
rename to test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamplesTest.java
index b49572dc4b..aea3609c84 100644
--- a/test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamples.java
+++ b/test/distributed/org/apache/cassandra/distributed/test/ByteBuddyExamplesTest.java
@@ -41,7 +41,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-public class ByteBuddyExamples extends TestBaseImpl
+public class ByteBuddyExamplesTest extends TestBaseImpl
{
@Test
public void writeFailureTest() throws Throwable
diff --git a/test/distributed/org/apache/cassandra/distributed/test/ReprepareTestOldBehaviour.java b/test/distributed/org/apache/cassandra/distributed/test/ReprepareOldBehaviourTest.java
similarity index 98%
rename from test/distributed/org/apache/cassandra/distributed/test/ReprepareTestOldBehaviour.java
rename to test/distributed/org/apache/cassandra/distributed/test/ReprepareOldBehaviourTest.java
index 9900febaea..2139485161 100644
--- a/test/distributed/org/apache/cassandra/distributed/test/ReprepareTestOldBehaviour.java
+++ b/test/distributed/org/apache/cassandra/distributed/test/ReprepareOldBehaviourTest.java
@@ -30,7 +30,7 @@ import static org.apache.cassandra.distributed.api.Feature.GOSSIP;
import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL;
import static org.apache.cassandra.distributed.api.Feature.NETWORK;
-public class ReprepareTestOldBehaviour extends ReprepareTestBase
+public class ReprepareOldBehaviourTest extends ReprepareTestBase
{
@Test
public void testReprepareMixedVersion() throws Throwable
diff --git a/test/long/org/apache/cassandra/cql3/CachingBench.java b/test/microbench/org/apache/cassandra/test/microbench/CachingBenchTest.java
similarity index 98%
rename from test/long/org/apache/cassandra/cql3/CachingBench.java
rename to test/microbench/org/apache/cassandra/test/microbench/CachingBenchTest.java
index f5f9ada28c..2859f586ca 100644
--- a/test/long/org/apache/cassandra/cql3/CachingBench.java
+++ b/test/microbench/org/apache/cassandra/test/microbench/CachingBenchTest.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.cassandra.cql3;
+package org.apache.cassandra.test.microbench;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,10 +34,13 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Assert;
+
import org.apache.cassandra.config.Config.CommitLogSync;
import org.apache.cassandra.config.Config.DiskAccessMode;
import org.apache.cassandra.cache.ChunkCache;
import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.rows.Row;
@@ -50,7 +53,7 @@ import org.apache.cassandra.utils.FBUtilities;
import static org.assertj.core.api.Assertions.assertThat;
-public class CachingBench extends CQLTester
+public class CachingBenchTest extends CQLTester
{
private static final String STRATEGY = "LeveledCompactionStrategy";
diff --git a/test/long/org/apache/cassandra/cql3/GcCompactionBench.java b/test/microbench/org/apache/cassandra/test/microbench/GcCompactionBenchTest.java
similarity index 98%
rename from test/long/org/apache/cassandra/cql3/GcCompactionBench.java
rename to test/microbench/org/apache/cassandra/test/microbench/GcCompactionBenchTest.java
index 009c9e2cb7..a1a614610a 100644
--- a/test/long/org/apache/cassandra/cql3/GcCompactionBench.java
+++ b/test/microbench/org/apache/cassandra/test/microbench/GcCompactionBenchTest.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.cassandra.cql3;
+package org.apache.cassandra.test.microbench;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,8 +34,11 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Assert;
+
import org.apache.cassandra.config.Config.CommitLogSync;
import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.rows.Row;
@@ -46,7 +49,7 @@ import org.apache.cassandra.io.sstable.format.SSTableReader;
import org.apache.cassandra.schema.CompactionParams.TombstoneOption;
import org.apache.cassandra.utils.FBUtilities;
-public class GcCompactionBench extends CQLTester
+public class GcCompactionBenchTest extends CQLTester
{
private static final String SIZE_TIERED_STRATEGY = "SizeTieredCompactionStrategy', 'min_sstable_size' : '0";
private static final String LEVELED_STRATEGY = "LeveledCompactionStrategy', 'sstable_size_in_mb' : '16";
diff --git a/test/unit/org/apache/cassandra/cql3/BatchTests.java b/test/unit/org/apache/cassandra/cql3/BatchTest.java
similarity index 99%
rename from test/unit/org/apache/cassandra/cql3/BatchTests.java
rename to test/unit/org/apache/cassandra/cql3/BatchTest.java
index 260db4eeed..28b0d5cbf7 100644
--- a/test/unit/org/apache/cassandra/cql3/BatchTests.java
+++ b/test/unit/org/apache/cassandra/cql3/BatchTest.java
@@ -30,7 +30,7 @@ import org.junit.Test;
import java.io.IOException;
-public class BatchTests extends CQLTester
+public class BatchTest extends CQLTester
{
private static EmbeddedCassandraService cassandra;
diff --git a/test/unit/org/apache/cassandra/cql3/KeywordTestSplit1.java b/test/unit/org/apache/cassandra/cql3/KeywordSplit1Test.java
similarity index 92%
rename from test/unit/org/apache/cassandra/cql3/KeywordTestSplit1.java
rename to test/unit/org/apache/cassandra/cql3/KeywordSplit1Test.java
index 802285afa8..6d51b34cf5 100644
--- a/test/unit/org/apache/cassandra/cql3/KeywordTestSplit1.java
+++ b/test/unit/org/apache/cassandra/cql3/KeywordSplit1Test.java
@@ -28,7 +28,7 @@ import org.junit.runners.Parameterized;
* KeywordTestSplitN to prevent CI timing out. If timeouts reappear split it further
*/
@RunWith(Parameterized.class)
-public class KeywordTestSplit1 extends KeywordTestBase
+public class KeywordSplit1Test extends KeywordTestBase
{
static int SPLIT = 1;
static int TOTAL_SPLITS = 2;
@@ -38,7 +38,7 @@ public class KeywordTestSplit1 extends KeywordTestBase
return KeywordTestBase.getKeywordsForSplit(SPLIT, TOTAL_SPLITS);
}
- public KeywordTestSplit1(String keyword, boolean isReserved)
+ public KeywordSplit1Test(String keyword, boolean isReserved)
{
super(keyword, isReserved);
}
diff --git a/test/unit/org/apache/cassandra/cql3/KeywordTestSplit2.java b/test/unit/org/apache/cassandra/cql3/KeywordSplit2Test.java
similarity index 92%
rename from test/unit/org/apache/cassandra/cql3/KeywordTestSplit2.java
rename to test/unit/org/apache/cassandra/cql3/KeywordSplit2Test.java
index 2da989a5c2..f400d4e8a6 100644
--- a/test/unit/org/apache/cassandra/cql3/KeywordTestSplit2.java
+++ b/test/unit/org/apache/cassandra/cql3/KeywordSplit2Test.java
@@ -28,7 +28,7 @@ import org.junit.runners.Parameterized;
* KeywordTestSplitN to prevent CI timing out. If timeouts reappear split it further
*/
@RunWith(Parameterized.class)
-public class KeywordTestSplit2 extends KeywordTestBase
+public class KeywordSplit2Test extends KeywordTestBase
{
static int SPLIT = 2;
static int TOTAL_SPLITS = 2;
@@ -38,7 +38,7 @@ public class KeywordTestSplit2 extends KeywordTestBase
return KeywordTestBase.getKeywordsForSplit(SPLIT, TOTAL_SPLITS);
}
- public KeywordTestSplit2(String keyword, boolean isReserved)
+ public KeywordSplit2Test(String keyword, boolean isReserved)
{
super(keyword, isReserved);
}
diff --git a/test/unit/org/apache/cassandra/cql3/KeywordTestBase.java b/test/unit/org/apache/cassandra/cql3/KeywordTestBase.java
index 48512d0751..0b8d2d59d9 100644
--- a/test/unit/org/apache/cassandra/cql3/KeywordTestBase.java
+++ b/test/unit/org/apache/cassandra/cql3/KeywordTestBase.java
@@ -35,7 +35,7 @@ import org.apache.cassandra.exceptions.SyntaxException;
* This class tests all keywords which took a long time. Hence it was split into multiple
* KeywordTestSplitN to prevent CI timing out. If timeouts reappear split it further
*/
-public class KeywordTestBase extends CQLTester
+public abstract class KeywordTestBase extends CQLTester
{
public static List