blob: b22ddcaec99c9a1c96a075bb2959bf3b6b495d24 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Cedric Chabanois and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cedric Chabanois (cchabanois@gmail.com) - initial implementation
*******************************************************************************/
package org.eclipse.jdt.debug.tests.launching;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
import org.eclipse.jdt.internal.launching.LaunchingPlugin;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathSupport;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
/**
* Test long module-path. OSs have limits in term of command line length or argument length. We use an argument file when module-path is too long.
*
*/
public class LongModulePathTests extends AbstractDebugTest {
private static final IPath CLASSPATH_PROJECT_CONTENT_PATH = new Path("testresources/classpathModuleProject");
private static final String MAIN_TYPE_NAME = "test.classpath.Main";
private IJavaProject javaProject;
private IJavaThread thread;
private ILaunchConfiguration launchConfiguration;
public LongModulePathTests(String name) {
super(name);
}
@Override
protected void tearDown() throws Exception {
try {
if (thread != null) {
terminateAndRemove(thread);
}
if (javaProject != null) {
javaProject.getProject().delete(true, true, null);
}
if (launchConfiguration != null) {
launchConfiguration.delete();
}
} catch (CoreException ce) {
// ignore
} finally {
super.tearDown();
}
}
/*
* When JVM > 9, an argument file for the modulepath is created when modulepath is too long
*/
public void testVeryLongModulepathWithArgumentFile() throws Exception {
// Given
javaProject = createJavaProjectClone("testVeryLongModulePath", CLASSPATH_PROJECT_CONTENT_PATH.toString(), JavaProjectHelper.JAVA_SE_9_EE_NAME, true);
useComplianceFromExecutionEnvironment(javaProject);
useModuleForJREContainer(javaProject);
launchConfiguration = createLaunchConfigurationStopInMain(javaProject, MAIN_TYPE_NAME);
int minModulePathLength = 300000;
setLongModulepath(javaProject, minModulePathLength);
waitForBuild();
// When
thread = launchAndSuspend(launchConfiguration);
// Then
File tempFile = getTempFile(thread.getLaunch()).orElseThrow(() -> new RuntimeException("No temp file"));
assertTrue(tempFile.exists());
assertTrue(tempFile.getName().endsWith(".txt"));
assertTrue(doEval(thread, "System.getProperty(\"jdk.module.path\")").getValueString().length() >= minModulePathLength);
// When
resumeAndExit(thread);
// Then
if (!Platform.getOS().equals(Platform.OS_WIN32)) {
// On windows, temp file deletion may fail
assertFalse(tempFile.exists());
}
}
private ILaunchConfiguration createLaunchConfigurationStopInMain(IJavaProject javaProject, String mainTypeName) throws Exception, CoreException {
ILaunchConfiguration launchConfiguration;
launchConfiguration = createLaunchConfiguration(javaProject, mainTypeName);
ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy();
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, true);
launchConfiguration = wc.doSave();
return launchConfiguration;
}
private void setLongModulepath(IJavaProject javaProject, int minModulePathLength) throws Exception {
StringBuilder sb = new StringBuilder();
List<IClasspathEntry> classpathEntries = new ArrayList<>();
int i = 0;
while (sb.length() < minModulePathLength) {
String jarName = "library" + i + ".jar";
IPath targetPath = javaProject.getPath().append("lib/" + jarName);
javaProject.getProject().getFile("lib/classpath.jar").copy(targetPath, IResource.FORCE, new NullProgressMonitor());
IClasspathAttribute moduleClasspathAttribute = JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true");
classpathEntries.add(JavaCore.newLibraryEntry(targetPath, null, null, null, new IClasspathAttribute[] {
moduleClasspathAttribute }, false));
if (i != 0) {
sb.append(File.pathSeparator);
}
sb.append(javaProject.getProject().getFile("lib/" + jarName).getLocation().toString());
i++;
}
IClasspathAttribute moduleClasspathAttribute = JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true");
classpathEntries.add(JavaCore.newLibraryEntry(javaProject.getPath().append("lib/classpath.jar"), null, null, null, new IClasspathAttribute[] {
moduleClasspathAttribute }, false));
sb.append(File.pathSeparator);
sb.append(javaProject.getProject().getFile("lib/classpath.jar").getLocation().toString());
classpathEntries.addAll(Arrays.asList(javaProject.getRawClasspath()));
javaProject.setRawClasspath(classpathEntries.toArray(new IClasspathEntry[classpathEntries.size()]), null);
}
private void useComplianceFromExecutionEnvironment(IJavaProject javaProject) throws JavaModelException {
IExecutionEnvironment executionEnvironment = getExecutionEnvironment(javaProject);
Map<String, String> eeOptions = BuildPathSupport.getEEOptions(executionEnvironment);
eeOptions.forEach((optionName, optionValue) -> javaProject.setOption(optionName, optionValue));
}
private IExecutionEnvironment getExecutionEnvironment(IJavaProject javaProject) throws JavaModelException {
IClasspathEntry[] entries = javaProject.getRawClasspath();
for (int i = 0; i < entries.length; i++) {
IClasspathEntry entry = entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
String eeId = JavaRuntime.getExecutionEnvironmentId(entry.getPath());
if (eeId != null) {
return JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(eeId);
}
}
}
return null;
}
private void useModuleForJREContainer(IJavaProject javaProject) throws JavaModelException {
IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
for (int i = 0; i < rawClasspath.length; i++) {
IClasspathEntry classpathEntry = rawClasspath[i];
if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
IClasspathAttribute moduleClasspathAttribute = JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true");
classpathEntry = JavaCore.newContainerEntry(classpathEntry.getPath(), classpathEntry.getAccessRules(), new IClasspathAttribute[] {
moduleClasspathAttribute }, classpathEntry.isExported());
rawClasspath[i] = classpathEntry;
}
}
javaProject.setRawClasspath(rawClasspath, null);
}
private Optional<File> getTempFile(ILaunch launch) {
IProcess process = launch.getProcesses()[0];
String tempFile = process.getAttribute(LaunchingPlugin.ATTR_LAUNCH_TEMP_FILES);
if (tempFile == null) {
return Optional.empty();
}
return Optional.of(new File(tempFile));
}
}