package org.testng.eclipse.launch;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
import org.eclipse.jdt.launching.AbstractVMInstall;
import org.eclipse.jdt.launching.ExecutionArguments;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMRunner;
import org.eclipse.jdt.launching.SocketUtil;
import org.eclipse.jdt.launching.VMRunnerConfiguration;
import org.osgi.framework.Version;
import org.testng.CommandLineArgs;
import org.testng.ITestNGListener;
import org.testng.eclipse.TestNGPlugin;
import org.testng.eclipse.TestNGPluginConstants;
import org.testng.eclipse.launch.TestNGLaunchConfigurationConstants.LaunchType;
import org.testng.eclipse.launch.TestNGLaunchConfigurationConstants.Protocols;
import org.testng.eclipse.ui.util.ConfigurationHelper;
import org.testng.eclipse.util.ListenerContributorUtil;
import org.testng.eclipse.util.PreferenceStoreUtil;
import org.testng.eclipse.util.ResourceUtil;
import org.testng.eclipse.util.StringUtils;
import org.testng.remote.RemoteArgs;
import org.testng.remote.RemoteTestNG;
import org.testng.xml.LaunchSuite;
import static org.testng.eclipse.buildpath.BuildPathSupport.getBundleFile;
public class TestNGLaunchConfigurationDelegate
extends AbstractJavaLaunchConfigurationDelegate {
private static final Version mimJvmVer = new Version("1.7.0"); //$NON-NLS-1$
/**
* Launch RemoteTestNG (except if we're in debug mode).
*/
public void launch(ILaunchConfiguration configuration, String mode,
ILaunch launch, IProgressMonitor monitor) throws CoreException {
IJavaProject javaProject = getJavaProject(configuration);
if ((javaProject == null) || !javaProject.exists()) {
abort(
ResourceUtil.getString(
"TestNGLaunchConfigurationDelegate.error.invalidproject"), //$NON-NLS-1$
null, IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT);
}
IVMInstall install = getVMInstall(configuration);
IVMRunner runner = install.getVMRunner(mode);
if (runner == null) {
abort(
ResourceUtil.getFormattedString(
"TestNGLaunchConfigurationDelegate.error.novmrunner", //$NON-NLS-1$
new String[] { install.getName() }),
null, IJavaLaunchConfigurationConstants.ERR_VM_RUNNER_DOES_NOT_EXIST);
}
AbstractVMInstall vmi = (AbstractVMInstall) install;
String jreVer = vmi.getJavaVersion();
if (jreVer == null) {
abort(
ResourceUtil.getFormattedString(
"TestNGLaunchConfigurationDelegate.error.unknownjre", //$NON-NLS-1$
new String[] { install.getName() }),
null, TestNGPluginConstants.LAUNCH_ERROR_JVM_VER_UNKNOWN);
}
Version vmVer = new Version(jreVer);
if (compareVersion(vmVer, mimJvmVer) < 0) {
abort(
ResourceUtil.getFormattedString(
"TestNGLaunchConfigurationDelegate.error.incompatiblevmversion", //$NON-NLS-1$
new String[] { jreVer }),
null, TestNGPluginConstants.LAUNCH_ERROR_JVM_VER_NOT_COMPATIBLE);
}
int port = SocketUtil.findFreePort();
VMRunnerConfiguration runConfig = launchTypes(configuration, launch,
javaProject, port, mode);
setDefaultSourceLocator(launch, configuration);
launch.setAttribute(TestNGLaunchConfigurationConstants.PORT,
Integer.toString(port));
launch.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
javaProject.getElementName());
launch.setAttribute(TestNGLaunchConfigurationConstants.TESTNG_RUN_NAME_ATTR,
getRunNameAttr(configuration));
StringBuilder sb = new StringBuilder();
for (String arg : runConfig.getProgramArguments()) {
sb.append(arg).append(" ");
}
TestNGPlugin
.log("[TestNGLaunchConfigurationDelegate] " + debugConfig(runConfig));
runner.run(runConfig, launch, monitor);
}
private static String join(String[] strings) {
return join(strings, " ");
}
private static String join(String[] strings, String sep) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strings.length; i++) {
if (i > 0)
sb.append(sep);
sb.append(strings[i]);
}
return sb.toString();
}
private String debugConfig(VMRunnerConfiguration config) {
StringBuilder sb = new StringBuilder("Launching:");
sb.append("\n Classpath: " + join(config.getClassPath()));
sb.append("\n VMArgs: " + join(config.getVMArguments()));
sb.append("\n Class: " + config.getClassToLaunch());
sb.append("\n Args: " + join(config.getProgramArguments()));
sb.append("\n");
sb.append("java " + join(config.getVMArguments()) + " -classpath "
+ join(config.getClassPath(), ":") + " " + config.getClassToLaunch()
+ " " + join(config.getProgramArguments()));
return sb.toString();
}
private static void p(String s) {
if (TestNGPlugin.isVerbose()) {
System.out.println("[TestNGLaunchConfigurationDelegate] " + s);
}
}
protected VMRunnerConfiguration launchTypes(
final ILaunchConfiguration configuration, ILaunch launch,
final IJavaProject jproject, final int port, final String mode)
throws CoreException {
File workingDir = verifyWorkingDirectory(configuration);
String workingDirName = null;
if (workingDir != null) {
workingDirName = workingDir.getAbsolutePath();
}
// Program & VM args
ExecutionArguments execArgs = new ExecutionArguments(
ConfigurationHelper.getJvmArgs(configuration), ""); //$NON-NLS-1$
VMRunnerConfiguration runConfig = createVMRunner(configuration, launch,
jproject, port, mode);
runConfig.setVMArguments(execArgs.getVMArgumentsArray());
runConfig.setWorkingDirectory(workingDirName);
runConfig.setEnvironment(getEnvironment(configuration));
Map<String, Object> vmAttributesMap = getVMSpecificAttributesMap(
configuration);
runConfig.setVMSpecificAttributesMap(vmAttributesMap);
String[] bootpath = getBootpath(configuration);
runConfig.setBootClassPath(bootpath);
return runConfig;
}
@Override
public String getMainTypeName(ILaunchConfiguration configuration)
throws CoreException {
return "org.testng.remote.RemoteTestNG";
}
/**
* This class creates the parameters to launch RemoteTestNG with the correct
* parameters.
*
* Add a VMRunner with a class path that includes org.eclipse.jdt.junit
* plugin. In addition it adds the port for the RemoteTestRunner as an
* argument.
*/
protected VMRunnerConfiguration createVMRunner(
final ILaunchConfiguration configuration, ILaunch launch,
final IJavaProject jproject, final int port, final String runMode)
throws CoreException {
String[] classPath = getClasspath(configuration);
String progArgs = getProgramArguments(configuration);
VMRunnerConfiguration vmConfig = new VMRunnerConfiguration(
getMainTypeName(configuration), classPath);
// insert the program arguments
List<String> argv = new ArrayList<>(10);
ExecutionArguments execArgs = new ExecutionArguments("", progArgs); //$NON-NLS-1$
String[] pa = execArgs.getProgramArgumentsArray();
for (String element : pa) {
argv.add(element);
}
// Use -serPort (serialized protocol) or -port (string protocol) based on
// a system property
Protocols protocol = ConfigurationHelper.getProtocol(configuration);
switch (protocol) {
case STRING:
p("Using the string protocol");
argv.add(CommandLineArgs.PORT);
break;
case OBJECT:
p("Using the object serialization protocol");
case JSON:
p("Using the json serialization protocol");
argv.add(RemoteArgs.PORT);
break;
}
argv.add(Integer.toString(port));
argv.add(RemoteArgs.PROTOCOL);
argv.add(protocol.toString());
IProject project = jproject.getProject();
// if (!isJDK15(javaVersion)) {
// List<File> sourceDirs = JDTUtil.getSourceDirFileList(jproject);
// if (null != sourceDirs) {
// argv.add(TestNGCommandLineArgs.SRC_COMMAND_OPT);
// argv.add(Utils.toSinglePath(sourceDirs, ";")); //$NON-NLS-1$
// }
// }
PreferenceStoreUtil storage = TestNGPlugin.getPluginPreferenceStore();
argv.add(CommandLineArgs.OUTPUT_DIRECTORY);
argv.add(storage.getOutputAbsolutePath(jproject).toOSString());
// String reporters = storage.getReporters(project.getName(), false);
// if (null != reporters && !"".equals(reporters)) {
// argv.add(TestNGCommandLineArgs.LISTENER_COMMAND_OPT);
// argv.add(reporters.replace(' ', ';'));
// }
String preDefinedListeners = configuration.getAttribute(
TestNGLaunchConfigurationConstants.PRE_DEFINED_LISTENERS, "");
if (!preDefinedListeners.trim().equals("")) {
if (!argv.contains(CommandLineArgs.LISTENER)) {
argv.add(CommandLineArgs.LISTENER);
argv.add(preDefinedListeners);
} else {
String listeners = argv.get(argv.size() - 1);
listeners += (";" + preDefinedListeners);
argv.set(argv.size() - 1, listeners);
}
}
List<ITestNGListener> contributors = ListenerContributorUtil
.findReporterContributors();
contributors.addAll(ListenerContributorUtil.findTestContributors());
StringBuffer reportersContributors = new StringBuffer();
boolean isFirst = true;
for (ITestNGListener contributor : contributors) {
if (isFirst) {
reportersContributors.append(contributor.getClass().getName());
} else {
reportersContributors.append(";" + contributor.getClass().getName());
}
isFirst = false;
}
if (!reportersContributors.toString().trim().equals("")) {
if (!argv.contains(CommandLineArgs.LISTENER)) {
argv.add(CommandLineArgs.LISTENER);
argv.add(reportersContributors.toString().trim());
} else {
String listeners = argv.get(argv.size() - 1);
listeners += (";" + reportersContributors.toString().trim());
argv.set(argv.size() - 1, listeners);
}
}
boolean disabledReporters = storage.hasDisabledListeners(project.getName(),
false);
if (disabledReporters) {
argv.add(CommandLineArgs.USE_DEFAULT_LISTENERS);
argv.add("false");
}
List<LaunchSuite> launchSuiteList = ConfigurationHelper
.getLaunchSuites(jproject, configuration);
List<String> suiteList = new ArrayList<String>();
List<String> tempSuites = new ArrayList<String>();
// Regular mode: generate a new random suite path
File suiteDir = TestNGPlugin.isDebug()
? new File(RemoteTestNG.DEBUG_SUITE_DIRECTORY)
: TestNGPlugin.getPluginPreferenceStore().getTemporaryDirectory();
for (LaunchSuite launchSuite : launchSuiteList) {
File suiteFile = launchSuite.save(suiteDir);
suiteList.add(suiteFile.getAbsolutePath());
if (launchSuite.isTemporary()) {
suiteFile.deleteOnExit();
tempSuites.add(suiteFile.getAbsolutePath());
}
}
if (null != suiteList) {
for (String suite : suiteList) {
argv.add(suite);
}
launch.setAttribute(TestNGLaunchConfigurationConstants.TEMP_SUITE_LIST,
StringUtils.listToString(tempSuites));
}
vmConfig.setProgramArguments(argv.toArray(new String[argv.size()]));
return vmConfig;
}
@Override
public String[] getClasspath(ILaunchConfiguration configuration)
throws CoreException {
String[] cp = super.getClasspath(configuration);
String[] allCp = new String[cp.length + 1];
allCp[0] = getBundleFile("lib/testng-remote.jar").toOSString();
System.arraycopy(cp, 0, allCp, 1, cp.length);
return allCp;
}
@Override
public String[] getEnvironment(ILaunchConfiguration configuration)
throws CoreException {
List<String> result = new ArrayList<>();
String[] base = super.getEnvironment(configuration);
if (base != null && base.length > 0) {
result.addAll(Arrays.asList(base));
}
for (ITestNGLaunchConfigurationProvider lcp : TestNGPlugin
.getLaunchConfigurationProviders()) {
List<String> environs = lcp.getEnvironment(configuration);
if (environs != null && environs.size() > 0) {
result.addAll(environs);
}
}
if (result.isEmpty()) {
// fixed #198, return null rather than empty array
// see also: https://bugs.openjdk.java.net/browse/JDK-4902796
return null;
}
return result.toArray(new String[result.size()]);
}
private String getRunNameAttr(ILaunchConfiguration configuration) {
LaunchType runType = ConfigurationHelper.getType(configuration);
switch (runType) {
case SUITE:
return "suite";
case GROUP:
return "groups";
case PACKAGE:
return "package";
case CLASS:
return "class " + configuration.getName();
case METHOD:
return "method " + configuration.getName();
default:
return "from context";
}
}
private static int compareVersion(Version v1, Version v2)
throws CoreException {
try {
// Works on Eclipse 3.7 or newer
return v1.compareTo(v2);
} catch (NoSuchMethodError e) {
// Works on Eclipse 3.6 and earlier
try {
Method compareToMethod = Version.class.getMethod("compareTo",
Object.class);
return (int) compareToMethod.invoke(v1, v2);
} catch (NoSuchMethodException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e2) {
throw new CoreException(TestNGPlugin.createError(e2));
}
}
}
}