Skip to content

Commit

Permalink
use parameters file for java 9+
Browse files Browse the repository at this point in the history
  • Loading branch information
hcoles committed Nov 8, 2023
1 parent ffd3fa6 commit 0595209
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class CoverageProcess {
public CoverageProcess(final ProcessArgs processArgs,
final CoverageOptions arguments, final ServerSocket socket,
final List<String> testClasses, final Consumer<CoverageResult> handler) {
this.process = new WrappingProcess(socket.getLocalPort(), processArgs,
this.process = WrappingProcess.create(socket.getLocalPort(), processArgs,
CoverageMinion.class);

this.crt = new CommunicationThread(socket, new SendData(arguments, testClasses), new Receive(handler));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class MutationTestProcess {

public MutationTestProcess(final ServerSocket socket,
final ProcessArgs processArgs, final MinionArguments arguments) {
this.process = new WrappingProcess(socket.getLocalPort(), processArgs,
this.process = WrappingProcess.create(socket.getLocalPort(), processArgs,
MutationTestMinion.class);

this.idMap = new ConcurrentHashMap<>();
Expand Down
152 changes: 152 additions & 0 deletions pitest-entry/src/main/java/org/pitest/process/Java9Process.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package org.pitest.process;

import static java.util.Arrays.asList;
import static org.pitest.functional.prelude.Prelude.or;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

import org.pitest.functional.FCollection;

/**
* Process for java 9+, using file to pass
* all parameters
*/
public class Java9Process implements WrappingProcess {

private final int port;
private final ProcessArgs processArgs;
private final Class<?> minionClass;
private JavaProcess process;

public Java9Process(int port, ProcessArgs args, Class<?> minionClass) {
this.port = port;
this.processArgs = args;
this.minionClass = minionClass;
}

public void start() throws IOException {
String[] args = { "" + this.port };

ProcessBuilder processBuilder = createProcessBuilder(
this.processArgs.getJavaExecutable(),
this.processArgs.getJvmArgs(),
this.minionClass, asList(args),
this.processArgs.getJavaAgentFinder(),
this.processArgs.getLaunchClassPath());


configureProcessBuilder(processBuilder, this.processArgs.getWorkingDir(),
this.processArgs.getEnvironmentVariables());

Process process = processBuilder.start();
this.process = new JavaProcess(process, this.processArgs.getStdout(),
this.processArgs.getStdErr());
}

public boolean isAlive() {
return process.isAlive();
}

private void configureProcessBuilder(ProcessBuilder processBuilder,
File workingDirectory, Map<String, String> environmentVariables) {
processBuilder.directory(workingDirectory);
Map<String, String> environment = processBuilder.environment();

for (final Map.Entry<String, String> entry : environmentVariables.entrySet()) {
environment.put(entry.getKey(), entry.getValue());
}
}

public void destroy() {
this.process.destroy();
}

private ProcessBuilder createProcessBuilder(String javaProc,
List<String> args, Class<?> mainClass, List<String> programArgs,
JavaAgent javaAgent, String classPath) {
List<String> cmd = createLaunchArgs(javaAgent, args, mainClass,
programArgs, classPath);

removeJacocoAgent(cmd);

try {
// all arguments are passed via a temporary file, thereby avoiding command line length limits
Path argsFile = createArgsFile(cmd);
return new ProcessBuilder(asList(javaProc, "@" + argsFile.toFile().getAbsolutePath()));
} catch (IOException e) {
throw new RuntimeException(e);
}

}
private void removeJacocoAgent(List<String> cmd) {
removeFromClassPath(cmd, line -> line.startsWith("-javaagent") && line.contains("jacoco"));
}

private static void removeFromClassPath(List<String> cmd, Predicate<String> match) {
for (int i = cmd.size() - 1; i >= 0; i--) {
if (match.test(cmd.get(i))) {
cmd.remove(i);
}
}
}

private List<String> createLaunchArgs(JavaAgent agentJarLocator, List<String> args, Class<?> mainClass,
List<String> programArgs, String classPath) {

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

cmd.add("-classpath");
cmd.add(classPath);

addPITJavaAgent(agentJarLocator, cmd);

cmd.addAll(args);

addLaunchJavaAgents(cmd);

cmd.add(mainClass.getName());
cmd.addAll(programArgs);
return cmd;
}

private Path createArgsFile(List<String> cmd) throws IOException {
Path args = Files.createTempFile("pitest-args", ".args");
args.toFile().deleteOnExit();
Files.write(args, cmd);
return args;
}

private static void addPITJavaAgent(JavaAgent agentJarLocator,
List<String> cmd) {
final Optional<String> jarLocation = agentJarLocator.getJarLocation();
jarLocation.ifPresent(l -> cmd.add("-javaagent:" + l));
}

private static void addLaunchJavaAgents(List<String> cmd) {
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
List<String> agents = FCollection.filter(rt.getInputArguments(),
or(isJavaAgentParam(), isEnvironmentSetting()));
cmd.addAll(agents);
}

private static Predicate<String> isEnvironmentSetting() {
return a -> a.startsWith("-D");
}

private static Predicate<String> isJavaAgentParam() {
return a -> a.toLowerCase().startsWith("-javaagent");
}

public JavaProcess getProcess() {
return this.process;
}
}
170 changes: 170 additions & 0 deletions pitest-entry/src/main/java/org/pitest/process/LegacyProcess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package org.pitest.process;

import static org.pitest.functional.prelude.Prelude.or;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

import org.pitest.functional.FCollection;
import org.pitest.util.ManifestUtils;

/**
* Process for Java 8, pre module and params file support
*/
public class LegacyProcess implements WrappingProcess {

private final int port;
private final ProcessArgs processArgs;
private final Class<?> minionClass;

private JavaProcess process;

public LegacyProcess(int port, ProcessArgs args, Class<?> minionClass) {
this.port = port;
this.processArgs = args;
this.minionClass = minionClass;
}

public void start() throws IOException {
final String[] args = { "" + this.port };

final ProcessBuilder processBuilder = createProcessBuilder(
this.processArgs.getJavaExecutable(),
this.processArgs.getJvmArgs(),
this.minionClass, Arrays.asList(args),
this.processArgs.getJavaAgentFinder(),
this.processArgs.getLaunchClassPath());


setClassPathInEnvironment(processBuilder);

configureProcessBuilder(processBuilder, this.processArgs.getWorkingDir(),
this.processArgs.getEnvironmentVariables());

final Process process = processBuilder.start();
this.process = new JavaProcess(process, this.processArgs.getStdout(),
this.processArgs.getStdErr());
}

public boolean isAlive() {
return process.isAlive();
}


// Reportedly passing the classpath as an environment variable rather than on the command
// line increases the allowable size of the classpath, but this has not been confirmed
private void setClassPathInEnvironment(final ProcessBuilder processBuilder) {
if (!processArgs.useClasspathJar()) {
processBuilder.environment().put("CLASSPATH", this.processArgs.getLaunchClassPath());
}
}

private void configureProcessBuilder(ProcessBuilder processBuilder,
File workingDirectory, Map<String, String> environmentVariables) {
processBuilder.directory(workingDirectory);
final Map<String, String> environment = processBuilder.environment();

for (final Map.Entry<String, String> entry : environmentVariables.entrySet()) {
environment.put(entry.getKey(), entry.getValue());
}
}

public void destroy() {
this.process.destroy();
}

private ProcessBuilder createProcessBuilder(String javaProc,
List<String> args, Class<?> mainClass, List<String> programArgs,
JavaAgent javaAgent, String classPath) {
final List<String> cmd = createLaunchArgs(javaProc, javaAgent, args, mainClass,
programArgs, classPath);

// IBM jdk adds this, thereby breaking everything
removeClassPathProperties(cmd);

removeJacocoAgent(cmd);

return new ProcessBuilder(cmd);
}

private void removeJacocoAgent(List<String> cmd) {
removeFromClassPath(cmd, line -> line.startsWith("-javaagent") && line.contains("jacoco"));
}

private static void removeClassPathProperties(List<String> cmd) {
removeFromClassPath(cmd, s -> s.startsWith("-Djava.class.path"));
}

private static void removeFromClassPath(List<String> cmd, Predicate<String> match) {
for (int i = cmd.size() - 1; i >= 0; i--) {
if (match.test(cmd.get(i))) {
cmd.remove(i);
}
}
}

private List<String> createLaunchArgs(String javaProcess,
JavaAgent agentJarLocator, List<String> args, Class<?> mainClass,
List<String> programArgs, String classPath) {

final List<String> cmd = new ArrayList<>();
cmd.add(javaProcess);

createClasspathJar(classPath, cmd);

addPITJavaAgent(agentJarLocator, cmd);

cmd.addAll(args);

addLaunchJavaAgents(cmd);

cmd.add(mainClass.getName());
cmd.addAll(programArgs);
return cmd;
}

private void createClasspathJar(String classPath, final List<String> cmd) {
if (this.processArgs.useClasspathJar()) {
try {
cmd.add("-classpath");
cmd.add(
ManifestUtils.createClasspathJarFile(classPath).getAbsolutePath());
} catch (Exception e) {
throw new RuntimeException("Unable to create jar to contain classpath",
e);
}
}
}

private static void addPITJavaAgent(JavaAgent agentJarLocator,
List<String> cmd) {
final Optional<String> jarLocation = agentJarLocator.getJarLocation();
jarLocation.ifPresent(l -> cmd.add("-javaagent:" + l));
}

private static void addLaunchJavaAgents(List<String> cmd) {
final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
final List<String> agents = FCollection.filter(rt.getInputArguments(),
or(isJavaAgentParam(), isEnvironmentSetting()));
cmd.addAll(agents);
}

private static Predicate<String> isEnvironmentSetting() {
return a -> a.startsWith("-D");
}

private static Predicate<String> isJavaAgentParam() {
return a -> a.toLowerCase().startsWith("-javaagent");
}

public JavaProcess getProcess() {
return this.process;
}
}
Loading

0 comments on commit 0595209

Please sign in to comment.