diff --git a/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml b/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml new file mode 100644 index 000000000..8cb98da5f --- /dev/null +++ b/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml @@ -0,0 +1,105 @@ + + 4.0.0 + TMP + TMP + 0.0.1-SNAPSHOT + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.0 + + + default-test + test + + test + + + + + -Xshare:off + -Djdk.net.URLClassPath.disableClassPathURLCheck=true + @{jacoco.surefireArgLine} @{titi.tata} + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + coverage-prepare-agent + + prepare-agent + + + + jacoco.surefireArgLine + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + jacoco-maven-plugin + [0.0.0,) + + prepare-agent + + + + + true + + + + + + + + + + + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter + test + + + \ No newline at end of file diff --git a/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java index e3f24fcc8..3d98a8f20 100644 --- a/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java +++ b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java @@ -56,26 +56,30 @@ public class UnitTestLaunchConfigConfigurationTest extends AbstractMavenProjectT private static final String SUREFIRE_ARGS_SET = """ - --argLineItem=surefireArgLineValue + --argLineItem=surefireArgLineValue --undefinedArgLineItem=${undefinedProperty} surefireProp1Value + ${undefinedProperty} surefireEnvironmentVariables1Value + ${undefinedProperty} """; private static final String FAILSAFE_ARGS_SET = """ - --argLineItem=failsafeArgLineValue + --argLineItem=failsafeArgLineValue --undefinedArgLineItem=${undefinedProperty} failsafeProp1Value + ${undefiniedProperty} failsafeEnvironmentVariables1Value + ${undefinedProperty} """; @@ -144,6 +148,10 @@ public void test_configuration_must_be_updated_with_surefire_config() // check systemPropertyVariables assertTrue(argLine.contains("-DsurefireProp1=surefireProp1Value")); + + // check systemPropertyVariables with null value aren't set + assertTrue(!argLine.contains("-DsurefireEmptyProp=")); + } @Test @@ -193,6 +201,9 @@ public void test_configuration_must_be_updated_with_failsafe_config() // check systemPropertyVariables assertTrue(argLine.contains("-DfailsafeProp1=failsafeProp1Value")); + + // check systemPropertyVariables with null value aren't set + assertTrue(!argLine.contains("-DfailsafeEmptyProp=")); } @Test @@ -279,6 +290,32 @@ public void test_configuration_must_be_updated_with_failSafe_config_when_created assertTrue(argLine.contains("-DfailsafeProp1=failsafeProp1Value")); } + @Test + public void test_deferred_variable_are_resolved() throws CoreException, IOException, InterruptedException { + // Get launch type + ILaunchConfigurationType type = LAUNCH_MANAGER.getLaunchConfigurationType(testType); + + assumeTrue(testType + " support not available", type != null); + + File pomFile = getTestFile("deferredVariables/pom.xml"); + + IProject project = importProject(pomFile.getAbsolutePath()); + + // create basic unit test + createDefaultTest(project, type, "test.SomeTest"); + + updateProject(project); + waitForJobsToComplete(); + + ILaunchConfiguration[] updatedConfigurations = LAUNCH_MANAGER.getLaunchConfigurations(type); + assertTrue(updatedConfigurations.length == 1); + + ILaunchConfiguration config = updatedConfigurations[0]; + String argLine = config.getAttribute(UnitTestSupport.LAUNCH_CONFIG_VM_ARGUMENTS, ""); + assertTrue(argLine.contains("-javaagent")); // resolved jacoco agent + assertTrue(argLine.contains("@{titi.tata}")); // unresolved property is unchanged as in CLI + } + private void updateProject(IProject project) throws CoreException, InterruptedException { MavenPlugin.getProjectConfigurationManager().updateProjectConfiguration(project, monitor); waitForJobsToComplete(); diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java index e57f9e737..7b21dac9a 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java @@ -24,8 +24,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Properties; import java.util.Set; import java.util.StringJoiner; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -143,6 +146,11 @@ public class UnitTestSupport { */ private static final String FAILSAFE_PLUGIN_ARTIFACT_ID = "maven-failsafe-plugin"; + /** + * deffered variable pattern + */ + private static final Pattern DEFERRED_VAR_PATTERN = Pattern.compile("@\\{(.*?)\\}"); + /** * maven group id for the maven plugins */ @@ -271,7 +279,9 @@ private void defineConfigurationValues(IProject project, ILaunchConfiguration co launchArguments.add(args.argLine()); } if(args.systemPropertyVariables() != null) { - args.systemPropertyVariables().forEach((key, value) -> launchArguments.add("-D" + key + "=" + value)); + args.systemPropertyVariables().entrySet().stream() // + .filter(e -> e.getKey() != null && e.getValue() != null) + .forEach(e -> launchArguments.add("-D" + e.getKey() + "=" + e.getValue())); } copy.setAttribute(LAUNCH_CONFIG_VM_ARGUMENTS, launchArguments.toString()); @@ -287,7 +297,10 @@ private void defineConfigurationValues(IProject project, ILaunchConfiguration co } if(args.environmentVariables() != null) { - copy.setAttribute(LAUNCH_CONFIG_ENVIRONMENT_VARIABLES, args.environmentVariables()); + Map filteredMap = args.environmentVariables().entrySet().stream() + .filter(entry -> entry.getKey() != null && entry.getValue() != null) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + copy.setAttribute(LAUNCH_CONFIG_ENVIRONMENT_VARIABLES, filteredMap); } copy.doSave(); @@ -398,8 +411,11 @@ private TestLaunchArguments getTestLaunchArguments(MavenProject mavenProject, Mo IProgressMonitor monitor) { try { IMaven maven = MavenPlugin.getMaven(); - return new TestLaunchArguments( - maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ARGLINE, String.class, monitor), + + String argLine = maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ARGLINE, String.class, monitor); + argLine = resolveDeferredVariables(mavenProject, argLine); + + return new TestLaunchArguments(argLine, maven.getMojoParameterValue(mavenProject, execution, PLUGIN_SYSPROP_VARIABLES, Map.class, monitor), maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ENVIRONMENT_VARIABLES, Map.class, monitor), maven.getMojoParameterValue(mavenProject, execution, PLUGIN_WORKING_DIRECTORY, File.class, monitor), @@ -412,6 +428,29 @@ private TestLaunchArguments getTestLaunchArguments(MavenProject mavenProject, Mo } + /** + * This method is used to resolve deferred variables introduced by failsafe/surefire plugins in a given string value. + * Deferred variables are placeholders in the string that are replaced with actual values from the Maven project's + * properties. The placeholders are in the format @{...}, where ... is the key of the property. If a placeholder's + * corresponding property does not exist, the placeholder is left as is. + * + * @param mavenProject the Maven project from which to retrieve the properties + * @param value the string containing the placeholders to be replaced + * @return the string with all resolvable placeholders replaced with their corresponding property values + */ + private static String resolveDeferredVariables(MavenProject mavenProject, String value) { + Properties properties = mavenProject.getProperties(); + if(properties.isEmpty() || value == null) { + return value; + } + return DEFERRED_VAR_PATTERN.matcher(value).replaceAll(match -> { + String placeholder = match.group(); + String key = match.group(1); + String replacement = properties.getProperty(key); + return replacement != null ? replacement : placeholder; + }); + } + /** * Holder for the surefire/failsafe launch arguments */