package org.testng.eclipse.maven; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; import org.apache.maven.model.BuildBase; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; import org.apache.maven.model.PluginManagement; import org.apache.maven.model.Profile; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.interpolation.EnvarBasedValueSource; import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.PrefixedObjectValueSource; import org.codehaus.plexus.interpolation.PropertiesBasedValueSource; import org.codehaus.plexus.interpolation.RegexBasedInterpolator; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.profiles.core.internal.IProfileManager; import org.eclipse.m2e.profiles.core.internal.MavenProfilesCoreActivator; import org.eclipse.m2e.profiles.core.internal.ProfileData; import org.eclipse.m2e.profiles.core.internal.ProfileState; import org.testng.eclipse.launch.ITestNGLaunchConfigurationProvider; import org.testng.eclipse.launch.LaunchConfigurationHelper; public class MavenTestNGLaunchConfigurationProvider implements ITestNGLaunchConfigurationProvider { public static final Pattern PATTERN = Pattern.compile("\\$\\{([^}]+)\\}"); @Override public String getVmArguments(ILaunchConfiguration launchConf) throws CoreException { IProject project = LaunchConfigurationHelper.getProject(launchConf); if (PreferenceUtils.getBoolean(project, Activator.PREF_ARGLINE) || PreferenceUtils.getBoolean(project, Activator.PREF_SYSPROPERTIES)) { String vmArgs = getVMArgsFromPom(launchConf); return vmArgs; } return null; } @Override public List<String> getEnvironment(ILaunchConfiguration launchConf) throws CoreException { IProject project = LaunchConfigurationHelper.getProject(launchConf); if (project == null || !project.hasNature(IMavenConstants.NATURE_ID)) { return null; } IMavenProjectFacade prjFecade = MavenPlugin.getMavenProjectRegistry().getProject(project); if (prjFecade == null) { throw new CoreException(Activator.createError(project.getName() + " is not in Maven project registry.")); } IProfileManager profileManager = MavenProfilesCoreActivator.getDefault().getProfileManager(); List<ProfileData> profiles = profileManager.getProfileDatas(prjFecade, new NullProgressMonitor()); Model model = MavenPlugin.getMavenModelManager().readMavenModel(prjFecade.getPom()); Xpp3Dom confDom = findPluginConfiguration(model, profiles); if (confDom != null) { if (PreferenceUtils.getBoolean(project, Activator.PREF_ENVIRON)) { Xpp3Dom envDom = confDom.getChild("environmentVariables"); if (envDom != null) { List<String> environList = new ArrayList<>(envDom.getChildCount()); for (Xpp3Dom varDom : envDom.getChildren()) { environList.add(varDom.getName() + "=" + varDom.getValue()); } return environList; } } } return null; } @SuppressWarnings("restriction") private String getVMArgsFromPom(ILaunchConfiguration launchConf) throws CoreException { IProject project = LaunchConfigurationHelper.getProject(launchConf); if (project == null || !project.hasNature(IMavenConstants.NATURE_ID)) { return null; } IMavenProjectFacade prjFecade = MavenPlugin.getMavenProjectRegistry().getProject(project); if (prjFecade == null) { throw new CoreException(Activator.createError(project.getName() + " is not in Maven project registry.")); } MavenProject mvnProject = prjFecade.getMavenProject(new NullProgressMonitor()); IProfileManager profileManager = MavenProfilesCoreActivator.getDefault().getProfileManager(); List<ProfileData> selectedProfiles = profileManager.getProfileDatas(prjFecade, new NullProgressMonitor()); Model model = mvnProject.getModel(); Xpp3Dom confDom = findPluginConfiguration(model, selectedProfiles); if (confDom != null) { StringBuilder sb = new StringBuilder(); if (PreferenceUtils.getBoolean(project, Activator.PREF_ARGLINE)) { Xpp3Dom argDom = confDom.getChild("argLine"); if (argDom != null) { sb.append(argDom.getValue()); } } if (PreferenceUtils.getBoolean(project, Activator.PREF_SYSPROPERTIES)) { Xpp3Dom propDom = confDom.getChild("systemPropertyVariables"); if (propDom != null) { for (Xpp3Dom pDom : propDom.getChildren()) { sb.append(" -D").append(pDom.getName()).append("=").append(pDom.getValue()); } } } String vmArgs = sb.toString(); vmArgs = resolve(vmArgs, mvnProject, selectedProfiles, prjFecade); return vmArgs; } return null; } /** * find the configuration of maven-surefire-plugin and/or * maven-failsafe-plugin. * * @param model * the Maven POM model * @return {@code null} if not found */ @SuppressWarnings("restriction") private Xpp3Dom findPluginConfiguration(Model model, List<ProfileData> selectedProfiles) { Xpp3Dom pluginConf = null; // found from selected profiles first, if anyone matched, use and return it. if (selectedProfiles != null) { for (ProfileData pd : selectedProfiles) { if (pd.getActivationState() == ProfileState.Active) { List<Profile> profiles = model.getProfiles(); if (profiles != null) { for (Profile profile : profiles) { if (pd.getId().equals(profile.getId())) { pluginConf = findPluginConfiguration(profile.getBuild()); if (pluginConf != null) { return pluginConf; } } } } } } } // otherwise, found from project build base pluginConf = findPluginConfiguration(model.getBuild()); return pluginConf; } private Xpp3Dom findPluginConfiguration(BuildBase build) { if (build == null) { return null; } // first, find from project plugins List<Plugin> plugins = build.getPlugins(); Xpp3Dom pluginConf = findPluginConfiguration(plugins); // otherwise, find from project pluginManagement if (pluginConf == null) { PluginManagement pluginMgnt = build.getPluginManagement(); if (pluginMgnt != null) { plugins = pluginMgnt.getPlugins(); pluginConf = findPluginConfiguration(plugins); } } return pluginConf; } private Xpp3Dom findPluginConfiguration(List<Plugin> plugins) { if (plugins != null) { for (Plugin plugin : plugins) { if ("maven-surefire-plugin".equals(plugin.getArtifactId()) || "maven-failsafe-plugin".equals(plugin.getArtifactId())) { Object mvnPlugConf = plugin.getConfiguration(); if (isTargetConfiguration(mvnPlugConf)) { return (Xpp3Dom) mvnPlugConf; } else { List<PluginExecution> pexecs = plugin.getExecutions(); if (pexecs != null) { for (PluginExecution pexec : pexecs) { mvnPlugConf = pexec.getConfiguration(); if (isTargetConfiguration(mvnPlugConf)) { return (Xpp3Dom) mvnPlugConf; } } } } } } } return null; } /** * the configuration node is trade as target one if one of the condition * satisfied: * <ul> * <li>if it has argLine and it's not empty</li> * <li>or, if it has systemPropertyVariables and it contains children</li> * <li>or, if it has environmentVariables and it contains children</li> </ul * * @param configuration * @return {@code true} if found */ private boolean isTargetConfiguration(Object configuration) { if (configuration != null && configuration instanceof Xpp3Dom) { Xpp3Dom dom = ((Xpp3Dom) configuration); Xpp3Dom d = dom.getChild("argLine"); if (d != null && !d.getValue().trim().isEmpty()) { return true; } d = dom.getChild("systemPropertyVariables"); if (d != null && d.getChildCount() > 0) { return true; } d = dom.getChild("environmentVariables"); if (d != null && d.getChildCount() > 0) { return true; } } return false; } private String resolve(String text, MavenProject mvnProject, List<ProfileData> selectedProfiles, IMavenProjectFacade prjFecade) throws CoreException { if (text == null) { return text; } if (!text.contains("${")) { return text; } RegexBasedInterpolator inter = new RegexBasedInterpolator(); Model model = mvnProject.getModel(); Properties profileProperties = collectProperties(model, selectedProfiles, prjFecade); try { inter.addValueSource(new PropertiesBasedValueSource(profileProperties)); inter.addValueSource(new EnvarBasedValueSource()); inter.addValueSource(new PrefixedObjectValueSource(Arrays.asList(new String[] { "pom.", "project." }), //$NON-NLS-1$ //$NON-NLS-2$ model, false)); inter.addValueSource(new PrefixedObjectValueSource("settings.", MavenPlugin.getMaven().getSettings())); text = inter.interpolate(text); } catch (IOException | InterpolationException e) { Activator.log("interpolate [" + text + "] failed: " + e.getMessage(), e); } return text; } @SuppressWarnings("restriction") private Properties collectProperties(Model model, List<ProfileData> selectedProfiles, IMavenProjectFacade project) { Properties result = new Properties(); // // basic properties // // sometimes we don't have 'localRepository' defined in ~/.m2/settings.xml, // so we trade it as a special case. result.put("settings.localRepository", MavenPlugin.getMaven().getLocalRepositoryPath()); result.put("basedir", project.getFullPath().toOSString()); // // project base properties // // actually we don't really need this since Maven model already // resolves the property placehoder at project level. result.putAll(model.getProperties()); // // profile base properties could override the project level properties/ // if (selectedProfiles != null) { for (ProfileData pd : selectedProfiles) { if (pd.getActivationState() == ProfileState.Active) { List<Profile> profiles = model.getProfiles(); if (profiles != null) { for (Profile profile : profiles) { if (pd.getId().equals(profile.getId())) { result.putAll(profile.getProperties()); } } } } } } return result; } }