diff --git a/CHANGES.txt b/CHANGES.txt
index 7ecf0e320b..20afe6819e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -13,6 +13,7 @@ Merged from 4.0:
* Restore internode custom tracing on 4.0's new messaging system (CASSANDRA-17981)
Merged from 3.11:
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 74751c9b1d..6475e57433 100644
--- a/build.xml
+++ b/build.xml
@@ -1439,12 +1439,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/anttasks/EchoEclipseProjectLibs.java b/test/anttasks/org/apache/cassandra/anttasks/EchoEclipseProjectLibs.java
similarity index 100%
rename from test/anttasks/EchoEclipseProjectLibs.java
rename to test/anttasks/org/apache/cassandra/anttasks/EchoEclipseProjectLibs.java
diff --git a/test/anttasks/KeepBriefBrief.java b/test/anttasks/org/apache/cassandra/anttasks/KeepBriefBrief.java
similarity index 100%
rename from test/anttasks/KeepBriefBrief.java
rename to test/anttasks/org/apache/cassandra/anttasks/KeepBriefBrief.java
diff --git a/test/anttasks/TestHelper.java b/test/anttasks/org/apache/cassandra/anttasks/TestHelper.java
similarity index 100%
rename from test/anttasks/TestHelper.java
rename to test/anttasks/org/apache/cassandra/anttasks/TestHelper.java
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/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternode.java b/test/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternodeTest.java
similarity index 98%
rename from test/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternode.java
rename to test/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternodeTest.java
index e322585a7b..229dd96277 100644
--- a/test/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternode.java
+++ b/test/distributed/org/apache/cassandra/distributed/test/VirtualTableFromInternodeTest.java
@@ -37,7 +37,7 @@ import org.apache.cassandra.locator.InetAddressAndPort;
import static org.apache.cassandra.distributed.util.QueryResultUtil.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
-public class VirtualTableFromInternode extends TestBaseImpl
+public class VirtualTableFromInternodeTest extends TestBaseImpl
{
private static Cluster CLUSTER;
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 11d90b7bfb..c589ca5d7e 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;
@@ -52,7 +55,7 @@ import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
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 c6f1bb6cb1..6af9811593 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;
@@ -49,7 +52,7 @@ import org.apache.cassandra.utils.FBUtilities;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
-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/auth/CassandraAuthorizerTruncatingTests.java b/test/unit/org/apache/cassandra/auth/CassandraAuthorizerTruncatingTest.java
similarity index 98%
rename from test/unit/org/apache/cassandra/auth/CassandraAuthorizerTruncatingTests.java
rename to test/unit/org/apache/cassandra/auth/CassandraAuthorizerTruncatingTest.java
index 3605239197..3806a232af 100644
--- a/test/unit/org/apache/cassandra/auth/CassandraAuthorizerTruncatingTests.java
+++ b/test/unit/org/apache/cassandra/auth/CassandraAuthorizerTruncatingTest.java
@@ -48,7 +48,7 @@ import static org.junit.Assert.assertTrue;
/**
* For Authorizer based tests where we need to fully truncate the roles, members, and permissions between tests
*/
-public class CassandraAuthorizerTruncatingTests extends CQLTester
+public class CassandraAuthorizerTruncatingTest extends CQLTester
{
@BeforeClass
public static void setupClass()
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 f7629e204a..330271e982 100644
--- a/test/unit/org/apache/cassandra/cql3/BatchTests.java
+++ b/test/unit/org/apache/cassandra/cql3/BatchTest.java
@@ -33,7 +33,7 @@ import org.junit.Test;
import java.io.IOException;
-public class BatchTests
+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 9e871b1097..c301650dee 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 edfafec920..7be651a626 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;
@@ -37,8 +37,8 @@ public class KeywordTestSplit2 extends KeywordTestBase
public static Collection