detect junit 5 based on custom classloader with engines (IDEA-168685)

This commit is contained in:
Anna.Kozlova
2017-08-10 14:27:35 +02:00
parent c230f92428
commit 5b42e85835
9 changed files with 98 additions and 108 deletions
@@ -123,12 +123,17 @@ public abstract class JavaTestFrameworkRunnableState<T extends
return module != null;
}
protected boolean isIdBasedTestTree() {
return false;
}
@NotNull
@Override
public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
final RunnerSettings runnerSettings = getRunnerSettings();
final SMTRunnerConsoleProperties testConsoleProperties = getConfiguration().createTestConsoleProperties(executor);
testConsoleProperties.setIdBasedTestTree(isIdBasedTestTree());
testConsoleProperties.setIfUndefined(TestConsoleProperties.HIDE_PASSED_TESTS, false);
final BaseTestsOutputConsoleView consoleView = SMTestRunnerConnectionUtil.createConsole(getFrameworkName(), testConsoleProperties);
@@ -50,21 +50,8 @@ public class TestClassCollector {
JavaTestConfigurationBase configuration,
Function<ClassLoader, Predicate<Class<?>>> predicateProducer) {
Module module = configuration.getConfigurationModule().getModule();
List<URL> urls = new ArrayList<>();
PathsList pathsList = ReadAction.compute(() -> (module == null || configuration.getTestSearchScope() == TestSearchScope.WHOLE_PROJECT ? OrderEnumerator.orderEntries(configuration.getProject()) : OrderEnumerator.orderEntries(module))
.runtimeOnly().recursively().getPathsList()); //include jdk to avoid NoClassDefFoundError for classes inside tools.jar
for (VirtualFile file : pathsList.getVirtualFiles()) {
try {
urls.add(VfsUtilCore.virtualToIoFile(file).toURI().toURL());
}
catch (MalformedURLException ignored) {
LOG.info(ignored);
}
}
ClassLoader classLoader = createUsersClassLoader(configuration);
Set<String> classes = new HashSet<>();
UrlClassLoader classLoader = UrlClassLoader.build().allowLock().useCache().urls(urls).get();
try {
String packagePath = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(packagePath);
@@ -118,6 +105,26 @@ public class TestClassCollector {
return ArrayUtil.toStringArray(classes);
}
public static ClassLoader createUsersClassLoader(JavaTestConfigurationBase configuration) {
Module module = configuration.getConfigurationModule().getModule();
List<URL> urls = new ArrayList<>();
PathsList pathsList = ReadAction
.compute(() -> (module == null || configuration.getTestSearchScope() == TestSearchScope.WHOLE_PROJECT ? OrderEnumerator
.orderEntries(configuration.getProject()) : OrderEnumerator.orderEntries(module))
.runtimeOnly().recursively().getPathsList()); //include jdk to avoid NoClassDefFoundError for classes inside tools.jar
for (VirtualFile file : pathsList.getVirtualFiles()) {
try {
urls.add(VfsUtilCore.virtualToIoFile(file).toURI().toURL());
}
catch (MalformedURLException ignored) {
LOG.info(ignored);
}
}
return UrlClassLoader.build().allowLock().useCache().urls(urls).get();
}
@Nullable
public static Path getRootPath(Module module, final boolean chooseSingleModule) {
if (chooseSingleModule) {
@@ -42,11 +42,9 @@ import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.rt.execution.junit.JUnitStarter;
import com.intellij.rt.execution.junit.RepeatCount;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -523,34 +521,6 @@ public class JUnitConfiguration extends JavaTestConfigurationBase {
return "j";
}
public String getPreferredRunner(final GlobalSearchScope globalSearchScope) {
Data data = getPersistentData();
Project project = getProject();
boolean isMethodConfiguration = TEST_METHOD.equals(data.TEST_OBJECT);
boolean isClassConfiguration = TEST_CLASS.equals(data.TEST_OBJECT);
final PsiClass psiClass = isMethodConfiguration || isClassConfiguration
? JavaExecutionUtil.findMainClass(project, data.getMainClassName(), globalSearchScope) : null;
if (psiClass != null) {
if (JUnitUtil.isJUnit5TestClass(psiClass, false)) {
return JUnitStarter.JUNIT5_PARAMETER;
}
if (isClassConfiguration || JUnitUtil.isJUnit4TestClass(psiClass)) {
return JUnitStarter.JUNIT4_PARAMETER;
}
final String methodName = data.getMethodName();
final PsiMethod[] methods = psiClass.findMethodsByName(methodName, true);
for (PsiMethod method : methods) {
if (JUnitUtil.isTestAnnotated(method)) {
return JUnitStarter.JUNIT4_PARAMETER;
}
}
return JUnitStarter.JUNIT3_PARAMETER;
}
return JUnitUtil.isJUnit5(globalSearchScope, project) ? JUnitStarter.JUNIT5_PARAMETER : null;
}
public static class Data implements Cloneable {
public String PACKAGE_NAME;
public String MAIN_CLASS_NAME;
@@ -82,9 +82,6 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope {
if (sourceScope == null) throw new JUnitUtil.NoJUnitException();
final JUnitUtil.NoJUnitException[] ex = new JUnitUtil.NoJUnitException[1];
final PsiClass testCase = ReadAction.compute(() -> {
if (TestObject.isJUnit5(module, sourceScope, sourceScope.getProject())) {
return null;
}
try {
return module == null ? JUnitUtil.getTestCaseClass(sourceScope) : JUnitUtil.getTestCaseClass(module);
}
@@ -32,7 +32,6 @@ import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
import com.intellij.junit4.JUnit4IdeaTestRunner;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -167,9 +166,8 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
}
final Project project = getConfiguration().getProject();
final SourceScope sourceScope = getSourceScope();
GlobalSearchScope globalSearchScope = getScopeForJUnit(getConfiguration().getConfigurationModule().getModule(), sourceScope, project);
String preferredRunner = getConfiguration().getPreferredRunner(globalSearchScope);
GlobalSearchScope globalSearchScope = getScopeForJUnit(getConfiguration().getConfigurationModule().getModule(), project);
String preferredRunner = getRunner();
if (JUnitStarter.JUNIT5_PARAMETER.equals(preferredRunner)) {
final PathsList classPath = javaParameters.getClassPath();
File lib = new File(PathUtil.getJarPathForClass(MultipleFailuresError.class)).getParentFile();
@@ -210,18 +208,12 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
return aPackage != null && aPackage.getDirectories(globalSearchScope).length > 0;
}
public static boolean isJUnit5(@Nullable Module module, @Nullable SourceScope sourceScope, Project project) {
return JUnitUtil.isJUnit5(getScopeForJUnit(module, sourceScope, project), project);
}
private static GlobalSearchScope getScopeForJUnit(@Nullable Module module, @Nullable SourceScope sourceScope, Project project) {
return module != null ? GlobalSearchScope.moduleRuntimeScope(module, true)
: sourceScope != null ? sourceScope.getLibrariesScope() : GlobalSearchScope.allScope(project);
private static GlobalSearchScope getScopeForJUnit(@Nullable Module module, Project project) {
return module != null ? GlobalSearchScope.moduleRuntimeScope(module, true) : GlobalSearchScope.allScope(project);
}
public static GlobalSearchScope getScopeForJUnit(JUnitConfiguration configuration) {
return getScopeForJUnit(configuration.getConfigurationModule().getModule(),
configuration.getTestSearchScope().getSourceScope(configuration),
configuration.getProject() );
}
@@ -246,6 +238,11 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
return processHandler;
}
@Override
protected boolean isIdBasedTestTree() {
return JUnitStarter.JUNIT5_PARAMETER.equals(getRunner());
}
@NotNull
@Override
protected String getForkMode() {
@@ -270,9 +267,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
final SourceScope sourceScope = getSourceScope();
Project project = getConfiguration().getProject();
if (sourceScope != null && packageName != null
&& !ReadAction.compute(() -> isJUnit5(getConfiguration().getConfigurationModule().getModule(),
sourceScope,
getConfiguration().getProject()))) {
&& !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) {
final PsiPackage aPackage = JavaPsiFacade.getInstance(getConfiguration().getProject()).findPackage(packageName);
if (aPackage != null) {
final TestSearchScope scope = getScope();
@@ -377,4 +372,62 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
parameters.getProgramParametersList().add(ForkedDebuggerHelper.DEBUG_SOCKET + getForkSocket().getLocalPort());
}
}
private String myRunner;
protected String getRunner() {
if (myRunner == null) {
myRunner = getRunnerInner();
}
return myRunner;
}
private String getRunnerInner() {
final GlobalSearchScope globalSearchScope = getScopeForJUnit(myConfiguration);
JUnitConfiguration.Data data = myConfiguration.getPersistentData();
Project project = myConfiguration.getProject();
boolean isMethodConfiguration = JUnitConfiguration.TEST_METHOD.equals(data.TEST_OBJECT);
boolean isClassConfiguration = JUnitConfiguration.TEST_CLASS.equals(data.TEST_OBJECT);
final PsiClass psiClass = isMethodConfiguration || isClassConfiguration
? JavaExecutionUtil.findMainClass(project, data.getMainClassName(), globalSearchScope) : null;
if (psiClass != null) {
if (JUnitUtil.isJUnit5TestClass(psiClass, false)) {
return JUnitStarter.JUNIT5_PARAMETER;
}
if (isClassConfiguration || JUnitUtil.isJUnit4TestClass(psiClass)) {
return JUnitStarter.JUNIT4_PARAMETER;
}
final String methodName = data.getMethodName();
final PsiMethod[] methods = psiClass.findMethodsByName(methodName, true);
for (PsiMethod method : methods) {
if (JUnitUtil.isTestAnnotated(method)) {
return JUnitStarter.JUNIT4_PARAMETER;
}
}
return JUnitStarter.JUNIT3_PARAMETER;
}
return JUnitUtil.isJUnit5(globalSearchScope, project) || isCustomJUnit5() ? JUnitStarter.JUNIT5_PARAMETER : null;
}
private boolean isCustomJUnit5() {
if (JavaPsiFacade.getInstance(myConfiguration.getProject()).findPackage("org.junit.platform") == null) return false;
ClassLoader loader = TestClassCollector.createUsersClassLoader(myConfiguration);
try {
ServiceLoader<?> serviceLoader = ServiceLoader.load(Class.forName("org.junit.platform.engine.TestEngine", false, loader), loader);
for (Object engine : serviceLoader) {
String engineClassName = engine.getClass().getName();
if (!"org.junit.jupiter.engine.JupiterTestEngine".equals(engineClassName) &&
!"org.junit.vintage.engine.VintageTestEngine".equals(engineClassName)) {
return true;
}
}
return false;
}
catch (Throwable e) {
return false;
}
}
}
@@ -36,6 +36,7 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.rt.execution.junit.JUnitStarter;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -73,7 +74,7 @@ public class TestPackage extends TestObject {
myClasses.clear();
final SourceScope sourceScope = getSourceScope();
final Module module = getConfiguration().getConfigurationModule().getModule();
if (sourceScope != null && !ReadAction.compute(() -> isJUnit5(module, sourceScope, myProject))) {
if (sourceScope != null && !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) {
DumbService instance = DumbService.getInstance(myProject);
try {
instance.setAlternativeResolveEnabled(true);
@@ -139,7 +140,7 @@ public class TestPackage extends TestObject {
final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
final Project project = getConfiguration().getProject();
final SourceScope sourceScope = data.getScope().getSourceScope(getConfiguration());
if (sourceScope == null || !isJUnit5(getConfiguration().getConfigurationModule().getModule(), sourceScope, project)) { //check for junit 5
if (sourceScope == null || !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) { //check for junit 5
JUnitUtil.checkTestCase(sourceScope, project);
}
createTempFiles(javaParameters);
@@ -17,7 +17,6 @@ package com.intellij.execution.junit2.ui.properties;
import com.intellij.execution.Executor;
import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.TestObject;
import com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction;
import com.intellij.execution.testframework.JavaAwareTestConsoleProperties;
import com.intellij.execution.testframework.JavaTestLocator;
@@ -28,7 +27,6 @@ import com.intellij.execution.testframework.sm.runner.SMTestLocator;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.rt.execution.junit.JUnitStarter;
import com.intellij.rt.execution.junit.RepeatCount;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,7 +38,6 @@ public class JUnitConsoleProperties extends JavaAwareTestConsoleProperties<JUnit
public JUnitConsoleProperties(@NotNull JUnitConfiguration configuration, Executor executor) {
super("JUnit", configuration, executor);
setIdBasedTestTree(JUnitStarter.JUNIT5_PARAMETER.equals(configuration.getPreferredRunner(TestObject.getScopeForJUnit(configuration))));
}
@NotNull
@@ -1,40 +0,0 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed 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 com.intellij.rt.execution.junit;
import java.util.Iterator;
import java.util.ServiceLoader;
public class JUnit5EngineDetector {
public static boolean hasCustomEngine() {
try {
Iterator iterator = ServiceLoader.load(Class.forName("org.junit.platform.engine.TestEngine")).iterator();
while (iterator.hasNext()) {
Object engine = iterator.next();
String engineClassName = engine.getClass().getName();
if (!"org.junit.jupiter.engine.JupiterTestEngine".equals(engineClassName) &&
!"org.junit.vintage.engine.VintageTestEngine".equals(engineClassName)) {
return true;
}
}
return false;
}
catch (Throwable e) {
return false;
}
}
}
@@ -178,7 +178,7 @@ public class JUnitStarter {
public static boolean isJUnit5Preferred() {
final String useJUnit5 = System.getProperty(JUNIT5_KEY);
if (useJUnit5 == null) {
return JUnit5EngineDetector.hasCustomEngine();
return false;
}
else {
final Boolean boolValue = Boolean.valueOf(useJUnit5);