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 12:37:48 UTC

[maven-surefire] branch SUREFIRE-1570 updated (7170a78 -> e1fdffd)

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

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


 discard 7170a78  early initialized Platform and ResolvePathResultWrapper to gain the performance
 discard 0aa2e2f  IT
 discard 47ba729  improved coverage in getEffectiveJvm()
 discard 8707187  unit tests
 discard 70e63d2  fixed impl
 discard f51fa30  fixed impl
 discard 0fbe05e  fixed impl and Java9FullApiIT
    omit 3ec9e3a  impl - missing setJdkHome, ...
    omit bab07c0  renamed method matching two use cases
    omit 48e8393  [SUREFIRE-1570] Maven-fail-safe doesn't put testing JPMS module on module path
     add 35f5eaa  Put XML example for "includes" inside its pre tag
     add 218de3c  included H35
     new a1b808d  [SUREFIRE-1570] Maven-fail-safe doesn't put testing JPMS module on module path
     new b120d8a  improved coverage in getEffectiveJvm()
     new e1fdffd  support Windows in Surefire1295AttributeJvmCrashesToTestsIT

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (7170a78)
            \
             N -- N -- N   refs/heads/SUREFIRE-1570 (e1fdffd)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

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:
 Jenkinsfile                                                         | 2 +-
 .../main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java  | 3 +--
 .../its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java         | 6 ++----
 3 files changed, 4 insertions(+), 7 deletions(-)


[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 SUREFIRE-1570
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit a1b808dfb5fa88d27547c17720b7b1311c0087da
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      | 117 ++++++-----
 .../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         |  12 +-
 .../plugin/surefire/AbstractSurefireMojoTest.java  | 218 +++++++++++++++++++--
 .../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, 707 insertions(+), 241 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..0dfb95d 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,23 @@ 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();
+                JdkAttributes jdkAttributes = platform.getJdkExecAttributesForTests();
+                File jdkHome = jdkAttributes.getJdkHome();
+                ResolvePathResult resolvePathResult = findModuleDescriptor( jdkHome ).getResolvePathResult();
 
                 return newStartupConfigWithModularPath( classLoaderConfiguration, providerArtifacts, providerName,
-                        getModuleDescriptor(), scanResult, javaHome, testClasspathWrapper );
+                        resolvePathResult, scanResult, jdkHome.getAbsolutePath(), testClasspathWrapper );
             }
             else
             {
@@ -1960,9 +1978,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 ResolvePathResult moduleDescriptor,
+        @Nonnull DefaultScanResult scanResult, @Nonnull String javaHome, @Nonnull TestClassPath testClasspathWrapper )
             throws IOException
     {
         Classpath testClasspath = testClasspathWrapper.toClasspath();
@@ -1975,7 +1993,7 @@ public abstract class AbstractSurefireMojo
 
         ResolvePathsRequest<String> req = ResolvePathsRequest.ofStrings( testClasspath.getClassPath() )
                 .setJdkHome( javaHome )
-                .setMainModuleDescriptor( moduleDescriptor.getAbsolutePath() );
+                .setModuleDescriptor( moduleDescriptor.getModuleDescriptor() );
 
         ResolvePathsResult<String> result = getLocationManager().resolvePaths( req );
         for ( Entry<String, Exception> entry : result.getPathExceptions().entrySet() )
@@ -2327,12 +2345,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 +2368,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 +2385,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 +2398,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 +2536,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 +2553,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 +2572,7 @@ public abstract class AbstractSurefireMojo
             if ( isNotEmpty( jvmToUse ) )
             {
                 boolean javaVersion9 = false;
+                String jdkHome = null;
 
                 if ( toolchain instanceof DefaultToolchain )
                 {
@@ -2559,9 +2584,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 +2596,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 +2648,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 +2768,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..6d259a8 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" );
 
@@ -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..92ef90c 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,22 @@ 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.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 +71,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 +85,25 @@ 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.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 +123,9 @@ public class AbstractSurefireMojoTest
     @Rule
     public final ExpectedException e = ExpectedException.none();
 
+    @Rule
+    public final TemporaryFolder tempFolder = new TemporaryFolder();
+
     @Mock
     private ArtifactHandler handler;
 
@@ -140,6 +157,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 +379,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 +428,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 +638,70 @@ 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
+        mojo.setLogger( mock( Logger.class ) );
+        mojo.setUseModulePath( true );
+        setInternalState( mojo, "locationManager", new 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 );
+
+        ResolvePathResultWrapper wrapper = new ResolvePathResultWrapper( mock( ResolvePathResult.class ), 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 +1997,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 +2097,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 +2381,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] 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 SUREFIRE-1570
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit b120d8a36ef8cc2dac698e1f4071984b2262c050
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


[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 SUREFIRE-1570
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit e1fdffd9bd5e2c5d8e3fdf0eaa3f3534ed4455a5
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() )