diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index c225160e076d..89061d8a4738 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -24,7 +24,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.ProjectFileIndex; @@ -124,12 +123,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState list = perModule.get(module); - if (list == null) { - list = new ArrayList<>(); - perModule.put(module, list); - } - list.add(name); + fillForkModule(perModule, module, name); } } else { @@ -160,6 +154,10 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState> perModule, Module module, String name) { + perModule.computeIfAbsent(module, elemList -> new ArrayList<>()).add(name); + } + public Module[] getModulesToCompile() { final SourceScope sourceScope = getSourceScope(); return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY; diff --git a/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfigurationProducer.java index 750f3ca1cbb4..fed204186010 100644 --- a/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfigurationProducer.java @@ -13,15 +13,14 @@ import com.intellij.execution.junit.TestsPattern; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testDiscovery.TestDiscoveryConfigurationProducer; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.rt.execution.junit.JUnitStarter; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; +import java.util.*; import java.util.stream.Collectors; public class JUnitTestDiscoveryConfigurationProducer extends TestDiscoveryConfigurationProducer { @@ -63,16 +62,57 @@ public class JUnitTestDiscoveryConfigurationProducer extends TestDiscoveryConfig }) .collect(Collectors.toCollection(LinkedHashSet::new))); data.TEST_OBJECT = JUnitConfiguration.TEST_PATTERN; + Map toRoot = splitModulesIntoChunks(testMethods, module); return new TestsPattern((JUnitConfiguration)configuration, environment) { @Override protected boolean forkPerModule() { return module == null; } + @Override + protected void fillForkModule(Map> perModule, Module module, String name) { + super.fillForkModule(perModule, toRoot.get(module), name); + } + @Override protected String getRunner() { return JUnitStarter.JUNIT4_PARAMETER; } }; } + + private static Map splitModulesIntoChunks(@NotNull Location[] testMethods, Module module) { + Map toRoot = new HashMap<>(); + if (module == null) { + List usedModules = Arrays.stream(testMethods).map(Location::getModule).collect(Collectors.toList()); + while (!usedModules.isEmpty()) { + Map> allDeps = new HashMap<>(); + for (Module usedModule : usedModules) { + List rootModules = ModuleUtilCore.getAllDependentModules(usedModule); + for (Module rootModule : rootModules) { + allDeps.computeIfAbsent(rootModule, __ -> new ArrayList<>()).add(usedModule); + } + allDeps.computeIfAbsent(usedModule, __ -> new ArrayList<>()).add(usedModule); + } + + + Optional>> maxDependency = + allDeps.entrySet().stream().max(Comparator.comparingInt(e -> e.getValue().size())); + + if (maxDependency.isPresent()) { + Map.Entry> entry = maxDependency.get(); + Module rootModule = entry.getKey(); + List srcModules = entry.getValue(); + for (Module srcModule : srcModules) { + toRoot.put(srcModule, rootModule); + } + usedModules.removeAll(srcModules); + } + else { + break; + } + } + } + return toRoot; + } }