Move NamingConventionsCheck into buildSrc
This will let things that don't depend on :test:framework like the client use it. Also skip initializing the classes we check because we don't care about their initialization behavior because we're not executing them. This makes the naming conventions check pretty close to instant from a "human eye" perspective.
This commit is contained in:
parent
f132a8f1c8
commit
d0e4485d42
|
@ -160,6 +160,7 @@ subprojects {
|
||||||
them as external dependencies so the build plugin that we use can be used
|
them as external dependencies so the build plugin that we use can be used
|
||||||
to build elasticsearch plugins outside of the elasticsearch source tree. */
|
to build elasticsearch plugins outside of the elasticsearch source tree. */
|
||||||
ext.projectSubstitutions = [
|
ext.projectSubstitutions = [
|
||||||
|
"org.elasticsearch.gradle:build-tools:${version}": ':build-tools',
|
||||||
"org.elasticsearch:rest-api-spec:${version}": ':rest-api-spec',
|
"org.elasticsearch:rest-api-spec:${version}": ':rest-api-spec',
|
||||||
"org.elasticsearch:elasticsearch:${version}": ':core',
|
"org.elasticsearch:elasticsearch:${version}": ':core',
|
||||||
"org.elasticsearch.test:framework:${version}": ':test:framework',
|
"org.elasticsearch.test:framework:${version}": ':test:framework',
|
||||||
|
|
|
@ -103,6 +103,7 @@ if (project == rootProject) {
|
||||||
url "https://oss.sonatype.org/content/repositories/snapshots/"
|
url "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
test.exclude 'org/elasticsearch/test/NamingConventionsCheckBadClasses*'
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
@ -122,8 +123,8 @@ if (project != rootProject) {
|
||||||
// build-tools is not ready for primetime with these...
|
// build-tools is not ready for primetime with these...
|
||||||
dependencyLicenses.enabled = false
|
dependencyLicenses.enabled = false
|
||||||
forbiddenApisMain.enabled = false
|
forbiddenApisMain.enabled = false
|
||||||
|
forbiddenApisTest.enabled = false
|
||||||
jarHell.enabled = false
|
jarHell.enabled = false
|
||||||
loggerUsageCheck.enabled = false
|
|
||||||
thirdPartyAudit.enabled = false
|
thirdPartyAudit.enabled = false
|
||||||
|
|
||||||
// test for elasticsearch.build tries to run with ES...
|
// test for elasticsearch.build tries to run with ES...
|
||||||
|
@ -137,4 +138,9 @@ if (project != rootProject) {
|
||||||
// the file that actually defines nocommit
|
// the file that actually defines nocommit
|
||||||
exclude '**/ForbiddenPatternsTask.groovy'
|
exclude '**/ForbiddenPatternsTask.groovy'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namingConventions {
|
||||||
|
testClass = 'org.elasticsearch.test.NamingConventionsCheckBadClasses$UnitTestCase'
|
||||||
|
integTestClass = 'org.elasticsearch.test.NamingConventionsCheckBadClasses$IntegTestCase'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.gradle.precommit
|
||||||
|
|
||||||
import org.elasticsearch.gradle.LoggedExec
|
import org.elasticsearch.gradle.LoggedExec
|
||||||
import org.elasticsearch.gradle.VersionProperties
|
import org.elasticsearch.gradle.VersionProperties
|
||||||
|
import org.gradle.api.artifacts.Dependency
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.tasks.Input
|
import org.gradle.api.tasks.Input
|
||||||
import org.gradle.api.tasks.InputFiles
|
import org.gradle.api.tasks.InputFiles
|
||||||
|
@ -57,8 +58,27 @@ public class NamingConventionsTask extends LoggedExec {
|
||||||
@Input
|
@Input
|
||||||
boolean skipIntegTestInDisguise = false
|
boolean skipIntegTestInDisguise = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass for all tests.
|
||||||
|
*/
|
||||||
|
@Input
|
||||||
|
String testClass = 'org.apache.lucene.util.LuceneTestCase'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass for all integration tests.
|
||||||
|
*/
|
||||||
|
@Input
|
||||||
|
String integTestClass = 'org.elasticsearch.test.ESIntegTestCase'
|
||||||
|
|
||||||
public NamingConventionsTask() {
|
public NamingConventionsTask() {
|
||||||
dependsOn(classpath)
|
// Extra classpath contains the actual test
|
||||||
|
project.configurations.create('namingConventions')
|
||||||
|
Dependency buildToolsDep = project.dependencies.add('namingConventions',
|
||||||
|
"org.elasticsearch.gradle:build-tools:${VersionProperties.elasticsearch}")
|
||||||
|
buildToolsDep.transitive = false // We don't need gradle in the classpath. It conflicts.
|
||||||
|
FileCollection extraClasspath = project.configurations.namingConventions
|
||||||
|
dependsOn(extraClasspath)
|
||||||
|
|
||||||
description = "Runs NamingConventionsCheck on ${classpath}"
|
description = "Runs NamingConventionsCheck on ${classpath}"
|
||||||
executable = new File(project.javaHome, 'bin/java')
|
executable = new File(project.javaHome, 'bin/java')
|
||||||
onlyIf { project.sourceSets.test.output.classesDir.exists() }
|
onlyIf { project.sourceSets.test.output.classesDir.exists() }
|
||||||
|
@ -69,7 +89,8 @@ public class NamingConventionsTask extends LoggedExec {
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
doFirst {
|
doFirst {
|
||||||
args('-Djna.nosys=true')
|
args('-Djna.nosys=true')
|
||||||
args('-cp', classpath.asPath, 'org.elasticsearch.test.NamingConventionsCheck')
|
args('-cp', (classpath + extraClasspath).asPath, 'org.elasticsearch.test.NamingConventionsCheck')
|
||||||
|
args(testClass, integTestClass)
|
||||||
if (skipIntegTestInDisguise) {
|
if (skipIntegTestInDisguise) {
|
||||||
args('--skip-integ-tests-in-disguise')
|
args('--skip-integ-tests-in-disguise')
|
||||||
}
|
}
|
||||||
|
@ -79,7 +100,7 @@ public class NamingConventionsTask extends LoggedExec {
|
||||||
* process of ignoring them lets us validate that they were found so this ignore parameter acts
|
* process of ignoring them lets us validate that they were found so this ignore parameter acts
|
||||||
* as the test for the NamingConventionsCheck.
|
* as the test for the NamingConventionsCheck.
|
||||||
*/
|
*/
|
||||||
if (':test:framework'.equals(project.path)) {
|
if (':build-tools'.equals(project.path)) {
|
||||||
args('--self-test')
|
args('--self-test')
|
||||||
}
|
}
|
||||||
args('--', project.sourceSets.test.output.classesDir.absolutePath)
|
args('--', project.sourceSets.test.output.classesDir.absolutePath)
|
||||||
|
|
|
@ -34,7 +34,6 @@ class PrecommitTasks {
|
||||||
configureForbiddenApis(project),
|
configureForbiddenApis(project),
|
||||||
configureCheckstyle(project),
|
configureCheckstyle(project),
|
||||||
configureNamingConventions(project),
|
configureNamingConventions(project),
|
||||||
configureLoggerUsage(project),
|
|
||||||
project.tasks.create('forbiddenPatterns', ForbiddenPatternsTask.class),
|
project.tasks.create('forbiddenPatterns', ForbiddenPatternsTask.class),
|
||||||
project.tasks.create('licenseHeaders', LicenseHeadersTask.class),
|
project.tasks.create('licenseHeaders', LicenseHeadersTask.class),
|
||||||
project.tasks.create('jarHell', JarHellTask.class),
|
project.tasks.create('jarHell', JarHellTask.class),
|
||||||
|
@ -49,6 +48,20 @@ class PrecommitTasks {
|
||||||
UpdateShasTask updateShas = project.tasks.create('updateShas', UpdateShasTask.class)
|
UpdateShasTask updateShas = project.tasks.create('updateShas', UpdateShasTask.class)
|
||||||
updateShas.parentTask = dependencyLicenses
|
updateShas.parentTask = dependencyLicenses
|
||||||
}
|
}
|
||||||
|
if (project.path != ':build-tools') {
|
||||||
|
/*
|
||||||
|
* Sadly, build-tools can't have logger-usage-check because that
|
||||||
|
* would create a circular project dependency between build-tools
|
||||||
|
* (which provides NamingConventionsCheck) and :test:logger-usage
|
||||||
|
* which provides the logger usage check. Since the build tools
|
||||||
|
* don't use the logger usage check because they don't have any
|
||||||
|
* of Elaticsearch's loggers and :test:logger-usage actually does
|
||||||
|
* use the NamingConventionsCheck we break the circular dependency
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
precommitTasks.add(configureLoggerUsage(project))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Map<String, Object> precommitOptions = [
|
Map<String, Object> precommitOptions = [
|
||||||
name: 'precommit',
|
name: 'precommit',
|
||||||
|
|
|
@ -25,14 +25,11 @@ import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.FileVisitor;
|
import java.nio.file.FileVisitor;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
|
||||||
import org.elasticsearch.common.SuppressForbidden;
|
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that all tests in a directory are named according to our naming conventions. This is important because tests that do not follow
|
* Checks that all tests in a directory are named according to our naming conventions. This is important because tests that do not follow
|
||||||
* our conventions aren't run by gradle. This was once a glorious unit test but now that Elasticsearch is a multi-module project it must be
|
* our conventions aren't run by gradle. This was once a glorious unit test but now that Elasticsearch is a multi-module project it must be
|
||||||
|
@ -46,11 +43,13 @@ import org.elasticsearch.common.io.PathUtils;
|
||||||
* {@code --self-test} that is only run in the test:framework project.
|
* {@code --self-test} that is only run in the test:framework project.
|
||||||
*/
|
*/
|
||||||
public class NamingConventionsCheck {
|
public class NamingConventionsCheck {
|
||||||
public static void main(String[] args) throws IOException, ClassNotFoundException {
|
public static void main(String[] args) throws IOException {
|
||||||
NamingConventionsCheck check = new NamingConventionsCheck();
|
int i = 0;
|
||||||
|
NamingConventionsCheck check = new NamingConventionsCheck(
|
||||||
|
loadClassWithoutInitializing(args[i++]),
|
||||||
|
loadClassWithoutInitializing(args[i++]));
|
||||||
boolean skipIntegTestsInDisguise = false;
|
boolean skipIntegTestsInDisguise = false;
|
||||||
boolean selfTest = false;
|
boolean selfTest = false;
|
||||||
int i = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (args[i]) {
|
switch (args[i]) {
|
||||||
case "--skip-integ-tests-in-disguise":
|
case "--skip-integ-tests-in-disguise":
|
||||||
|
@ -69,7 +68,7 @@ public class NamingConventionsCheck {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
check.check(PathUtils.get(args[i]));
|
check.check(Paths.get(args[i]));
|
||||||
|
|
||||||
if (selfTest) {
|
if (selfTest) {
|
||||||
assertViolation("WrongName", check.missingSuffix);
|
assertViolation("WrongName", check.missingSuffix);
|
||||||
|
@ -82,14 +81,12 @@ public class NamingConventionsCheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we should have no violations
|
// Now we should have no violations
|
||||||
assertNoViolations("Not all subclasses of " + ESTestCase.class.getSimpleName()
|
assertNoViolations("Not all subclasses of " + check.testClass.getSimpleName()
|
||||||
+ " match the naming convention. Concrete classes must end with [Tests]", check.missingSuffix);
|
+ " match the naming convention. Concrete classes must end with [Tests]", check.missingSuffix);
|
||||||
assertNoViolations("Classes ending with [Tests] are abstract or interfaces", check.notRunnable);
|
assertNoViolations("Classes ending with [Tests] are abstract or interfaces", check.notRunnable);
|
||||||
assertNoViolations("Found inner classes that are tests, which are excluded from the test runner", check.innerClasses);
|
assertNoViolations("Found inner classes that are tests, which are excluded from the test runner", check.innerClasses);
|
||||||
String classesToSubclass = String.join(",", ESTestCase.class.getSimpleName(), ESTestCase.class.getSimpleName(),
|
assertNoViolations("Pure Unit-Test found must subclass [" + check.testClass.getSimpleName() + "]", check.pureUnitTest);
|
||||||
ESTokenStreamTestCase.class.getSimpleName(), LuceneTestCase.class.getSimpleName());
|
assertNoViolations("Classes ending with [Tests] must subclass [" + check.testClass.getSimpleName() + "]", check.notImplementing);
|
||||||
assertNoViolations("Pure Unit-Test found must subclass one of [" + classesToSubclass + "]", check.pureUnitTest);
|
|
||||||
assertNoViolations("Classes ending with [Tests] must subclass [" + classesToSubclass + "]", check.notImplementing);
|
|
||||||
if (!skipIntegTestsInDisguise) {
|
if (!skipIntegTestsInDisguise) {
|
||||||
assertNoViolations("Subclasses of ESIntegTestCase should end with IT as they are integration tests",
|
assertNoViolations("Subclasses of ESIntegTestCase should end with IT as they are integration tests",
|
||||||
check.integTestsInDisguise);
|
check.integTestsInDisguise);
|
||||||
|
@ -103,6 +100,14 @@ public class NamingConventionsCheck {
|
||||||
private final Set<Class<?>> notRunnable = new HashSet<>();
|
private final Set<Class<?>> notRunnable = new HashSet<>();
|
||||||
private final Set<Class<?>> innerClasses = new HashSet<>();
|
private final Set<Class<?>> innerClasses = new HashSet<>();
|
||||||
|
|
||||||
|
private final Class<?> testClass;
|
||||||
|
private final Class<?> integTestClass;
|
||||||
|
|
||||||
|
public NamingConventionsCheck(Class<?> testClass, Class<?> integTestClass) {
|
||||||
|
this.testClass = testClass;
|
||||||
|
this.integTestClass = integTestClass;
|
||||||
|
}
|
||||||
|
|
||||||
public void check(Path rootPath) throws IOException {
|
public void check(Path rootPath) throws IOException {
|
||||||
Files.walkFileTree(rootPath, new FileVisitor<Path>() {
|
Files.walkFileTree(rootPath, new FileVisitor<Path>() {
|
||||||
/**
|
/**
|
||||||
|
@ -136,9 +141,9 @@ public class NamingConventionsCheck {
|
||||||
String filename = file.getFileName().toString();
|
String filename = file.getFileName().toString();
|
||||||
if (filename.endsWith(".class")) {
|
if (filename.endsWith(".class")) {
|
||||||
String className = filename.substring(0, filename.length() - ".class".length());
|
String className = filename.substring(0, filename.length() - ".class".length());
|
||||||
Class<?> clazz = loadClass(className);
|
Class<?> clazz = loadClassWithoutInitializing(packageName + className);
|
||||||
if (clazz.getName().endsWith("Tests")) {
|
if (clazz.getName().endsWith("Tests")) {
|
||||||
if (ESIntegTestCase.class.isAssignableFrom(clazz)) {
|
if (integTestClass.isAssignableFrom(clazz)) {
|
||||||
integTestsInDisguise.add(clazz);
|
integTestsInDisguise.add(clazz);
|
||||||
}
|
}
|
||||||
if (Modifier.isAbstract(clazz.getModifiers()) || Modifier.isInterface(clazz.getModifiers())) {
|
if (Modifier.isAbstract(clazz.getModifiers()) || Modifier.isInterface(clazz.getModifiers())) {
|
||||||
|
@ -164,15 +169,7 @@ public class NamingConventionsCheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTestCase(Class<?> clazz) {
|
private boolean isTestCase(Class<?> clazz) {
|
||||||
return LuceneTestCase.class.isAssignableFrom(clazz);
|
return testClass.isAssignableFrom(clazz);
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> loadClass(String className) {
|
|
||||||
try {
|
|
||||||
return Thread.currentThread().getContextClassLoader().loadClass(packageName + className);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -186,7 +183,6 @@ public class NamingConventionsCheck {
|
||||||
* Fail the process if there are any violations in the set. Named to look like a junit assertion even though it isn't because it is
|
* Fail the process if there are any violations in the set. Named to look like a junit assertion even though it isn't because it is
|
||||||
* similar enough.
|
* similar enough.
|
||||||
*/
|
*/
|
||||||
@SuppressForbidden(reason = "System.err/System.exit")
|
|
||||||
private static void assertNoViolations(String message, Set<Class<?>> set) {
|
private static void assertNoViolations(String message, Set<Class<?>> set) {
|
||||||
if (false == set.isEmpty()) {
|
if (false == set.isEmpty()) {
|
||||||
System.err.println(message + ":");
|
System.err.println(message + ":");
|
||||||
|
@ -201,10 +197,9 @@ public class NamingConventionsCheck {
|
||||||
* Fail the process if we didn't detect a particular violation. Named to look like a junit assertion even though it isn't because it is
|
* Fail the process if we didn't detect a particular violation. Named to look like a junit assertion even though it isn't because it is
|
||||||
* similar enough.
|
* similar enough.
|
||||||
*/
|
*/
|
||||||
@SuppressForbidden(reason = "System.err/System.exit")
|
private static void assertViolation(String className, Set<Class<?>> set) {
|
||||||
private static void assertViolation(String className, Set<Class<?>> set) throws ClassNotFoundException {
|
className = "org.elasticsearch.test.NamingConventionsCheckBadClasses$" + className;
|
||||||
className = "org.elasticsearch.test.test.NamingConventionsCheckBadClasses$" + className;
|
if (false == set.remove(loadClassWithoutInitializing(className))) {
|
||||||
if (false == set.remove(Class.forName(className))) {
|
|
||||||
System.err.println("Error in NamingConventionsCheck! Expected [" + className + "] to be a violation but wasn't.");
|
System.err.println("Error in NamingConventionsCheck! Expected [" + className + "] to be a violation but wasn't.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
@ -213,9 +208,20 @@ public class NamingConventionsCheck {
|
||||||
/**
|
/**
|
||||||
* Fail the process with the provided message.
|
* Fail the process with the provided message.
|
||||||
*/
|
*/
|
||||||
@SuppressForbidden(reason = "System.err/System.exit")
|
|
||||||
private static void fail(String reason) {
|
private static void fail(String reason) {
|
||||||
System.err.println(reason);
|
System.err.println(reason);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Class<?> loadClassWithoutInitializing(String name) {
|
||||||
|
try {
|
||||||
|
return Class.forName(name,
|
||||||
|
// Don't initialize the class to save time. Not needed for this test and this doesn't share a VM with any other tests.
|
||||||
|
false,
|
||||||
|
// Use our classloader rather than the bootstrap class loader.
|
||||||
|
NamingConventionsCheck.class.getClassLoader());
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,9 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.test.test;
|
package org.elasticsearch.test;
|
||||||
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
@ -30,21 +28,35 @@ public class NamingConventionsCheckBadClasses {
|
||||||
public static final class NotImplementingTests {
|
public static final class NotImplementingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class WrongName extends ESTestCase {
|
public static final class WrongName extends UnitTestCase {
|
||||||
|
/*
|
||||||
|
* Dummy test so the tests pass. We do this *and* skip the tests so anyone who jumps back to a branch without these tests can still
|
||||||
|
* compile without a failure. That is because clean doesn't actually clean these....
|
||||||
|
*/
|
||||||
|
public void testDummy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class DummyAbstractTests extends ESTestCase {
|
public static abstract class DummyAbstractTests extends UnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DummyInterfaceTests {
|
public interface DummyInterfaceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class InnerTests extends ESTestCase {
|
public static final class InnerTests extends UnitTestCase {
|
||||||
|
public void testDummy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class WrongNameTheSecond extends ESTestCase {
|
public static final class WrongNameTheSecond extends UnitTestCase {
|
||||||
|
public void testDummy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class PlainUnit extends TestCase {
|
public static final class PlainUnit extends TestCase {
|
||||||
|
public void testDummy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class UnitTestCase extends TestCase {
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class IntegTestCase extends UnitTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue