Skip to content

Commit

Permalink
Merge pull request #29808 from aloubyansky/gradle-test-from-ide
Browse files Browse the repository at this point in the history
Look for test classes in the model loaded from the Gradle tooling
  • Loading branch information
aloubyansky authored Dec 14, 2022
2 parents 8ba65e5 + 87eb67f commit 057e847
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
Expand All @@ -27,7 +29,9 @@
import org.gradle.api.initialization.IncludedBuild;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskCollection;
import org.gradle.api.tasks.compile.AbstractCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.internal.composite.IncludedBuildInternal;
import org.gradle.language.jvm.tasks.ProcessResources;
import org.gradle.tooling.provider.model.ParameterizedToolingModelBuilder;
Expand Down Expand Up @@ -94,7 +98,8 @@ public Object buildAll(String modelName, Project project) {
public Object buildAll(String modelName, ModelParameter parameter, Project project) {
final LaunchMode mode = LaunchMode.valueOf(parameter.getMode());

final ApplicationDeploymentClasspathBuilder classpathBuilder = new ApplicationDeploymentClasspathBuilder(project, mode);
final ApplicationDeploymentClasspathBuilder classpathBuilder = new ApplicationDeploymentClasspathBuilder(project,
mode);
final Configuration classpathConfig = classpathBuilder.getRuntimeConfiguration();
final Configuration deploymentConfig = classpathBuilder.getDeploymentConfiguration();
final PlatformImports platformImports = classpathBuilder.getPlatformImports();
Expand Down Expand Up @@ -127,18 +132,41 @@ public static ResolvedDependency getProjectArtifact(Project project, boolean wor
.setArtifactId(project.getName())
.setVersion(project.getVersion().toString());

SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
final SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
final WorkspaceModule.Mutable mainModule = WorkspaceModule.builder()
.setModuleId(new GAV(appArtifact.getGroupId(), appArtifact.getArtifactId(), appArtifact.getVersion()))
.setModuleDir(project.getProjectDir().toPath())
.setBuildDir(project.getBuildDir().toPath())
.setBuildFile(project.getBuildFile().toPath());

initProjectModule(project, mainModule, sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME),
SourceSet.MAIN_SOURCE_SET_NAME, ArtifactSources.MAIN);
initProjectModule(project, mainModule, sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME), ArtifactSources.MAIN);
if (workspaceDiscovery) {
initProjectModule(project, mainModule, sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME),
SourceSet.TEST_SOURCE_SET_NAME, ArtifactSources.TEST);
final TaskCollection<Test> testTasks = project.getTasks().withType(Test.class);
if (!testTasks.isEmpty()) {
final Map<File, SourceSet> sourceSetsByClassesDir = new HashMap<>();
sourceSets.forEach(s -> {
s.getOutput().getClassesDirs().forEach(d -> {
if (d.exists()) {
sourceSetsByClassesDir.put(d, s);
}
});
});
testTasks.forEach(t -> {
if (t.getEnabled()) {
t.getTestClassesDirs().forEach(d -> {
if (d.exists()) {
final SourceSet sourceSet = sourceSetsByClassesDir.remove(d);
if (sourceSet != null) {
initProjectModule(project, mainModule, sourceSet,
sourceSet.getName().equals(SourceSet.TEST_SOURCE_SET_NAME)
? ArtifactSources.TEST
: sourceSet.getName());
}
}
});
}
});
}
}

final PathList.Builder paths = PathList.builder();
Expand All @@ -150,12 +178,8 @@ public static ResolvedDependency getProjectArtifact(Project project, boolean wor

private static void collectDestinationDirs(Collection<SourceDir> sources, final PathList.Builder paths) {
for (SourceDir src : sources) {
if (!Files.exists(src.getOutputDir())) {
continue;
}

final Path path = src.getOutputDir();
if (paths.contains(path)) {
if (paths.contains(path) || !Files.exists(path)) {
continue;
}
paths.add(path);
Expand Down Expand Up @@ -314,7 +338,7 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res
paths = pathBuilder.build();
}
} else if (sourceSets != null) {
if ("test".equals(classifier)) {
if (SourceSet.TEST_SOURCE_SET_NAME.equals(classifier)) {
final PathList.Builder pathBuilder = PathList.builder();
projectModule = initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder,
pathBuilder, SourceSet.TEST_SOURCE_SET_NAME, true);
Expand Down Expand Up @@ -347,7 +371,7 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res
}
}

processedModules.add(new GACT(resolvedDep.getModuleGroup(), resolvedDep.getModuleName()));
processedModules.add(ArtifactKey.ga(resolvedDep.getModuleGroup(), resolvedDep.getModuleName()));
for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) {
if (!processedModules.contains(new GACT(child.getModuleGroup(), child.getModuleName()))) {
collectDependencies(child, workspaceDiscovery, project, artifactFiles, processedModules,
Expand All @@ -357,7 +381,7 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res
}

private static String toNonNullClassifier(String resolvedClassifier) {
return resolvedClassifier == null ? "" : resolvedClassifier;
return resolvedClassifier == null ? ArtifactCoords.DEFAULT_CLASSIFIER : resolvedClassifier;
}

private WorkspaceModule.Mutable initProjectModuleAndBuildPaths(final Project project,
Expand All @@ -375,13 +399,13 @@ private WorkspaceModule.Mutable initProjectModuleAndBuildPaths(final Project pro

final String classifier = toNonNullClassifier(resolvedArtifact.getClassifier());
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
initProjectModule(project, projectModule, sourceSets.findByName(sourceName), sourceName, classifier);
initProjectModule(project, projectModule, sourceSets.findByName(sourceName), classifier);

collectDestinationDirs(projectModule.getSources(classifier).getSourceDirs(), buildPaths);
collectDestinationDirs(projectModule.getSources(classifier).getResourceDirs(), buildPaths);

appModel.addReloadableWorkspaceModule(
new GACT(resolvedArtifact.getModuleVersion().getId().getGroup(), resolvedArtifact.getName(), classifier,
ArtifactKey.of(resolvedArtifact.getModuleVersion().getId().getGroup(), resolvedArtifact.getName(), classifier,
ArtifactCoords.TYPE_JAR));
return projectModule;
}
Expand Down Expand Up @@ -445,7 +469,7 @@ private static Properties readDescriptor(final Path path) {
}

private static void initProjectModule(Project project, WorkspaceModule.Mutable module, SourceSet sourceSet,
String sourceName, String classifier) {
String classifier) {

if (sourceSet == null) {
return;
Expand All @@ -456,8 +480,6 @@ private static void initProjectModule(Project project, WorkspaceModule.Mutable m
// see https://github.com/quarkusio/quarkus/issues/20755

final List<SourceDir> sourceDirs = new ArrayList<>(1);
final List<SourceDir> resourceDirs = new ArrayList<>(1);

project.getTasks().withType(AbstractCompile.class, t -> {
if (!t.getEnabled()) {
return;
Expand All @@ -474,9 +496,7 @@ private static void initProjectModule(Project project, WorkspaceModule.Mutable m
// we are looking for the root dirs containing sources
if (a.getRelativePath().getSegments().length == 1) {
final File srcDir = a.getFile().getParentFile();
DefaultSourceDir sources = new DefaultSourceDir(srcDir.toPath(), destDir.toPath(),
Collections.singletonMap("compiler", t.getName()));
sourceDirs.add(sources);
sourceDirs.add(new DefaultSourceDir(srcDir.toPath(), destDir.toPath(), Map.of("compiler", t.getName())));
}
});
});
Expand All @@ -500,18 +520,17 @@ private static void initProjectModule(Project project, WorkspaceModule.Mutable m
// we are looking for the root dirs containing sources
if (a.getRelativePath().getSegments().length == 1) {
final File srcDir = a.getFile().getParentFile();
DefaultSourceDir sources = new DefaultSourceDir(srcDir.toPath(), destDir.toPath(),
Collections.singletonMap("compiler", t.getName()));
sourceDirs.add(sources);
sourceDirs
.add(new DefaultSourceDir(srcDir.toPath(), destDir.toPath(), Map.of("compiler", t.getName())));
}
});
});
} catch (ClassNotFoundException e) {
// ignore
}

final LinkedHashMap<File, Path> resourceDirs = new LinkedHashMap<>(1);
final File resourcesOutputDir = sourceSet.getOutput().getResourcesDir();

project.getTasks().withType(ProcessResources.class, t -> {
if (!t.getEnabled()) {
return;
Expand All @@ -528,16 +547,20 @@ private static void initProjectModule(Project project, WorkspaceModule.Mutable m
// we are looking for the root dirs containing sources
if (a.getRelativePath().getSegments().length == 1) {
final File srcDir = a.getFile().getParentFile();
resourceDirs.add(new DefaultSourceDir(srcDir.toPath(), destDir));
resourceDirs.put(srcDir, destDir);
}
});
});
// there could be a task generating resources
if (resourcesOutputDir.exists() && resourceDirs.isEmpty()) {
sourceSet.getResources().getSrcDirs()
.forEach(srcDir -> resourceDirs.add(new DefaultSourceDir(srcDir.toPath(), resourcesOutputDir.toPath())));
.forEach(srcDir -> resourceDirs.put(srcDir, resourcesOutputDir.toPath()));
}
final List<SourceDir> resources = new ArrayList<>(resourceDirs.size());
for (Map.Entry<File, Path> e : resourceDirs.entrySet()) {
resources.add(new DefaultSourceDir(e.getKey().toPath(), e.getValue()));
}
module.addArtifactSources(new DefaultArtifactSources(classifier, sourceDirs, resourceDirs));
module.addArtifactSources(new DefaultArtifactSources(classifier, sourceDirs, resources));
}

private void addSubstitutedProject(PathList.Builder paths, File projectFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import java.util.Collection;
import java.util.List;

import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.paths.EmptyPathTree;
import io.quarkus.paths.MultiRootPathTree;
import io.quarkus.paths.PathTree;

public interface ArtifactSources {

String MAIN = "";
String MAIN = ArtifactCoords.DEFAULT_CLASSIFIER;
String TEST = "tests";

static ArtifactSources main(SourceDir sources, SourceDir resources) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class BuildToolHelper {
private static final Logger log = Logger.getLogger(BuildToolHelper.class);

private final static String[] DEVMODE_REQUIRED_TASKS = new String[] { "classes" };
private final static String[] TEST_REQUIRED_TASKS = new String[] { "classes", "testClasses" };
private final static String[] TEST_REQUIRED_TASKS = new String[] { "classes", "testClasses", "integrationTestClasses" };
private final static List<String> ENABLE_JAR_PACKAGING = Collections
.singletonList("-Dorg.gradle.java.compile-classpath-packaging=true");

Expand Down Expand Up @@ -108,6 +108,7 @@ public static ApplicationModel enableGradleAppModelForTest(Path projectRoot)
public static ApplicationModel enableGradleAppModel(Path projectRoot, String mode, List<String> jvmArgs, String... tasks)
throws IOException, AppModelResolverException {
if (isGradleProject(projectRoot)) {
log.infof("Loading Quarkus Gradle application model for %s", projectRoot);
final ApplicationModel model = QuarkusGradleModelFactory.create(
getBuildFile(projectRoot, BuildTool.GRADLE).toFile(),
mode, jvmArgs, tasks);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkus.bootstrap.resolver;

import java.io.File;
import java.util.Collections;
import java.util.List;

import org.gradle.tooling.GradleConnector;
Expand All @@ -14,7 +13,7 @@
public class QuarkusGradleModelFactory {

public static ApplicationModel create(File projectDir, String mode, String... tasks) {
return create(projectDir, mode, Collections.emptyList(), tasks);
return create(projectDir, mode, List.of(), tasks);
}

public static ApplicationModel create(File projectDir, String mode, List<String> jvmArgs, String... tasks) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public class Dummy {
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void shouldLoadSimpleModuleTestModel() throws URISyntaxException, IOExcep
@Test
public void shouldLoadSimpleModuleDevModel() throws URISyntaxException, IOException {
File projectDir = getResourcesProject("builder/simple-module-project");
final ApplicationModel quarkusModel = QuarkusGradleModelFactory.create(projectDir, "DEVELOPMENT");
final ApplicationModel quarkusModel = QuarkusGradleModelFactory.create(projectDir, "DEVELOPMENT", "testClasses");

assertNotNull(quarkusModel);
assertNotNull(quarkusModel.getApplicationModule());
Expand All @@ -63,7 +63,8 @@ public void shouldLoadSimpleModuleDevModel() throws URISyntaxException, IOExcept
public void shouldLoadMultiModuleTestModel() throws URISyntaxException, IOException {
File projectDir = getResourcesProject("builder/multi-module-project");

final ApplicationModel quarkusModel = QuarkusGradleModelFactory.create(new File(projectDir, "application"), "TEST");
final ApplicationModel quarkusModel = QuarkusGradleModelFactory.create(new File(projectDir, "application"), "TEST",
"testClasses");

assertNotNull(quarkusModel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ private TestClassIndexer() {
}

public static Index indexTestClasses(Class<?> testClass) {
return indexTestClasses(getTestClassesLocation(testClass));
}

public static Index indexTestClasses(final Path testClassesLocation) {
final Indexer indexer = new Indexer();
final Path testClassesLocation = getTestClassesLocation(testClass);
try {
if (Files.isDirectory(testClassesLocation)) {
indexTestClassesDir(indexer, testClassesLocation);
Expand All @@ -48,7 +51,11 @@ public static Index indexTestClasses(Class<?> testClass) {
}

public static void writeIndex(Index index, Class<?> testClass) {
try (FileOutputStream fos = new FileOutputStream(indexPath(testClass).toFile(), false)) {
writeIndex(index, getTestClassesLocation(testClass), testClass);
}

public static void writeIndex(Index index, Path testClassLocation, Class<?> testClass) {
try (FileOutputStream fos = new FileOutputStream(indexPath(testClassLocation, testClass).toFile(), false)) {
IndexWriter indexWriter = new IndexWriter(fos);
indexWriter.write(index);
} catch (IOException ignored) {
Expand All @@ -58,7 +65,11 @@ public static void writeIndex(Index index, Class<?> testClass) {
}

public static Index readIndex(Class<?> testClass) {
Path path = indexPath(testClass);
return readIndex(getTestClassesLocation(testClass), testClass);
}

public static Index readIndex(Path testClassLocation, Class<?> testClass) {
Path path = indexPath(testClassLocation, testClass);
if (path.toFile().exists()) {
try (FileInputStream fis = new FileInputStream(path.toFile())) {
return new IndexReader(fis).read();
Expand All @@ -75,7 +86,11 @@ public static Index readIndex(Class<?> testClass) {
}

private static Path indexPath(Class<?> testClass) {
return PathTestHelper.getTestClassesLocation(testClass).resolve(testClass.getSimpleName() + ".idx");
return indexPath(PathTestHelper.getTestClassesLocation(testClass), testClass);
}

private static Path indexPath(Path testClassLocation, Class<?> testClass) {
return testClassLocation.resolve(testClass.getSimpleName() + ".idx");
}

private static void indexTestClassesDir(Indexer indexer, final Path testClassesLocation) throws IOException {
Expand Down
Loading

0 comments on commit 057e847

Please sign in to comment.