You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2020/05/16 19:10:57 UTC

[maven-surefire] branch master updated (218de3c -> 13ff548)

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.


    from 218de3c  included H35
     new feb0efc  [SUREFIRE-1570] Maven-fail-safe doesn't put testing JPMS module on module path
     new d44122a  improved coverage in getEffectiveJvm()
     new 13ff548  support Windows in Surefire1295AttributeJvmCrashesToTestsIT

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../maven/plugin/failsafe/IntegrationTestMojo.java |   6 +-
 .../plugin/failsafe/IntegrationTestMojoTest.java   |  10 +-
 .../plugin/surefire/AbstractSurefireMojo.java      | 116 ++++++----
 .../maven/plugin/surefire/JdkAttributes.java       |  21 +-
 ...tributes.java => ResolvePathResultWrapper.java} |  28 +--
 .../surefire/SurefireExecutionParameters.java      |   4 +-
 .../booterclient/DefaultForkConfiguration.java     |   2 +-
 .../plugin/surefire/booterclient/Platform.java     |   2 +-
 .../AbstractSurefireMojoJava7PlusTest.java         |  16 +-
 .../plugin/surefire/AbstractSurefireMojoTest.java  | 233 ++++++++++++++++++++-
 .../AbstractSurefireMojoToolchainsTest.java        |  77 ++++++-
 .../maven/plugin/surefire/MojoMocklessTest.java    |   4 +-
 .../apache/maven/plugin/surefire/module-info.class | Bin 0 -> 149 bytes
 .../maven/plugin/surefire/SurefirePlugin.java      |   6 +-
 .../Surefire1295AttributeJvmCrashesToTestsIT.java  |   6 +-
 ...5IT.java => Surefire1570ModularFailsafeIT.java} |  30 ++-
 .../src/test/java/{ => java9/full/api}/J9IT.java   |   2 +
 .../src/test/java/{ => java9/full/api}/J9Test.java |   2 +
 .../resources/surefire-1570/com.foo.api}/pom.xml   |  29 ++-
 .../src/main/java/com/foo/api/SomeInterface.java   |   5 +-
 .../com.foo.api}/src/main/java/module-info.java    |   9 +-
 .../com.foo.impl}/pom.xml                          |  84 ++++----
 .../src/main/java/com/foo/impl/Bar.java            |  44 ++--
 .../com.foo.impl}/src/main/java/module-info.java   |   7 +-
 .../src/test/java/com/foo/impl/BarIT.java}         |  21 +-
 .../src/test/java/com/foo/impl/BarTest.java}       |  21 +-
 .../src/test/resources/surefire-1570/pom.xml       | 101 +++++++++
 27 files changed, 655 insertions(+), 231 deletions(-)
 copy maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/{JdkAttributes.java => ResolvePathResultWrapper.java} (55%)
 create mode 100644 maven-surefire-common/src/test/resources/org/apache/maven/plugin/surefire/module-info.class
 copy surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/{Surefire1585IT.java => Surefire1570ModularFailsafeIT.java} (64%)
 rename surefire-its/src/test/resources/java9-full-api/src/test/java/{ => java9/full/api}/J9IT.java (98%)
 rename surefire-its/src/test/resources/java9-full-api/src/test/java/{ => java9/full/api}/J9Test.java (98%)
 copy {surefire-extensions-spi => surefire-its/src/test/resources/surefire-1570/com.foo.api}/pom.xml (64%)
 copy maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/DataZT1A.java => surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/com/foo/api/SomeInterface.java (90%)
 copy surefire-its/src/test/resources/{surefire-1712-extracted-modulename-without-asm => surefire-1570/com.foo.api}/src/main/java/module-info.java (81%)
 copy surefire-its/src/test/resources/{surefire-1490 => surefire-1570/com.foo.impl}/pom.xml (54%)
 copy surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnitTestFailureListener.java => surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/com/foo/impl/Bar.java (54%)
 copy surefire-its/src/test/resources/{surefire-1712-extracted-modulename-without-asm => surefire-1570/com.foo.impl}/src/main/java/module-info.java (86%)
 copy surefire-its/src/test/resources/{junit-platform/src/test/java/junitplatform/JUnitPlatformTest.java => surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarIT.java} (67%)
 copy surefire-its/src/test/resources/{junit-platform/src/test/java/junitplatform/JUnitPlatformTest.java => surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarTest.java} (67%)
 create mode 100644 surefire-its/src/test/resources/surefire-1570/pom.xml


[maven-surefire] 01/03: [SUREFIRE-1570] Maven-fail-safe doesn't put testing JPMS module on module path

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit feb0efc1c73a009c49f22eb2bc0c923a36d78ab6
Author: tibordigana <ti...@apache.org>
AuthorDate: Tue May 12 22:45:04 2020 +0200

    [SUREFIRE-1570] Maven-fail-safe doesn't put testing JPMS module on module path
---
 .../maven/plugin/failsafe/IntegrationTestMojo.java |   6 +-
 .../plugin/failsafe/IntegrationTestMojoTest.java   |  10 +-
 .../plugin/surefire/AbstractSurefireMojo.java      | 116 ++++++----
 .../maven/plugin/surefire/JdkAttributes.java       |  21 +-
 ...tributes.java => ResolvePathResultWrapper.java} |  28 +--
 .../surefire/SurefireExecutionParameters.java      |   4 +-
 .../booterclient/DefaultForkConfiguration.java     |   2 +-
 .../plugin/surefire/booterclient/Platform.java     |   2 +-
 .../AbstractSurefireMojoJava7PlusTest.java         |  16 +-
 .../plugin/surefire/AbstractSurefireMojoTest.java  | 233 ++++++++++++++++++++-
 .../AbstractSurefireMojoToolchainsTest.java        |  22 +-
 .../maven/plugin/surefire/MojoMocklessTest.java    |   4 +-
 .../apache/maven/plugin/surefire/module-info.class | Bin 0 -> 149 bytes
 .../maven/plugin/surefire/SurefirePlugin.java      |   6 +-
 .../its/jiras/Surefire1570ModularFailsafeIT.java   |  54 +++++
 .../src/test/java/{ => java9/full/api}/J9IT.java   |   2 +
 .../src/test/java/{ => java9/full/api}/J9Test.java |   2 +
 .../resources/surefire-1570/com.foo.api/pom.xml    |  51 +++++
 .../src/main/java/com/foo/api/SomeInterface.java   |  28 +--
 .../com.foo.api/src/main/java/module-info.java     |  34 +--
 .../resources/surefire-1570/com.foo.impl/pom.xml   |  85 ++++++++
 .../src/main/java/com/foo/impl/Bar.java            |  41 ++--
 .../com.foo.impl/src/main/java/module-info.java    |  32 +--
 .../src/test/java/com/foo/impl/BarIT.java          |  33 ++-
 .../src/test/java/com/foo/impl/BarTest.java        |  33 ++-
 .../src/test/resources/surefire-1570/pom.xml       | 101 +++++++++
 26 files changed, 722 insertions(+), 244 deletions(-)

diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
index 0e6e26d..71c652b 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
@@ -614,7 +614,7 @@ public class IntegrationTestMojo
      * used instead. See the resolution of {@link #getClassLoaderConfiguration() ClassLoaderConfiguration}.
      */
     @Override
-    public File getClassesDirectory()
+    public File getMainBuildPath()
     {
         File artifact = getProject().getArtifact().getFile();
         boolean isDefaultClsDir = classesDirectory == null;
@@ -622,9 +622,9 @@ public class IntegrationTestMojo
     }
 
     @Override
-    public void setClassesDirectory( File classesDirectory )
+    public void setMainBuildPath( File mainBuildPath )
     {
-        this.classesDirectory = toAbsoluteCanonical( classesDirectory );
+        classesDirectory = toAbsoluteCanonical( mainBuildPath );
     }
 
     public void setDefaultClassesDirectory( File defaultClassesDirectory )
diff --git a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
index c605938..f5edf0b 100644
--- a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
+++ b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
@@ -58,25 +58,25 @@ public class IntegrationTestMojoTest
     public void shouldBeJar()
     {
         mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
-        File binaries = mojo.getClassesDirectory();
+        File binaries = mojo.getMainBuildPath();
         assertThat( binaries.getName() ).isEqualTo( "a-1.0.jar" );
     }
 
     @Test
     public void shouldBeAnotherJar()
     {
-        mojo.setClassesDirectory( new File( "./target/another-1.0.jar" ) );
+        mojo.setMainBuildPath( new File( "./target/another-1.0.jar" ) );
         mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
-        File binaries = mojo.getClassesDirectory();
+        File binaries = mojo.getMainBuildPath();
         assertThat( binaries.getName() ).isEqualTo( "another-1.0.jar" );
     }
 
     @Test
     public void shouldBeClasses()
     {
-        mojo.setClassesDirectory( new File( "./target/classes" ) );
+        mojo.setMainBuildPath( new File( "./target/classes" ) );
         mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
-        File binaries = mojo.getClassesDirectory();
+        File binaries = mojo.getMainBuildPath();
         assertThat( binaries.getName() ).isEqualTo( "classes" );
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 9fa9d88..b1197e1 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -90,6 +90,8 @@ import org.apache.maven.toolchain.DefaultToolchain;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathRequest;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.languages.java.jpms.LocationManager;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
@@ -101,7 +103,6 @@ import java.io.IOException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -909,6 +910,7 @@ public abstract class AbstractSurefireMojo
         cli = commandLineOptions();
         // Stuff that should have been final
         setupStuff();
+        Platform platform = PLATFORM.withJdkExecAttributesForTests( getEffectiveJvm() );
 
         if ( verifyParameters() && !hasExecutedBefore() )
         {
@@ -924,7 +926,7 @@ public abstract class AbstractSurefireMojo
                 return;
             }
             logReportsDirectory();
-            executeAfterPreconditionsChecked( scan );
+            executeAfterPreconditionsChecked( scan, platform );
         }
     }
 
@@ -1136,11 +1138,12 @@ public abstract class AbstractSurefireMojo
         }
     }
 
-    private void executeAfterPreconditionsChecked( @Nonnull DefaultScanResult scanResult )
+    private void executeAfterPreconditionsChecked( @Nonnull DefaultScanResult scanResult, @Nonnull Platform platform )
         throws MojoExecutionException, MojoFailureException
     {
         TestClassPath testClasspath = generateTestClasspath();
         List<ProviderInfo> providers = createProviders( testClasspath );
+        ResolvePathResultWrapper wrapper = findModuleDescriptor( platform.getJdkExecAttributesForTests().getJdkHome() );
 
         RunResult current = noTestsRun();
 
@@ -1149,7 +1152,8 @@ public abstract class AbstractSurefireMojo
         {
             try
             {
-                current = current.aggregate( executeProvider( provider, scanResult, testClasspath ) );
+                current =
+                    current.aggregate( executeProvider( provider, scanResult, testClasspath, platform, wrapper ) );
             }
             catch ( SurefireBooterForkException | SurefireExecutionException | TestSetFailedException e )
             {
@@ -1267,7 +1271,8 @@ public abstract class AbstractSurefireMojo
 
     @Nonnull
     private RunResult executeProvider( @Nonnull ProviderInfo provider, @Nonnull DefaultScanResult scanResult,
-                                       @Nonnull TestClassPath testClasspathWrapper )
+                                       @Nonnull TestClassPath testClasspathWrapper, @Nonnull Platform platform,
+                                       @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult )
         throws MojoExecutionException, MojoFailureException, SurefireExecutionException, SurefireBooterForkException,
         TestSetFailedException
     {
@@ -1278,7 +1283,6 @@ public abstract class AbstractSurefireMojo
         RunOrderParameters runOrderParameters =
             new RunOrderParameters( getRunOrder(), getStatisticsFile( getConfigChecksum() ) );
 
-        Platform platform = PLATFORM.withJdkExecAttributesForTests( getEffectiveJvm() );
         if ( isNotForking() )
         {
             createCopyAndReplaceForkNumPlaceholder( effectiveProperties, 1 ).copyToSystemProperties();
@@ -1289,7 +1293,7 @@ public abstract class AbstractSurefireMojo
         }
         else
         {
-            ForkConfiguration forkConfiguration = createForkConfiguration( platform );
+            ForkConfiguration forkConfiguration = createForkConfiguration( platform, resolvedJavaModularityResult );
             if ( getConsoleLogger().isDebugEnabled() )
             {
                 showMap( getEnvironmentVariables(), "environment variable" );
@@ -1301,8 +1305,8 @@ public abstract class AbstractSurefireMojo
             try
             {
                 forkStarter = createForkStarter( provider, forkConfiguration, classLoaderConfiguration,
-                                                       runOrderParameters, getConsoleLogger(), scanResult, platform,
-                                                       testClasspathWrapper );
+                                                       runOrderParameters, getConsoleLogger(), scanResult,
+                                                       testClasspathWrapper, platform, resolvedJavaModularityResult );
 
                 return forkStarter.run( effectiveProperties, scanResult );
             }
@@ -1377,21 +1381,38 @@ public abstract class AbstractSurefireMojo
         this.dependencyResolver = dependencyResolver;
     }
 
-    private boolean existsModuleDescriptor()
+    private boolean existsModuleDescriptor( ResolvePathResultWrapper resolvedJavaModularityResult )
     {
-        return getModuleDescriptor().isFile();
+        return resolvedJavaModularityResult.getResolvePathResult() != null;
     }
 
-    private File getModuleDescriptor()
+    private ResolvePathResultWrapper findModuleDescriptor( File jdkHome )
     {
-        return new File( getClassesDirectory(), "module-info.class" );
+        File mainBuildPath = getMainBuildPath();
+
+        if ( mainBuildPath.isDirectory() && !new File( mainBuildPath, "module-info.class" ).exists() )
+        {
+            return new ResolvePathResultWrapper( null, true );
+        }
+
+        try
+        {
+            ResolvePathRequest<?> request = ResolvePathRequest.ofFile( mainBuildPath ).setJdkHome( jdkHome );
+            ResolvePathResult result = getLocationManager().resolvePath( request );
+            return new ResolvePathResultWrapper( result.getModuleNameSource() == null ? null : result, true );
+        }
+        catch ( Exception e )
+        {
+            return new ResolvePathResultWrapper( null, true );
+        }
     }
 
-    private boolean canExecuteProviderWithModularPath( Platform platform )
+    private boolean canExecuteProviderWithModularPath( Platform platform,
+                                                       ResolvePathResultWrapper resolvedJavaModularityResult )
     {
         return useModulePath()
                 && platform.getJdkExecAttributesForTests().isJava9AtLeast()
-                && existsModuleDescriptor();
+                && existsModuleDescriptor( resolvedJavaModularityResult );
     }
 
     /**
@@ -1847,26 +1868,20 @@ public abstract class AbstractSurefireMojo
     private StartupConfiguration createStartupConfiguration( @Nonnull ProviderInfo provider, boolean isForking,
                                                              @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
                                                              @Nonnull DefaultScanResult scanResult,
+                                                             @Nonnull TestClassPath testClasspathWrapper,
                                                              @Nonnull Platform platform,
-                                                             @Nonnull TestClassPath testClasspathWrapper )
+                                                             @Nonnull ResolvePathResultWrapper resolvedJavaModularity )
         throws MojoExecutionException
     {
         try
         {
             Set<Artifact> providerArtifacts = provider.getProviderClasspath();
             String providerName = provider.getProviderName();
-            if ( isForking && canExecuteProviderWithModularPath( platform ) )
+            if ( isForking && canExecuteProviderWithModularPath( platform, resolvedJavaModularity ) )
             {
-                String jvmExecutable = platform.getJdkExecAttributesForTests().getJvmExecutable();
-                String javaHome = Paths.get( jvmExecutable )
-                        .toAbsolutePath()
-                        .normalize()
-                        .getParent()
-                        .getParent()
-                        .toString();
-
+                File jdkHome = platform.getJdkExecAttributesForTests().getJdkHome();
                 return newStartupConfigWithModularPath( classLoaderConfiguration, providerArtifacts, providerName,
-                        getModuleDescriptor(), scanResult, javaHome, testClasspathWrapper );
+                    resolvedJavaModularity, scanResult, jdkHome.getAbsolutePath(), testClasspathWrapper );
             }
             else
             {
@@ -1960,9 +1975,9 @@ public abstract class AbstractSurefireMojo
     }
 
     private StartupConfiguration newStartupConfigWithModularPath(
-            @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull Set<Artifact> providerArtifacts,
-            @Nonnull String providerName, @Nonnull File moduleDescriptor, @Nonnull DefaultScanResult scanResult,
-            @Nonnull String javaHome, @Nonnull TestClassPath testClasspathWrapper )
+        @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull Set<Artifact> providerArtifacts,
+        @Nonnull String providerName, @Nonnull ResolvePathResultWrapper moduleDescriptor,
+        @Nonnull DefaultScanResult scanResult, @Nonnull String javaHome, @Nonnull TestClassPath testClasspathWrapper )
             throws IOException
     {
         Classpath testClasspath = testClasspathWrapper.toClasspath();
@@ -1975,7 +1990,7 @@ public abstract class AbstractSurefireMojo
 
         ResolvePathsRequest<String> req = ResolvePathsRequest.ofStrings( testClasspath.getClassPath() )
                 .setJdkHome( javaHome )
-                .setMainModuleDescriptor( moduleDescriptor.getAbsolutePath() );
+                .setModuleDescriptor( moduleDescriptor.getResolvePathResult().getModuleDescriptor() );
 
         ResolvePathsResult<String> result = getLocationManager().resolvePaths( req );
         for ( Entry<String, Exception> entry : result.getPathExceptions().entrySet() )
@@ -2327,12 +2342,13 @@ public abstract class AbstractSurefireMojo
     private ForkStarter createForkStarter( @Nonnull ProviderInfo provider, @Nonnull ForkConfiguration forkConfiguration,
                                            @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
                                            @Nonnull RunOrderParameters runOrderParameters, @Nonnull ConsoleLogger log,
-                                           @Nonnull DefaultScanResult scanResult, @Nonnull Platform platform,
-                                           @Nonnull TestClassPath testClasspathWrapper )
+                                           @Nonnull DefaultScanResult scanResult,
+                                           @Nonnull TestClassPath testClasspathWrapper, @Nonnull Platform platform,
+                                           ResolvePathResultWrapper resolvedJavaModularityResult )
         throws MojoExecutionException, MojoFailureException
     {
         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, true,
-                classLoaderConfiguration, scanResult, platform, testClasspathWrapper );
+                classLoaderConfiguration, scanResult, testClasspathWrapper, platform, resolvedJavaModularityResult );
         String configChecksum = getConfigChecksum();
         StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum, true );
         ProviderConfiguration providerConfiguration = createProviderConfiguration( runOrderParameters );
@@ -2349,7 +2365,7 @@ public abstract class AbstractSurefireMojo
         throws MojoExecutionException, MojoFailureException
     {
         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, false, classLoaderConfig,
-                scanResult, platform, testClasspathWrapper );
+                scanResult, testClasspathWrapper, platform, new ResolvePathResultWrapper( null, true ) );
         String configChecksum = getConfigChecksum();
         StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum, false );
         ProviderConfiguration providerConfiguration = createProviderConfiguration( runOrderParameters );
@@ -2366,7 +2382,8 @@ public abstract class AbstractSurefireMojo
     }
 
     @Nonnull
-    private ForkConfiguration createForkConfiguration( Platform platform )
+    private ForkConfiguration createForkConfiguration( @Nonnull Platform platform,
+                                                       @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult )
     {
         File tmpDir = getSurefireTempDir();
 
@@ -2378,7 +2395,7 @@ public abstract class AbstractSurefireMojo
 
         getConsoleLogger().debug( "Found implementation of fork node factory: " + forkNode.getClass().getName() );
 
-        if ( canExecuteProviderWithModularPath( platform ) )
+        if ( canExecuteProviderWithModularPath( platform, resolvedJavaModularityResult ) )
         {
             return new ModularClasspathForkConfiguration( bootClasspath,
                     tmpDir,
@@ -2516,9 +2533,9 @@ public abstract class AbstractSurefireMojo
 
     private JdkAttributes getEffectiveJvm() throws MojoFailureException
     {
-        if ( isNotEmpty( jvm ) )
+        if ( isNotEmpty( getJvm() ) )
         {
-            File pathToJava = new File( jvm ).getAbsoluteFile();
+            File pathToJava = new File( getJvm() ).getAbsoluteFile();
             if ( !endsWithJavaPath( pathToJava.getPath() ) )
             {
                 throw new MojoFailureException( "Given path does not end with java executor \""
@@ -2533,13 +2550,17 @@ public abstract class AbstractSurefireMojo
             }
 
             File jdkHome = toJdkHomeFromJvmExec( pathToJava.getPath() );
-            if ( !environmentVariables.containsKey( "JAVA_HOME" ) )
+            if ( jdkHome == null )
+            {
+                getConsoleLogger().warning( "Cannot determine JAVA_HOME of jvm exec path " + pathToJava );
+            }
+            else if ( !getEnvironmentVariables().containsKey( "JAVA_HOME" ) )
             {
-                environmentVariables.put( "JAVA_HOME", jdkHome.getAbsolutePath() );
+                getEnvironmentVariables().put( "JAVA_HOME", jdkHome.getAbsolutePath() );
             }
             BigDecimal version = jdkHome == null ? null : toJdkVersionFromReleaseFile( jdkHome );
             boolean javaVersion9 = version == null ? isJava9AtLeast( pathToJava.getPath() ) : isJava9AtLeast( version );
-            return new JdkAttributes( pathToJava.getPath(), javaVersion9 );
+            return new JdkAttributes( pathToJava, jdkHome, javaVersion9 );
         }
 
         if ( toolchain != null )
@@ -2548,6 +2569,7 @@ public abstract class AbstractSurefireMojo
             if ( isNotEmpty( jvmToUse ) )
             {
                 boolean javaVersion9 = false;
+                String jdkHome = null;
 
                 if ( toolchain instanceof DefaultToolchain )
                 {
@@ -2559,9 +2581,10 @@ public abstract class AbstractSurefireMojo
                 if ( toolchain instanceof DefaultJavaToolChain )
                 {
                     DefaultJavaToolChain defaultJavaToolChain = (DefaultJavaToolChain) toolchain;
-                    if ( !environmentVariables.containsKey( "JAVA_HOME" ) )
+                    if ( !getEnvironmentVariables().containsKey( "JAVA_HOME" ) )
                     {
-                        environmentVariables.put( "JAVA_HOME", defaultJavaToolChain.getJavaHome() );
+                        jdkHome = defaultJavaToolChain.getJavaHome();
+                        getEnvironmentVariables().put( "JAVA_HOME", jdkHome );
                     }
                 }
 
@@ -2570,7 +2593,8 @@ public abstract class AbstractSurefireMojo
                     javaVersion9 = isJava9AtLeast( jvmToUse );
                 }
 
-                return new JdkAttributes( jvmToUse, javaVersion9 );
+                return new JdkAttributes( new File( jvmToUse ),
+                    jdkHome == null ? toJdkHomeFromJvmExec( jvmToUse ) : new File( jdkHome ), javaVersion9 );
             }
         }
 
@@ -2621,7 +2645,7 @@ public abstract class AbstractSurefireMojo
         checksum.add( isSkipExec() );
         checksum.add( isSkip() );
         checksum.add( getTestClassesDirectory() );
-        checksum.add( getClassesDirectory() );
+        checksum.add( getMainBuildPath() );
         checksum.add( getClasspathDependencyExcludes() );
         checksum.add( getClasspathDependencyScopeExclude() );
         checksum.add( getAdditionalClasspathElements() );
@@ -2741,7 +2765,7 @@ public abstract class AbstractSurefireMojo
             classpathArtifacts = filterArtifacts( classpathArtifacts, dependencyFilter );
         }
 
-        return new TestClassPath( classpathArtifacts, getClassesDirectory(),
+        return new TestClassPath( classpathArtifacts, getMainBuildPath(),
                 getTestClassesDirectory(), getAdditionalClasspathElements() );
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
index 96049a5..f8ab5f7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
@@ -19,7 +19,10 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
+import java.io.File;
+
 import static java.util.Objects.requireNonNull;
+import static org.apache.maven.surefire.booter.SystemUtils.toJdkHomeFromJvmExec;
 
 /**
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
@@ -27,20 +30,32 @@ import static java.util.Objects.requireNonNull;
  */
 public final class JdkAttributes
 {
-    private final String jvmExecutable;
+    private final File jvmExecutable;
+    private final File jdkHome;
     private final boolean java9AtLeast;
 
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
+    public JdkAttributes( File jvmExecutable, File jdkHome, boolean java9AtLeast )
     {
         this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
+        this.jdkHome = jdkHome;
         this.java9AtLeast = java9AtLeast;
     }
 
-    public String getJvmExecutable()
+    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
+    {
+        this( new File( jvmExecutable ), toJdkHomeFromJvmExec( jvmExecutable ), java9AtLeast );
+    }
+
+    public File getJvmExecutable()
     {
         return jvmExecutable;
     }
 
+    public File getJdkHome()
+    {
+        return jdkHome;
+    }
+
     public boolean isJava9AtLeast()
     {
         return java9AtLeast;
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ResolvePathResultWrapper.java
similarity index 55%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ResolvePathResultWrapper.java
index 96049a5..9197d89 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ResolvePathResultWrapper.java
@@ -19,30 +19,32 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
 
 /**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
+ * Wraps {@link ResolvePathResult} and place marker.
  */
-public final class JdkAttributes
+final class ResolvePathResultWrapper
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
+    private final ResolvePathResult resolvePathResult;
+    private final boolean isMainModuleDescriptor;
 
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
+    ResolvePathResultWrapper( ResolvePathResult resolvePathResult, boolean isMainModuleDescriptor )
     {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
+        this.resolvePathResult = resolvePathResult;
+        this.isMainModuleDescriptor = isMainModuleDescriptor;
     }
 
-    public String getJvmExecutable()
+    ResolvePathResult getResolvePathResult()
     {
-        return jvmExecutable;
+        return resolvePathResult;
     }
 
-    public boolean isJava9AtLeast()
+    /**
+     * @return {@code true} if module-info appears in src/main/java module
+     */
+    boolean isMainModuleDescriptor()
     {
-        return java9AtLeast;
+        return isMainModuleDescriptor;
     }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
index 4425ddc..e66a7dd 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
@@ -50,9 +50,9 @@ public interface SurefireExecutionParameters
 
     void setTestClassesDirectory( File testClassesDirectory );
 
-    File getClassesDirectory();
+    File getMainBuildPath();
 
-    void setClassesDirectory( File classesDirectory );
+    void setMainBuildPath( File mainBuildPath );
 
     File getReportsDirectory();
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
index 443bf45..af09d67 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
@@ -144,7 +144,7 @@ public abstract class DefaultForkConfiguration
             cli.addEnvironment( entry.getKey(), value == null ? "" : value );
         }
 
-        cli.setExecutable( getJdkForTests().getJvmExecutable() );
+        cli.setExecutable( getJdkForTests().getJvmExecutable().getAbsolutePath() );
 
         String jvmArgLine = newJvmArgLine( forkNumber );
         if ( !jvmArgLine.isEmpty() )
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
index 074a3cb..14196f8 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
@@ -38,7 +38,7 @@ public final class Platform
 {
     private final RunnableFuture<Long> pluginPidJob;
 
-    private volatile JdkAttributes jdk;
+    private final JdkAttributes jdk;
 
     public Platform()
     {
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
index abd896e..e1a3b27 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
@@ -33,6 +33,7 @@ import org.apache.maven.surefire.suite.RunResult;
 import org.apache.maven.surefire.util.DefaultScanResult;
 import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
 import org.codehaus.plexus.languages.java.jpms.LocationManager;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
 import org.codehaus.plexus.languages.java.jpms.ModuleNameSource;
@@ -138,14 +139,15 @@ public class AbstractSurefireMojoJava7PlusTest
         provider.setFile( mockFile( "surefire-provider.jar" ) );
         Set<Artifact> providerClasspath = singleton( provider );
 
-        File moduleInfo = mockFile( "classes/module-info.class" );
+        ResolvePathResult moduleInfo = mock( ResolvePathResult.class );
+        when( moduleInfo.getModuleDescriptor() ).thenReturn( descriptor );
 
         @SuppressWarnings( "unchecked" )
         ResolvePathsRequest<String> req = mock( ResolvePathsRequest.class );
         mockStatic( ResolvePathsRequest.class );
         when( ResolvePathsRequest.ofStrings( eq( testClasspath.toClasspath().getClassPath() ) ) ).thenReturn( req );
         when( req.setJdkHome( anyString() ) ).thenReturn( req );
-        when( req.setMainModuleDescriptor( eq( moduleInfo.getAbsolutePath() ) ) ).thenReturn( req );
+        when( req.setModuleDescriptor( eq( descriptor ) ) ).thenReturn( req );
 
         when( descriptor.name() ).thenReturn( "abc" );
 
@@ -204,8 +206,8 @@ public class AbstractSurefireMojoJava7PlusTest
         when( mojo.getPluginArtifactMap() ).thenReturn( artifacts );
 
         StartupConfiguration conf = invokeMethod( mojo, "newStartupConfigWithModularPath",
-                classLoaderConfiguration, providerClasspath, "org.asf.Provider", moduleInfo, scanResult,
-                "", testClasspath );
+            classLoaderConfiguration, providerClasspath, "org.asf.Provider",
+            new ResolvePathResultWrapper( moduleInfo, true ), scanResult, "", testClasspath );
 
         verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
         verify( mojo, times( 1 ) ).isChildDelegation();
@@ -213,7 +215,7 @@ public class AbstractSurefireMojoJava7PlusTest
         verify( scanResult, times( 1 ) ).getClasses();
         verifyStatic( ResolvePathsRequest.class, times( 1 ) );
         ResolvePathsRequest.ofStrings( eq( testClasspath.toClasspath().getClassPath() ) );
-        verify( req, times( 1 ) ).setMainModuleDescriptor( eq( moduleInfo.getAbsolutePath() ) );
+        verify( req, times( 1 ) ).setModuleDescriptor( eq( descriptor ) );
         verify( res, times( 1 ) ).getClasspathElements();
         verify( res, times( 1 ) ).getModulepathElements();
         verify( locationManager, times( 1 ) ).resolvePaths( eq( req ) );
@@ -347,13 +349,13 @@ public class AbstractSurefireMojoJava7PlusTest
         }
 
         @Override
-        public File getClassesDirectory()
+        public File getMainBuildPath()
         {
             return null;
         }
 
         @Override
-        public void setClassesDirectory( File classesDirectory )
+        public void setMainBuildPath( File mainBuildPath )
         {
 
         }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
index 7ed96b3..8647c0f 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
@@ -33,6 +33,7 @@ import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.plugin.surefire.AbstractSurefireMojo.JUnitPlatformProviderInfo;
+import org.apache.maven.plugin.surefire.booterclient.Platform;
 import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingRequest;
@@ -43,15 +44,24 @@ import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
 import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
 import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
 import org.apache.maven.surefire.booter.StartupConfiguration;
 import org.apache.maven.surefire.extensions.ForkNodeFactory;
 import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.util.DefaultScanResult;
 import org.apache.maven.toolchain.Toolchain;
+import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
+import org.codehaus.plexus.languages.java.jpms.LocationManager;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathRequest;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
 import org.codehaus.plexus.logging.Logger;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -63,6 +73,8 @@ import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -75,21 +87,27 @@ import java.util.Map;
 import java.util.Set;
 
 import static java.io.File.separatorChar;
+import static java.nio.file.Files.write;
 import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
 import static java.util.Collections.emptySet;
 import static java.util.Collections.singleton;
 import static java.util.Collections.singletonList;
-import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.maven.artifact.versioning.VersionRange.createFromVersion;
 import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
+import static org.apache.maven.surefire.shared.lang3.JavaVersion.JAVA_9;
+import static org.apache.maven.surefire.shared.lang3.JavaVersion.JAVA_RECENT;
+import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
+import static org.codehaus.plexus.languages.java.jpms.ModuleNameSource.MODULEDESCRIPTOR;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.MapAssert.entry;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.doNothing;
 import static org.powermock.api.mockito.PowerMockito.doReturn;
 import static org.powermock.api.mockito.PowerMockito.mock;
@@ -109,6 +127,9 @@ public class AbstractSurefireMojoTest
     @Rule
     public final ExpectedException e = ExpectedException.none();
 
+    @Rule
+    public final TemporaryFolder tempFolder = new TemporaryFolder();
+
     @Mock
     private ArtifactHandler handler;
 
@@ -140,6 +161,119 @@ public class AbstractSurefireMojoTest
     }
 
     @Test
+    public void noModuleDescriptorFile() throws Exception
+    {
+        AbstractSurefireMojo mojo = spy( new Mojo() );
+        mojo.setMainBuildPath( tempFolder.newFolder() );
+        File jdkHome = new File( System.getProperty( "java.home" ) );
+        ResolvePathResultWrapper wrapper = invokeMethod( mojo, "findModuleDescriptor", jdkHome );
+
+        assertThat( wrapper )
+            .isNotNull();
+
+        assertThat( wrapper.getResolvePathResult() )
+            .isNull();
+
+        assertThat( invokeMethod( mojo, "existsModuleDescriptor", wrapper ) )
+            .isEqualTo( false );
+
+        when( mojo.useModulePath() ).thenReturn( true );
+
+        File jvmExecutable = new File( jdkHome, IS_OS_WINDOWS ? "bin\\java.exe" : "bin/java" );
+        JdkAttributes jdkAttributes = new JdkAttributes( jvmExecutable, jdkHome, true );
+        Platform platform = new Platform().withJdkExecAttributesForTests( jdkAttributes );
+        assertThat( invokeMethod( mojo, "canExecuteProviderWithModularPath", platform, wrapper ) )
+            .isEqualTo( false );
+    }
+
+    @Test
+    public void correctModuleDescriptor() throws Exception
+    {
+        AbstractSurefireMojo mojo = spy( new Mojo() );
+        LocationManager locationManager = mock( LocationManager.class );
+        ResolvePathResult result = mock( ResolvePathResult.class );
+        when( result.getModuleNameSource() ).thenReturn( MODULEDESCRIPTOR );
+        JavaModuleDescriptor descriptor = mock( JavaModuleDescriptor.class );
+        when( result.getModuleDescriptor() ).thenReturn( descriptor );
+        when( locationManager.resolvePath( any( ResolvePathRequest.class ) ) ).thenReturn( result );
+        doReturn( locationManager )
+            .when( mojo, "getLocationManager" );
+        File classesDir = tempFolder.newFolder();
+        mojo.setMainBuildPath( classesDir );
+        File descriptorFile = new File( classesDir, "module-info.class" );
+        assertThat( descriptorFile.createNewFile() ).isTrue();
+        File jdkHome = new File( System.getProperty( "java.home" ) );
+        ResolvePathResultWrapper wrapper = invokeMethod( mojo, "findModuleDescriptor", jdkHome );
+
+        assertThat( wrapper )
+            .isNotNull();
+
+        assertThat( wrapper.getResolvePathResult() )
+            .isSameAs( result );
+
+        assertThat( wrapper.getResolvePathResult().getModuleNameSource() )
+            .isSameAs( MODULEDESCRIPTOR );
+
+        assertThat( wrapper.getResolvePathResult().getModuleDescriptor() )
+            .isSameAs( descriptor );
+
+        assertThat( invokeMethod( mojo, "existsModuleDescriptor", wrapper ) )
+            .isEqualTo( true );
+
+        when( mojo.useModulePath() ).thenReturn( true );
+
+        File jvmExecutable = new File( jdkHome, IS_OS_WINDOWS ? "bin\\java.exe" : "bin/java" );
+        JdkAttributes jdkAttributes = new JdkAttributes( jvmExecutable, jdkHome, true );
+        Platform platform = new Platform().withJdkExecAttributesForTests( jdkAttributes );
+        assertThat( invokeMethod( mojo, "canExecuteProviderWithModularPath", platform, wrapper ) )
+            .isEqualTo( true );
+
+        jdkAttributes = new JdkAttributes( jvmExecutable, jdkHome, false );
+        platform = new Platform().withJdkExecAttributesForTests( jdkAttributes );
+        assertThat( invokeMethod( mojo, "canExecuteProviderWithModularPath", platform, wrapper ) )
+            .isEqualTo( false );
+
+        when( mojo.useModulePath() ).thenReturn( false );
+
+        jdkAttributes = new JdkAttributes( jvmExecutable, jdkHome, true );
+        platform = new Platform().withJdkExecAttributesForTests( jdkAttributes );
+        assertThat( invokeMethod( mojo, "canExecuteProviderWithModularPath", platform, wrapper ) )
+            .isEqualTo( false );
+    }
+
+    @Test
+    @SuppressWarnings( "checkstyle:magicnumber" )
+    public void corruptedModuleDescriptor() throws Exception
+    {
+        if ( !JAVA_RECENT.atLeast( JAVA_9 ) )
+        {
+            return;
+        }
+
+        AbstractSurefireMojo mojo = spy( new Mojo() );
+        doReturn( new LocationManager() )
+            .when( mojo, "getLocationManager" );
+        File classesDir = tempFolder.newFolder();
+        mojo.setMainBuildPath( classesDir );
+
+        File descriptorFile = new File( classesDir, "module-info.class" );
+        assertThat( descriptorFile.createNewFile() ).isTrue();
+        write( descriptorFile.toPath(), new byte[]{(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE} );
+
+        File jdkHome = new File( System.getProperty( "java.home" ) );
+        ResolvePathResultWrapper wrapper = invokeMethod( mojo, "findModuleDescriptor", jdkHome );
+
+        assertThat( wrapper )
+            .isNotNull();
+
+        assertThat( wrapper.getResolvePathResult() )
+            .isNull();
+
+        assertThat( invokeMethod( mojo, "existsModuleDescriptor", wrapper ) )
+            .isEqualTo( false );
+    }
+
+    @Test
     public void shouldShowArray() throws Exception
     {
         Logger logger = mock( Logger.class );
@@ -249,7 +383,7 @@ public class AbstractSurefireMojoTest
     {
         AbstractSurefireMojo mojo = spy( this.mojo );
 
-        when( mojo.getClassesDirectory() ).thenReturn( new File( "target" + separatorChar + "classes" ) );
+        when( mojo.getMainBuildPath() ).thenReturn( new File( "target" + separatorChar + "classes" ) );
         when( mojo.getTestClassesDirectory() ).thenReturn( new File( "target" + separatorChar + "test-classes" ) );
         when( mojo.getClasspathDependencyScopeExclude() ).thenReturn( "runtime" );
         when( mojo.getClasspathDependencyExcludes() ).thenReturn( new String[]{ "g3:a3" } );
@@ -298,7 +432,7 @@ public class AbstractSurefireMojoTest
         TestClassPath cp = invokeMethod( mojo, "generateTestClasspath" );
 
         verifyPrivate( mojo, times( 1 ) ).invoke( "generateTestClasspath" );
-        verify( mojo, times( 1 ) ).getClassesDirectory();
+        verify( mojo, times( 1 ) ).getMainBuildPath();
         verify( mojo, times( 1 ) ).getTestClassesDirectory();
         verify( mojo, times( 3 ) ).getClasspathDependencyScopeExclude();
         verify( mojo, times( 2 ) ).getClasspathDependencyExcludes();
@@ -508,7 +642,81 @@ public class AbstractSurefireMojoTest
 
         doReturn( 1 ).when( mojo, "getEffectiveForkCount" );
 
-        return invokeMethod( mojo, "createStartupConfiguration", providerInfo, false, null, null, null, testClassPath );
+        return invokeMethod( mojo, "createStartupConfiguration",
+            providerInfo, false, null, null, testClassPath, null, null );
+    }
+
+    @Test
+    public void shouldCreateStartupConfigWithModularPath() throws Exception
+    {
+        String baseDir = System.getProperty( "user.dir" );
+
+        Mojo mojo = new Mojo();
+
+        // ### BEGIN
+        // we cannot mock private method newStartupConfigWithModularPath() - mocking the data to prevent from errors
+        LocationManager locationManager = mock( LocationManager.class );
+        ResolvePathsResult resolvePathsResult = mock( ResolvePathsResult.class );
+        when( locationManager.resolvePaths( any( ResolvePathsRequest.class ) ) ).thenReturn( resolvePathsResult );
+        when( resolvePathsResult.getPathExceptions() ).thenReturn( emptyMap() );
+        when( resolvePathsResult.getClasspathElements() ).thenReturn( emptyList() );
+        when( resolvePathsResult.getModulepathElements() ).thenReturn( emptyMap() );
+        JavaModuleDescriptor desc = mock( JavaModuleDescriptor.class );
+        when( desc.name() ).thenReturn( "" );
+        when( resolvePathsResult.getMainModuleDescriptor() ).thenReturn( desc );
+
+        mojo.setLogger( mock( Logger.class ) );
+        mojo.setUseModulePath( true );
+        setInternalState( mojo, "locationManager", locationManager );
+
+        File jdkHome = new File( System.getProperty( "java.home" ) );
+        File jvmExecutable = new File( jdkHome, IS_OS_WINDOWS ? "bin\\java.exe" : "bin/java" );
+        JdkAttributes jdkAttributes = new JdkAttributes( jvmExecutable, jdkHome, true );
+        Platform platform = new Platform().withJdkExecAttributesForTests( jdkAttributes );
+
+        File classesDirectory = new File( baseDir, "mock-dir" );
+        File testClassesDirectory = new File( baseDir, "mock-dir" );
+        TestClassPath testClassPath = new TestClassPath( Collections.<Artifact>emptySet(),
+            classesDirectory, testClassesDirectory, new String[0] );
+
+        ProviderInfo providerInfo = mock( ProviderInfo.class );
+        when( providerInfo.getProviderName() ).thenReturn( "provider mock" );
+        when( providerInfo.getProviderClasspath() ).thenReturn( Collections.<Artifact>emptySet() );
+
+        DefaultScanResult defaultScanResult = mock( DefaultScanResult.class );
+        when( defaultScanResult.getClasses() ).thenReturn( Collections.<String>emptyList() );
+
+        Path pathToModularDescriptor =
+            Paths.get( baseDir, "src", "test", "resources", "org", "apache", "maven", "plugin", "surefire" );
+        mojo.setMainBuildPath( pathToModularDescriptor.toFile() );
+
+        Map<String, Artifact> artifacts = new HashMap<>();
+        Artifact dummyArtifact = mock( Artifact.class );
+        when( dummyArtifact.getFile() ).thenReturn( new File( baseDir, "mock-file" ) );
+        artifacts.put( "org.apache.maven.surefire:maven-surefire-common", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-extensions-api", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-api", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-logger-api", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-extensions-spi", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-booter", dummyArtifact );
+        artifacts.put( "org.apache.maven.surefire:surefire-shared-utils", dummyArtifact );
+        mojo.setPluginArtifactMap( artifacts );
+
+        ResolvePathResult resolvePathResult = mock( ResolvePathResult.class );
+        ResolvePathResultWrapper wrapper = new ResolvePathResultWrapper( resolvePathResult, true );
+        // ### END
+
+        StartupConfiguration actualConfig = invokeMethod( mojo, "createStartupConfiguration",
+            new Class[] {ProviderInfo.class, boolean.class, ClassLoaderConfiguration.class, DefaultScanResult.class,
+                TestClassPath.class, Platform.class, ResolvePathResultWrapper.class},
+            providerInfo, true, mock( ClassLoaderConfiguration.class ), defaultScanResult,
+            testClassPath, platform, wrapper );
+
+        assertThat( actualConfig )
+            .isNotNull();
+
+        assertThat( actualConfig.getClasspathConfiguration() )
+            .isInstanceOf( ModularClasspathConfiguration.class );
     }
 
     @Test
@@ -1804,6 +2012,9 @@ public class AbstractSurefireMojoTest
     public static class Mojo
             extends AbstractSurefireMojo implements SurefireReportParameters
     {
+        private File mainBuildPath;
+        private boolean useModulePath;
+
         private JUnitPlatformProviderInfo createJUnitPlatformProviderInfo( Artifact junitPlatformArtifact,
                                                                            TestClassPath testClasspathWrapper )
         {
@@ -1901,15 +2112,15 @@ public class AbstractSurefireMojoTest
         }
 
         @Override
-        public File getClassesDirectory()
+        public File getMainBuildPath()
         {
-            return null;
+            return mainBuildPath;
         }
 
         @Override
-        public void setClassesDirectory( File classesDirectory )
+        public void setMainBuildPath( File mainBuildPath )
         {
-
+            this.mainBuildPath = mainBuildPath;
         }
 
         @Override
@@ -2185,13 +2396,13 @@ public class AbstractSurefireMojoTest
         @Override
         protected boolean useModulePath()
         {
-            return false;
+            return useModulePath;
         }
 
         @Override
         protected void setUseModulePath( boolean useModulePath )
         {
-
+            this.useModulePath = useModulePath;
         }
 
         @Override
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
index 64437fb..ddcb169 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
@@ -37,6 +37,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import static java.io.File.separatorChar;
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
@@ -155,7 +156,8 @@ public class AbstractSurefireMojoToolchainsTest
         assertThat( mojo.getEnvironmentVariables() ).isEmpty();
         JdkAttributes effectiveJvm = invokeMethod( mojo, "getEffectiveJvm" );
         assertThat( mojo.getEnvironmentVariables() ).includes( MapAssert.entry( "JAVA_HOME", "/some/path" ) );
-        assertThat( effectiveJvm.getJvmExecutable() ).contains( "/path/from/toolchain" );
+        assertThat( effectiveJvm.getJvmExecutable().getPath() )
+            .contains( "/path/from/toolchain".replace( '/', separatorChar ) );
     }
 
     @Test
@@ -171,7 +173,8 @@ public class AbstractSurefireMojoToolchainsTest
 
         JdkAttributes effectiveJvm = invokeMethod( mojo, "getEffectiveJvm" );
         assertThat( mojo.getEnvironmentVariables() ).includes( MapAssert.entry( "JAVA_HOME", "/already/set/path" ) );
-        assertThat( effectiveJvm.getJvmExecutable() ).contains( "/path/from/toolchain" );
+        assertThat( effectiveJvm.getJvmExecutable().getPath() )
+            .contains( "/path/from/toolchain".replace( '/', separatorChar ) );
     }
 
     /**
@@ -191,9 +194,9 @@ public class AbstractSurefireMojoToolchainsTest
 
         assertThat( mojo.getEnvironmentVariables() ).isEmpty();
         JdkAttributes effectiveJvm = invokeMethod( mojo, "getEffectiveJvm" );
-        assertThat( mojo.getEnvironmentVariables() ).
-            includes( MapAssert.entry( "JAVA_HOME", currentJdkHome.getAbsolutePath() ) );
-        assertThat( effectiveJvm.getJvmExecutable() ).contains( javaExecutablePath );
+        assertThat( mojo.getEnvironmentVariables() )
+            .includes( MapAssert.entry( "JAVA_HOME", currentJdkHome.getAbsolutePath() ) );
+        assertThat( effectiveJvm.getJvmExecutable().getPath() ).contains( javaExecutablePath );
     }
 
     /**
@@ -207,15 +210,14 @@ public class AbstractSurefireMojoToolchainsTest
         mojo.setEnvironmentVariables( singletonMap( "JAVA_HOME", "/already/set/path" ) );
 
         File currentJdkHome = toJdkHomeFromJre();
-        String javaExecutablePath = FilenameUtils.concat(
-            currentJdkHome.getAbsolutePath(), "bin/java" );
+        String javaExecutablePath = FilenameUtils.concat( currentJdkHome.getAbsolutePath(), "bin/java" );
 
         mojo.setJvm( javaExecutablePath );
 
         JdkAttributes effectiveJvm = invokeMethod( mojo, "getEffectiveJvm" );
-        assertThat( mojo.getEnvironmentVariables() ).
-            includes( MapAssert.entry( "JAVA_HOME", "/already/set/path" ) );
-        assertThat( effectiveJvm.getJvmExecutable() ).contains( javaExecutablePath );
+        assertThat( mojo.getEnvironmentVariables() )
+            .includes( MapAssert.entry( "JAVA_HOME", "/already/set/path" ) );
+        assertThat( effectiveJvm.getJvmExecutable().getPath() ).contains( javaExecutablePath );
     }
 
 
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
index 835ce8e..dda40b3 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
@@ -452,13 +452,13 @@ public class MojoMocklessTest
         }
 
         @Override
-        public File getClassesDirectory()
+        public File getMainBuildPath()
         {
             return null;
         }
 
         @Override
-        public void setClassesDirectory( File classesDirectory )
+        public void setMainBuildPath( File mainBuildPath )
         {
 
         }
diff --git a/maven-surefire-common/src/test/resources/org/apache/maven/plugin/surefire/module-info.class b/maven-surefire-common/src/test/resources/org/apache/maven/plugin/surefire/module-info.class
new file mode 100644
index 0000000..51e6dcd
Binary files /dev/null and b/maven-surefire-common/src/test/resources/org/apache/maven/plugin/surefire/module-info.class differ
diff --git a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
index 4d47596..35d15fa 100644
--- a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
+++ b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
@@ -565,15 +565,15 @@ public class SurefirePlugin
     }
 
     @Override
-    public File getClassesDirectory()
+    public File getMainBuildPath()
     {
         return classesDirectory;
     }
 
     @Override
-    public void setClassesDirectory( File classesDirectory )
+    public void setMainBuildPath( File mainBuildPath )
     {
-        this.classesDirectory = classesDirectory;
+        classesDirectory = mainBuildPath;
     }
 
     @Override
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1570ModularFailsafeIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1570ModularFailsafeIT.java
new file mode 100644
index 0000000..83d3d08
--- /dev/null
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1570ModularFailsafeIT.java
@@ -0,0 +1,54 @@
+package org.apache.maven.surefire.its.jiras;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.maven.surefire.its.fixture.HelperAssertions.assumeJavaVersion;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+/**
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SUREFIRE-1570">SUREFIRE-1570</a>
+ */
+@SuppressWarnings( "checkstyle:magicnumber" )
+public class Surefire1570ModularFailsafeIT
+    extends SurefireJUnit4IntegrationTestCase
+{
+    @Before
+    public void setUp()
+    {
+        assumeJavaVersion( 9d );
+    }
+
+    @Test
+    public void shouldRunWithJupiterApi() throws Exception
+    {
+        unpack( "surefire-1570" )
+            .debugLogging()
+            .executeVerify()
+            .verifyErrorFreeLog()
+            .assertThatLogLine( containsString( "Lets see JDKModulePath" ), is( 2 ) )
+            .assertThatLogLine( containsString( "Lets see JDKModulePath: null" ), is( 0 ) );
+    }
+}
diff --git a/surefire-its/src/test/resources/java9-full-api/src/test/java/J9IT.java b/surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9IT.java
similarity index 98%
rename from surefire-its/src/test/resources/java9-full-api/src/test/java/J9IT.java
rename to surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9IT.java
index c74678d..9c8f976 100644
--- a/surefire-its/src/test/resources/java9-full-api/src/test/java/J9IT.java
+++ b/surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9IT.java
@@ -1,3 +1,5 @@
+package java9.full.api;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
diff --git a/surefire-its/src/test/resources/java9-full-api/src/test/java/J9Test.java b/surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9Test.java
similarity index 98%
rename from surefire-its/src/test/resources/java9-full-api/src/test/java/J9Test.java
rename to surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9Test.java
index 6fc8536..71e645f 100644
--- a/surefire-its/src/test/resources/java9-full-api/src/test/java/J9Test.java
+++ b/surefire-its/src/test/resources/java9-full-api/src/test/java/java9/full/api/J9Test.java
@@ -1,3 +1,5 @@
+package java9.full.api;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
diff --git a/surefire-its/src/test/resources/surefire-1570/com.foo.api/pom.xml b/surefire-its/src/test/resources/surefire-1570/com.foo.api/pom.xml
new file mode 100644
index 0000000..6e1883c
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.api/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.foo</groupId>
+        <artifactId>com.foo</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>com.foo.api</artifactId>
+    
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.persistence</groupId>
+            <artifactId>jakarta.persistence-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.ws.rs</groupId>
+            <artifactId>jakarta.ws.rs-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.xml.bind</groupId>
+            <artifactId>jakarta.xml.bind-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
similarity index 54%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
index 96049a5..43ecf73 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.api;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,30 +19,10 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
-
 /**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
+ *
  */
-public final class JdkAttributes
+public interface SomeInterface
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
-
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
-
-    public boolean isJava9AtLeast()
-    {
-        return java9AtLeast;
-    }
+    void doItNow( Class<?> observer );
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/module-info.java
similarity index 54%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/module-info.java
index 96049a5..95b05f7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.api/src/main/java/module-info.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.surefire;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,30 +17,12 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
- */
-public final class JdkAttributes
+module com.foo.api
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
-
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
-
-    public boolean isJava9AtLeast()
-    {
-        return java9AtLeast;
-    }
+    exports com.foo.api;
+    requires org.slf4j;
+    requires java.persistence;
+    requires java.ws.rs;
+    requires java.xml.bind;
+    requires jakarta.activation;
 }
diff --git a/surefire-its/src/test/resources/surefire-1570/com.foo.impl/pom.xml b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/pom.xml
new file mode 100644
index 0000000..e151aff
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.foo</groupId>
+        <artifactId>com.foo</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>com.foo.impl</artifactId>
+    
+    <dependencies>
+        <dependency>
+            <groupId>com.foo</groupId>
+            <artifactId>com.foo.api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+<!--                    <multiReleaseOutput>true</multiReleaseOutput>-->
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestEntries>
+<!--                            <Multi-Release>true</Multi-Release>-->
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>integration-tests</id>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/com/foo/impl/Bar.java
similarity index 50%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/com/foo/impl/Bar.java
index 96049a5..50009e3 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/com/foo/impl/Bar.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.impl;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,30 +19,33 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
+import com.foo.api.SomeInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
+ *
  */
-public final class JdkAttributes
+public class Bar implements SomeInterface
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
+    private static final Logger LOG = LoggerFactory.getLogger( Bar.class );
 
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
+    private boolean weAreAmongModules;
 
-    public boolean isJava9AtLeast()
+    @Override
+    public void doItNow( Class<?> observer )
     {
-        return java9AtLeast;
+        ModuleLayer.boot().modules().forEach( m -> {
+            if ( m == observer.getModule() || m == Bar.class.getModule() || m == Logger.class.getModule() )
+            {
+                weAreAmongModules = true;
+            }
+        } );
+        LOG.info( "" );
+        LOG.info( "Let's see if I or SLF4J are among boot layer modules: {}", weAreAmongModules );
+        if ( !weAreAmongModules )
+        {
+            LOG.info( "Maybe we are in child layer? Or this is not module path?" );
+        }
     }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/module-info.java
similarity index 54%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/module-info.java
index 96049a5..af383c6 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/main/java/module-info.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.surefire;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,30 +17,10 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
- */
-public final class JdkAttributes
+module com.foo.impl
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
-
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
-
-    public boolean isJava9AtLeast()
-    {
-        return java9AtLeast;
-    }
+    requires org.slf4j;
+    requires org.slf4j.simple;
+    opens com.foo.impl;
+    requires com.foo.api;
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarIT.java
similarity index 55%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarIT.java
index 96049a5..43596b7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarIT.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.impl;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,30 +19,23 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
+ *
  */
-public final class JdkAttributes
+public class BarIT
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
-
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
+    private static final Logger LOG = LoggerFactory.getLogger( BarIT.class );
 
-    public boolean isJava9AtLeast()
+    @Test
+    void shouldPrintModulePath()
     {
-        return java9AtLeast;
+        Bar bar = new Bar();
+        LOG.info( "======INTEGRATION TEST=======" );
+        LOG.info( "Lets see JDKModulePath: {}", System.getProperty( "jdk.module.path" ) );
+        bar.doItNow( getClass() );
     }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarTest.java
similarity index 55%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
copy to surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarTest.java
index 96049a5..6e392b6 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
+++ b/surefire-its/src/test/resources/surefire-1570/com.foo.impl/src/test/java/com/foo/impl/BarTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.impl;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,30 +19,23 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import static java.util.Objects.requireNonNull;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20.1
+ *
  */
-public final class JdkAttributes
+public class BarTest
 {
-    private final String jvmExecutable;
-    private final boolean java9AtLeast;
-
-    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
-    {
-        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
-        this.java9AtLeast = java9AtLeast;
-    }
-
-    public String getJvmExecutable()
-    {
-        return jvmExecutable;
-    }
+    private static final Logger LOG = LoggerFactory.getLogger( BarTest.class );
 
-    public boolean isJava9AtLeast()
+    @Test
+    void shouldPrintModulePath()
     {
-        return java9AtLeast;
+        Bar bar = new Bar();
+        LOG.info( "======UNIT TEST=======" );
+        LOG.info( "Lets see JDKModulePath: {}", System.getProperty( "jdk.module.path" ) );
+        bar.doItNow( getClass() );
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-1570/pom.xml b/surefire-its/src/test/resources/surefire-1570/pom.xml
new file mode 100644
index 0000000..0f6bc9a
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-1570/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.foo</groupId>
+    <artifactId>com.foo</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.release>${java.specification.version}</maven.compiler.release>
+    </properties>
+
+    <modules>
+        <module>com.foo.api</module>
+        <module>com.foo.impl</module>
+    </modules>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>jakarta.persistence</groupId>
+                <artifactId>jakarta.persistence-api</artifactId>
+                <version>2.2.3</version>
+            </dependency>
+            <dependency>
+                <groupId>jakarta.ws.rs</groupId>
+                <artifactId>jakarta.ws.rs-api</artifactId>
+                <version>2.1.6</version>
+            </dependency>
+            <dependency>
+                <groupId>jakarta.xml.bind</groupId>
+                <artifactId>jakarta.xml.bind-api</artifactId>
+                <version>2.3.2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>1.8.0-beta2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-simple</artifactId>
+                <version>1.8.0-beta2</version>
+            </dependency>
+            <dependency>
+               <groupId>org.junit.jupiter</groupId>
+               <artifactId>junit-jupiter-api</artifactId>
+               <version>5.6.2</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.8.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>${surefire.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>3.2.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-failsafe-plugin</artifactId>
+                    <version>${surefire.version}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>


[maven-surefire] 03/03: support Windows in Surefire1295AttributeJvmCrashesToTestsIT

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit 13ff5483f591662143f40014bb5f2e7556c9557f
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat May 16 14:37:24 2020 +0200

    support Windows in Surefire1295AttributeJvmCrashesToTestsIT
---
 .../its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java         | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
index 25af97d..50ff20d 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
@@ -34,9 +34,7 @@ import static java.util.Arrays.asList;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC_OSX;
-import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS_10;
-import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS_7;
-import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS_8;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.maven.surefire.its.jiras.Surefire1295AttributeJvmCrashesToTestsIT.ForkMode.DEFAULT;
 import static org.apache.maven.surefire.its.jiras.Surefire1295AttributeJvmCrashesToTestsIT.ForkMode.ONE_FORK_NO_REUSE;
 import static org.apache.maven.surefire.its.jiras.Surefire1295AttributeJvmCrashesToTestsIT.ForkMode.ONE_FORK_REUSE;
@@ -95,7 +93,7 @@ public class Surefire1295AttributeJvmCrashesToTestsIT
     public void test()
             throws Exception
     {
-        assumeTrue( IS_OS_LINUX || IS_OS_MAC_OSX || IS_OS_WINDOWS_7 || IS_OS_WINDOWS_8 || IS_OS_WINDOWS_10 );
+        assumeTrue( IS_OS_LINUX || IS_OS_MAC_OSX || IS_OS_WINDOWS );
 
         SurefireLauncher launcher =
                 unpack( "crash-during-test", "_" + crashStyle + "_" + forkStyle.ordinal() )


[maven-surefire] 02/03: improved coverage in getEffectiveJvm()

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit d44122a8d5108041316986f7fedbfdd144905c1c
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat May 16 04:25:13 2020 +0200

    improved coverage in getEffectiveJvm()
---
 .../AbstractSurefireMojoToolchainsTest.java        | 55 ++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
index ddcb169..8468df5 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoToolchainsTest.java
@@ -25,14 +25,20 @@ import org.apache.maven.surefire.shared.io.FilenameUtils;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
+import org.codehaus.plexus.logging.Logger;
 import org.fest.assertions.MapAssert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -44,6 +50,9 @@ import static java.util.Collections.singletonMap;
 import static junit.framework.TestCase.assertNull;
 import static org.apache.maven.surefire.booter.SystemUtils.toJdkHomeFromJre;
 import static org.fest.assertions.Assertions.assertThat;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.powermock.api.mockito.PowerMockito.mock;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 import static org.powermock.api.mockito.PowerMockito.when;
@@ -57,6 +66,8 @@ import static org.powermock.reflect.Whitebox.invokeMethod;
 @PowerMockIgnore( {"org.jacoco.agent.rt.*", "com.vladium.emma.rt.*"} )
 public class AbstractSurefireMojoToolchainsTest
 {
+    @Rule
+    public final ExpectedException e = ExpectedException.none();
 
     /**
      * Ensure that we use the toolchain found by getToolchainMaven33x()
@@ -220,7 +231,51 @@ public class AbstractSurefireMojoToolchainsTest
         assertThat( effectiveJvm.getJvmExecutable().getPath() ).contains( javaExecutablePath );
     }
 
+    @Test
+    public void withoutJvmAndToolchain() throws Exception
+    {
+        AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
+        Logger logger = mock( Logger.class );
+        mojo.setLogger( logger );
+        ArgumentCaptor<String> argument = ArgumentCaptor.forClass( String.class );
+        JdkAttributes effectiveJvm = invokeMethod( mojo, "getEffectiveJvm" );
+
+        assertThat( mojo.getJvm() )
+            .isNull();
+
+        assertThat( mojo.getEnvironmentVariables() )
+            .isEmpty();
+
+        assertThat( effectiveJvm )
+            .isNotNull();
+
+        assertThat( effectiveJvm.getJvmExecutable() )
+            .isNotNull();
+
+        Path javaHome = Paths.get( System.getProperty( "java.home" ) ).normalize();
+        boolean isLocalJvm = effectiveJvm.getJvmExecutable().toPath().normalize().startsWith( javaHome );
+        assertThat( isLocalJvm )
+            .isTrue();
 
+        verify( logger, times( 1 ) )
+            .debug( argument.capture() );
+
+        assertThat( argument.getValue() )
+            .startsWith( "Using JVM: " + System.getProperty( "java.home" ) );
+    }
+
+    @Test
+    public void shouldFailWithWrongJvmExecPath() throws Exception
+    {
+        AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
+        mojo.setLogger( mock( Logger.class ) );
+        mojo.setJvm( System.getProperty( "user.dir" ) );
+
+        e.expect( MojoFailureException.class );
+        e.expectMessage( startsWith( "Given path does not end with java executor" ) );
+
+        invokeMethod( mojo, "getEffectiveJvm" );
+    }
 
     /**
      * Mocks a ToolchainManager