You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2018/01/29 14:11:34 UTC
[geode] branch develop updated: GEODE-4139: Add javac processor to
ensure correct RunWith options are enabled for parameterized tests (#1318)
This is an automated email from the ASF dual-hosted git repository.
jensdeppe pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 819599b GEODE-4139: Add javac processor to ensure correct RunWith options are enabled for parameterized tests (#1318)
819599b is described below
commit 819599ba26944353ed72ac312f3b11e72e2ce425
Author: Jens Deppe <jd...@pivotal.io>
AuthorDate: Mon Jan 29 06:11:31 2018 -0800
GEODE-4139: Add javac processor to ensure correct RunWith options are enabled for parameterized tests (#1318)
- This ensures that if @RunWith(Parameterized.class) is specified for a test class, then
@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
is also specified for that class. Without that, the tests are not correctly run as the
presence of @Category breaks the parameterization.
---
buildSrc/build.gradle | 4 +-
.../geode/gradle/TestPropertiesWriter.groovy | 2 -
.../javac/EnsureCorrectRunsWithProcessor.java | 135 +++++++++++++++++++++
.../services/javax.annotation.processing.Processor | 1 +
.../org/apache/geode/javac/SimpleClassFile.java | 42 +++++++
.../org/apache/geode/javac/SimpleFileManager.java | 46 +++++++
.../org/apache/geode/javac/SimpleSourceFile.java | 35 ++++++
.../geode/javac/TestAnnotationProcessor.java | 51 ++++++++
.../java/org/apache/geode/javac/TestCompiler.java | 51 ++++++++
gradle/test.gradle | 22 +++-
10 files changed, 385 insertions(+), 4 deletions(-)
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index d7ff581..21cf963 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -21,5 +21,7 @@ repositories {
}
dependencies {
- compile group: 'org.apache.mina', name: 'mina-core', version: '2.0.14'
+ compile group: 'org.apache.geode', name: 'geode-junit', version: '1.3.0'
+ compile group: 'junit', name: 'junit', version: '4.12'
+ compile files("${System.getProperty('java.home')}/../lib/tools.jar")
}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/org/apache/geode/gradle/TestPropertiesWriter.groovy b/buildSrc/src/main/groovy/org/apache/geode/gradle/TestPropertiesWriter.groovy
index 58e61f7..8cd0d9b 100644
--- a/buildSrc/src/main/groovy/org/apache/geode/gradle/TestPropertiesWriter.groovy
+++ b/buildSrc/src/main/groovy/org/apache/geode/gradle/TestPropertiesWriter.groovy
@@ -18,8 +18,6 @@
package org.apache.geode.gradle;
-import org.apache.mina.util.AvailablePortFinder;
-
public class TestPropertiesWriter {
public static void writeTestProperties(File parent, String name) {
Properties props = new Properties();
diff --git a/buildSrc/src/main/java/org/apache/geode/javac/EnsureCorrectRunsWithProcessor.java b/buildSrc/src/main/java/org/apache/geode/javac/EnsureCorrectRunsWithProcessor.java
new file mode 100644
index 0000000..e4afa4c
--- /dev/null
+++ b/buildSrc/src/main/java/org/apache/geode/javac/EnsureCorrectRunsWithProcessor.java
@@ -0,0 +1,135 @@
+/*
+ * 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.geode.javac;
+
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.MirroredTypeException;
+import javax.tools.Diagnostic;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
+
+@SupportedAnnotationTypes("org.junit.runner.RunWith")
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
+public class EnsureCorrectRunsWithProcessor extends AbstractProcessor {
+
+ private static final String RUNWITH = RunWith.class.getCanonicalName();
+
+ private Messager messager;
+
+ @Override
+ public synchronized void init(ProcessingEnvironment env) {
+ super.init(env);
+ messager = env.getMessager();
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ boolean hasErrors = false;
+
+ for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(RunWith.class)) {
+ if (annotatedElement.getKind() != ElementKind.CLASS) {
+ continue;
+ }
+
+ TypeElement typeElement = (TypeElement) annotatedElement;
+
+ boolean hasUseParameterizedRunnerFactory = false;
+ boolean hasRunWithParameterized = false;
+
+ for (AnnotationMirror am : typeElement.getAnnotationMirrors()) {
+ String clazz = am.getAnnotationType().toString();
+ if (clazz.equals(RunWith.class.getCanonicalName())) {
+ hasRunWithParameterized = isRunWithParameterized(typeElement);
+ }
+
+ if (clazz.equals(Parameterized.UseParametersRunnerFactory.class.getCanonicalName())) {
+ hasUseParameterizedRunnerFactory = isUseParameterizedRunnerFactory(typeElement);
+ }
+ }
+
+ if (hasRunWithParameterized && !hasUseParameterizedRunnerFactory) {
+ error(typeElement, "class is annotated with @RunWith(Parameterized.class) but is missing the annotation @Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)");
+ hasErrors = true;
+ }
+ }
+
+ return hasErrors;
+ }
+
+ private boolean isRunWithParameterized(TypeElement typeElement) {
+ RunWith runWith = typeElement.getAnnotation(RunWith.class);
+
+ String runWithValue;
+ try {
+ runWithValue = runWith.value().getSimpleName();
+ } catch (MirroredTypeException mex) {
+ DeclaredType classTypeMirror = (DeclaredType) mex.getTypeMirror();
+ TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
+ runWithValue = classTypeElement.getSimpleName().toString();
+ }
+
+ if (runWithValue == null) {
+ return false;
+ }
+
+ return runWithValue.equals(Parameterized.class.getCanonicalName())
+ || runWithValue.equals(Parameterized.class.getSimpleName());
+ }
+
+ private boolean isUseParameterizedRunnerFactory(TypeElement typeElement) {
+ Parameterized.UseParametersRunnerFactory
+ runnerFactory = typeElement.getAnnotation(Parameterized.UseParametersRunnerFactory.class);
+
+ String runnerFactoryValue;
+ try {
+ runnerFactoryValue = runnerFactory.value().getSimpleName();
+ } catch (MirroredTypeException mex) {
+ DeclaredType classTypeMirror = (DeclaredType) mex.getTypeMirror();
+ TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
+ runnerFactoryValue = classTypeElement.getSimpleName().toString();
+ }
+
+ if (runnerFactoryValue == null) {
+ return false;
+ }
+
+ return runnerFactoryValue.equals(CategoryWithParameterizedRunnerFactory.class.getCanonicalName())
+ || runnerFactoryValue.equals(CategoryWithParameterizedRunnerFactory.class.getSimpleName());
+ }
+
+ private void error(Element e, String msg, Object... args) {
+ messager.printMessage(
+ Diagnostic.Kind.ERROR,
+ String.format(msg, args),
+ e);
+ }
+}
diff --git a/buildSrc/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/buildSrc/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..f1390a0
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.apache.geode.javac.EnsureCorrectRunsWithProcessor
\ No newline at end of file
diff --git a/buildSrc/src/test/java/org/apache/geode/javac/SimpleClassFile.java b/buildSrc/src/test/java/org/apache/geode/javac/SimpleClassFile.java
new file mode 100644
index 0000000..63ca323
--- /dev/null
+++ b/buildSrc/src/test/java/org/apache/geode/javac/SimpleClassFile.java
@@ -0,0 +1,42 @@
+/*
+ * 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.geode.javac;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+
+import javax.tools.SimpleJavaFileObject;
+
+public class SimpleClassFile extends SimpleJavaFileObject {
+
+ private ByteArrayOutputStream out;
+
+ public SimpleClassFile(URI uri) {
+ super(uri, Kind.CLASS);
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return out = new ByteArrayOutputStream();
+ }
+
+ public byte[] getCompiledBinaries() {
+ return out.toByteArray();
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/apache/geode/javac/SimpleFileManager.java b/buildSrc/src/test/java/org/apache/geode/javac/SimpleFileManager.java
new file mode 100644
index 0000000..e65f287
--- /dev/null
+++ b/buildSrc/src/test/java/org/apache/geode/javac/SimpleFileManager.java
@@ -0,0 +1,46 @@
+/*
+ * 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.geode.javac;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+
+public class SimpleFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
+
+ private List<SimpleClassFile> compiled = new ArrayList<>();
+
+ public SimpleFileManager(StandardJavaFileManager fileManager) {
+ super(fileManager);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className,
+ JavaFileObject.Kind kind, FileObject sibling) {
+ SimpleClassFile result = new SimpleClassFile(URI.create("string://" + className));
+ compiled.add(result);
+ return result;
+ }
+
+ public List<SimpleClassFile> getCompiled() {
+ return compiled;
+ }
+}
diff --git a/buildSrc/src/test/java/org/apache/geode/javac/SimpleSourceFile.java b/buildSrc/src/test/java/org/apache/geode/javac/SimpleSourceFile.java
new file mode 100644
index 0000000..5a4090f
--- /dev/null
+++ b/buildSrc/src/test/java/org/apache/geode/javac/SimpleSourceFile.java
@@ -0,0 +1,35 @@
+/*
+ * 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.geode.javac;
+
+import java.net.URI;
+
+import javax.tools.SimpleJavaFileObject;
+
+public class SimpleSourceFile extends SimpleJavaFileObject {
+ private String content;
+
+ public SimpleSourceFile(String qualifiedClassName, String testSource) {
+ super(URI.create(String.format("file://%s%s", qualifiedClassName.replaceAll("\\.", "/"),
+ Kind.SOURCE.extension)), Kind.SOURCE);
+ content = testSource;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return content;
+ }
+}
diff --git a/buildSrc/src/test/java/org/apache/geode/javac/TestAnnotationProcessor.java b/buildSrc/src/test/java/org/apache/geode/javac/TestAnnotationProcessor.java
new file mode 100644
index 0000000..0b88d05
--- /dev/null
+++ b/buildSrc/src/test/java/org/apache/geode/javac/TestAnnotationProcessor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.geode.javac;
+
+import org.junit.Test;
+import sun.tools.java.CompilerError;
+
+public class TestAnnotationProcessor {
+ private static final String VALID_CLASS_TEMPLATE = "package org.apache.geode;\n"
+ + "import org.junit.runner.RunWith;\n" + "import org.junit.runners.Parameterized;\n"
+ + "import org.junit.experimental.categories.Category;\n"
+ + "import org.apache.geode.test.junit.categories.UnitTest;\n"
+ + "import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;\n"
+ + "@Category(UnitTest.class)\n"
+ + "@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)\n"
+ + "@RunWith(Parameterized.class)\n" + "public class Test {\n" + "}\n";
+
+ private static final String INVALID_CLASS_TEMPLATE = "package org.apache.geode;\n"
+ + "import org.junit.runner.RunWith;\n" + "import org.junit.runners.Parameterized;\n"
+ + "import org.junit.experimental.categories.Category;\n"
+ + "import org.apache.geode.test.junit.categories.UnitTest;\n"
+ + "@Category(UnitTest.class)\n"
+ + "@RunWith(Parameterized.class)\n" + "public class Test {\n" + "}\n";
+
+ private TestCompiler compiler = new TestCompiler();
+
+ @Test
+ public void checkValidAnnotations() {
+ String qualifiedClassName = "org.apache.geode.Test";
+ compiler.compile(qualifiedClassName, VALID_CLASS_TEMPLATE);
+ }
+
+ @Test (expected = CompilerError.class)
+ public void checkInvalidAnnotations() {
+ String qualifiedClassName = "org.apache.geode.Test";
+ compiler.compile(qualifiedClassName, INVALID_CLASS_TEMPLATE);
+ }
+}
diff --git a/buildSrc/src/test/java/org/apache/geode/javac/TestCompiler.java b/buildSrc/src/test/java/org/apache/geode/javac/TestCompiler.java
new file mode 100644
index 0000000..2b8d78a
--- /dev/null
+++ b/buildSrc/src/test/java/org/apache/geode/javac/TestCompiler.java
@@ -0,0 +1,51 @@
+/*
+ * 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.geode.javac;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
+import sun.tools.java.CompilerError;
+
+public class TestCompiler {
+ public byte[] compile(String qualifiedClassName, String testSource) {
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ SimpleFileManager fileManager =
+ new SimpleFileManager(compiler.getStandardFileManager(null, null, null));
+
+ List<SimpleSourceFile> compilationUnits =
+ Collections.singletonList(new SimpleSourceFile(qualifiedClassName, testSource));
+
+ List<String> arguments = new ArrayList<>();
+ arguments.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path"),
+ "-processor", EnsureCorrectRunsWithProcessor.class.getName()));
+
+ JavaCompiler.CompilationTask task =
+ compiler.getTask(null, fileManager, null, arguments, null, compilationUnits);
+
+ if (!task.call()) {
+ throw new CompilerError("Compilation errors");
+ }
+
+ return fileManager.getCompiled().iterator().next().getCompiledBinaries();
+ }
+}
diff --git a/gradle/test.gradle b/gradle/test.gradle
index 762a2aa..95f3d89 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -56,7 +56,27 @@ subprojects {
testRuntime 'cglib:cglib:' + project.'cglib.version'
}
-
+
+ configurations {
+ apt
+ }
+
+ dependencies {
+ apt files("${rootProject.projectDir}/buildSrc/build/libs/buildSrc.jar")
+ apt(group: 'junit', name: 'junit', version: project.'junit.version') {
+ transitive = false
+ }
+ // Because EnsureCorrectRunsWithProcessor needs access to
+ // CategoryWithParameterizedRunnerFactory. The specific version of geode-junit is not important.
+ apt(group: 'org.apache.geode', name: 'geode-junit', version: '1.3.0') {
+ transitive = false
+ }
+ }
+
+ compileTestJava {
+ options.annotationProcessorPath = files(configurations['apt'])
+ }
+
//This target does not run any tests. Rather, it validates that there are no
//tests that are missing a category annotation
task checkMissedTests(type: Test) {
--
To stop receiving notification emails like this one, please contact
jensdeppe@apache.org.