Skip to content

Commit

Permalink
chore: simplify simulations detection
Browse files Browse the repository at this point in the history
  • Loading branch information
slandelle committed Feb 14, 2024
1 parent 9f60857 commit 3ca23c8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 186 deletions.
107 changes: 1 addition & 106 deletions src/main/java/io/gatling/mojo/GatlingMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,17 @@
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.apache.maven.toolchain.Toolchain;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.ExceptionUtils;
import org.codehaus.plexus.util.SelectorUtils;

/** Mojo to execute Gatling. */
@Execute(phase = LifecyclePhase.TEST_COMPILE)
Expand Down Expand Up @@ -342,8 +334,7 @@ private List<String> simulations() throws MojoFailureException {

} else {
List<String> simulations =
SimulationClassUtils.resolveSimulations(
mavenProject, compiledClassesFolder, includes, excludes);
SimulationClassUtils.resolveSimulations(mavenProject, includes, excludes);

if (simulations.isEmpty()) {
getLog().error("No simulations to run");
Expand Down Expand Up @@ -388,100 +379,4 @@ private List<String> gatlingArgs(String simulationClass) throws Exception {

return args;
}

private Optional<Class<?>> loadJavaSimulationClass(ClassLoader testClassLoader) {
try {
return Optional.of(testClassLoader.loadClass("io.gatling.javaapi.core.Simulation"));
} catch (ClassNotFoundException e) {
// ignore
return Optional.empty();
}
}

/**
* Resolve simulation files to execute from the simulation folder.
*
* @return a comma separated String of simulation class names.
*/
private List<String> resolveSimulations() {

try {
ClassLoader testClassLoader = new URLClassLoader(testClassPathUrls());

Class<?> scalaSimulationClass =
testClassLoader.loadClass("io.gatling.core.scenario.Simulation");
Optional<Class<?>> javaSimulationClass = loadJavaSimulationClass(testClassLoader);

List<String> includes = MojoUtils.arrayAsListEmptyIfNull(this.includes);
List<String> excludes = MojoUtils.arrayAsListEmptyIfNull(this.excludes);

List<String> simulationsClasses = new ArrayList<>();

for (String classFile : compiledClassFiles()) {
String className = pathToClassName(classFile);

boolean isIncluded = includes.isEmpty() || match(includes, className);
boolean isExcluded = !excludes.isEmpty() && match(excludes, className);

if (isIncluded && !isExcluded) {
// check if the class is a concrete Simulation
Class<?> clazz = testClassLoader.loadClass(className);
if (isConcreteClass(clazz)
&& (javaSimulationClass
.map(simClass -> simClass.isAssignableFrom(clazz))
.orElse(false)
|| scalaSimulationClass.isAssignableFrom(clazz))) {
simulationsClasses.add(className);
}
}
}

return simulationsClasses;

} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static boolean match(List<String> patterns, String string) {
for (String pattern : patterns) {
if (pattern != null && SelectorUtils.match(pattern, string)) {
return true;
}
}
return false;
}

private URL[] testClassPathUrls()
throws DependencyResolutionRequiredException, MalformedURLException {

List<String> testClasspathElements = mavenProject.getTestClasspathElements();

URL[] urls = new URL[testClasspathElements.size()];
for (int i = 0; i < testClasspathElements.size(); i++) {
String testClasspathElement = testClasspathElements.get(i);
URL url = Paths.get(testClasspathElement).toUri().toURL();
urls[i] = url;
}

return urls;
}

private String[] compiledClassFiles() throws IOException {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(compiledClassesFolder.getCanonicalPath());
scanner.setIncludes(new String[] {"**/*.class"});
scanner.scan();
String[] files = scanner.getIncludedFiles();
Arrays.sort(files);
return files;
}

private String pathToClassName(String path) {
return path.substring(0, path.length() - ".class".length()).replace(File.separatorChar, '.');
}

private boolean isConcreteClass(Class<?> clazz) {
return !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers());
}
}
107 changes: 27 additions & 80 deletions src/main/java/io/gatling/mojo/SimulationClassUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,13 @@
*/
package io.gatling.mojo;

import io.gatling.scanner.SimulationScanResult;
import io.gatling.scanner.SimulationScanner;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import java.util.stream.Collectors;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.SelectorUtils;

public final class SimulationClassUtils {
Expand All @@ -42,83 +35,41 @@ private SimulationClassUtils() {}
* @return a list of simulation class names.
*/
public static List<String> resolveSimulations(
MavenProject mavenProject, File compiledClassesFolder, String[] includes, String[] excludes) {

MavenProject mavenProject, String[] includes, String[] excludes) {
try {
ClassLoader testClassLoader = new URLClassLoader(testClassPathUrls(mavenProject));

Class<?> scalaSimulationClass =
testClassLoader.loadClass("io.gatling.core.scenario.Simulation");
Optional<Class<?>> javaSimulationClass = loadJavaSimulationClass(testClassLoader);

List<String> includesList = MojoUtils.arrayAsListEmptyIfNull(includes);
List<String> excludesList = MojoUtils.arrayAsListEmptyIfNull(excludes);

List<String> simulationsClasses = new ArrayList<>();

for (String classFile : compiledClassFiles(compiledClassesFolder)) {
String className = pathToClassName(classFile);
List<String> testClasspathElements = mavenProject.getTestClasspathElements();

boolean isIncluded = includesList.isEmpty() || match(includesList, className);
boolean isExcluded = !excludesList.isEmpty() && match(excludesList, className);
List<File> dependencies = new ArrayList<>();
List<File> classDirectories = new ArrayList<>();

if (isIncluded && !isExcluded) {
// check if the class is a concrete Simulation
Class<?> clazz = testClassLoader.loadClass(className);
if (isConcreteClass(clazz)
&& (javaSimulationClass
.map(simClass -> simClass.isAssignableFrom(clazz))
.orElse(false)
|| scalaSimulationClass.isAssignableFrom(clazz))) {
simulationsClasses.add(className);
}
for (String testClasspathElement : testClasspathElements) {
File file = new File(testClasspathElement);
if (file.isDirectory()) {
classDirectories.add(file);
} else if (file.isFile()) {
dependencies.add(file);
}
}

return simulationsClasses;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
SimulationScanResult simulationScanResult =
SimulationScanner.scan(dependencies, classDirectories);

private static URL[] testClassPathUrls(MavenProject mavenProject)
throws DependencyResolutionRequiredException, MalformedURLException {

List<String> testClasspathElements = mavenProject.getTestClasspathElements();

URL[] urls = new URL[testClasspathElements.size()];
for (int i = 0; i < testClasspathElements.size(); i++) {
String testClasspathElement = testClasspathElements.get(i);
URL url = Paths.get(testClasspathElement).toUri().toURL();
urls[i] = url;
}

return urls;
}
List<String> includesList = MojoUtils.arrayAsListEmptyIfNull(includes);
List<String> excludesList = MojoUtils.arrayAsListEmptyIfNull(excludes);

private static Optional<Class<?>> loadJavaSimulationClass(ClassLoader testClassLoader) {
try {
return Optional.of(testClassLoader.loadClass("io.gatling.javaapi.core.Simulation"));
} catch (ClassNotFoundException e) {
// ignore
return Optional.empty();
return simulationScanResult.getSimulationClasses().stream()
.filter(
className -> {
boolean isIncluded = includesList.isEmpty() || match(includesList, className);
boolean isExcluded = !excludesList.isEmpty() && match(excludesList, className);
return isIncluded && !isExcluded;
})
.collect(Collectors.toList());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static String[] compiledClassFiles(File compiledClassesFolder) throws IOException {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(compiledClassesFolder.getCanonicalPath());
scanner.setIncludes(new String[] {"**/*.class"});
scanner.scan();
String[] files = scanner.getIncludedFiles();
Arrays.sort(files);
return files;
}

private static String pathToClassName(String path) {
return path.substring(0, path.length() - ".class".length()).replace(File.separatorChar, '.');
}

private static boolean match(List<String> patterns, String string) {
for (String pattern : patterns) {
if (pattern != null && SelectorUtils.match(pattern, string)) {
Expand All @@ -127,8 +78,4 @@ private static boolean match(List<String> patterns, String string) {
}
return false;
}

private static boolean isConcreteClass(Class<?> clazz) {
return !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers());
}
}

0 comments on commit 3ca23c8

Please sign in to comment.