You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2017/09/03 20:13:00 UTC

maven-surefire git commit: [SUREFIRE-1262] Initial commit running tests with modulepath

Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1262 [created] 14191e51d


[SUREFIRE-1262] Initial commit running tests with modulepath


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/14191e51
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/14191e51
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/14191e51

Branch: refs/heads/SUREFIRE-1262
Commit: 14191e51d43cb60ee45c537961cb0d421391dce9
Parents: 1a65d61
Author: rfscholte <rf...@apache.org>
Authored: Sun Sep 3 22:12:48 2017 +0200
Committer: rfscholte <rf...@apache.org>
Committed: Sun Sep 3 22:12:48 2017 +0200

----------------------------------------------------------------------
 maven-surefire-common/pom.xml                   |   5 +
 .../plugin/surefire/AbstractSurefireMojo.java   |  68 +++++++--
 .../booterclient/ForkConfiguration.java         | 148 +++++++++++++++++--
 .../booterclient/ForkConfigurationTest.java     |  10 +-
 pom.xml                                         |  23 ++-
 .../surefire/booter/ClasspathConfiguration.java |  39 ++++-
 surefire-integration-tests/pom.xml              |   2 +
 .../apache/maven/surefire/its/ModulePathIT.java |  42 ++++++
 .../src/test/resources/modulepath/pom.xml       |  43 ++++++
 .../modulepath/src/main/java/com/app/Main.java  |  33 +++++
 .../modulepath/src/main/java/module-info.java   |  21 +++
 .../src/test/java/com/app/AppTest.java          |  39 +++++
 12 files changed, 436 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/maven-surefire-common/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index ae050c7..35a1055 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -90,6 +90,11 @@
       <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-java</artifactId>
+      <version>0.9.3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
       <groupId>com.google.code.findbugs</groupId>
       <artifactId>jsr305</artifactId>
       <scope>provided</scope>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
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 f2e5bfb..357c653 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
@@ -79,6 +79,9 @@ import org.apache.maven.surefire.util.RunOrder;
 import org.apache.maven.surefire.util.SurefireReflectionException;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
+import org.codehaus.plexus.languages.java.jpms.LocationManager;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
 
 import javax.annotation.Nonnull;
 import java.io.File;
@@ -713,6 +716,9 @@ public abstract class AbstractSurefireMojo
      */
     @Component
     private ToolchainManager toolchainManager;
+    
+    @Component
+    private LocationManager locationManager;
 
     private Artifact surefireBooterArtifact;
 
@@ -1650,17 +1656,55 @@ public abstract class AbstractSurefireMojo
                     providerClasspath.addClassPathElementUrl( surefireArtifact.getFile().getAbsolutePath() )
                             .addClassPathElementUrl( getApiArtifact().getFile().getAbsolutePath() );
 
-            final Classpath testClasspath = generateTestClasspath();
-
-            getConsoleLogger().debug( testClasspath.getLogMessage( "test" ) );
-            getConsoleLogger().debug( providerClasspath.getLogMessage( "provider" ) );
-
-            getConsoleLogger().debug( testClasspath.getCompactLogMessage( "test(compact)" ) );
-            getConsoleLogger().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
+            final List<String> testPath = generateTestClasspath();
+            
+            File moduleDescriptor = new File( getClassesDirectory(), "module-info.class" );
+            
+            final ClasspathConfiguration classpathConfiguration;
+            if ( moduleDescriptor.exists() )
+            {
+                ResolvePathsRequest<String> req =
+                    ResolvePathsRequest.withStrings( testPath )
+                                       .setMainModuleDescriptor( moduleDescriptor.getAbsolutePath() );
+                
+                ResolvePathsResult<String> result;
+                try
+                {
+                    result = locationManager.resolvePaths( req );
+                }
+                catch ( IOException e )
+                {
+                    throw new MojoExecutionException( e.getMessage(), e );
+                }
+                
+                Classpath testClasspath = new Classpath( result.getClasspathElements() );
+                Classpath testModulepath = new Classpath( result.getModulepathElements().keySet() );
+                
+                classpathConfiguration =
+                    new ClasspathConfiguration( testClasspath, testModulepath, providerClasspath, inprocClassPath,
+                                                moduleDescriptor, effectiveIsEnableAssertions(), isChildDelegation() );
+
+                getConsoleLogger().debug( testClasspath.getLogMessage( "test-classpath" ) );
+                getConsoleLogger().debug( testModulepath.getLogMessage( "test-modulepath" ) );
+                getConsoleLogger().debug( providerClasspath.getLogMessage( "provider" ) );
+
+                getConsoleLogger().debug( testClasspath.getCompactLogMessage( "test-classpath(compact)" ) );
+                getConsoleLogger().debug( testModulepath.getCompactLogMessage( "test-modulepath(compact)" ) );
+                getConsoleLogger().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
+            }
+            else
+            {
+                Classpath testClasspath = new Classpath( testPath );
+                classpathConfiguration =
+                    new ClasspathConfiguration( testClasspath, providerClasspath, inprocClassPath,
+                                                effectiveIsEnableAssertions(), isChildDelegation() );
+                
+                getConsoleLogger().debug( testClasspath.getLogMessage( "test" ) );
+                getConsoleLogger().debug( providerClasspath.getLogMessage( "provider" ) );
 
-            final ClasspathConfiguration classpathConfiguration =
-                new ClasspathConfiguration( testClasspath, providerClasspath, inprocClassPath,
-                                            effectiveIsEnableAssertions(), isChildDelegation() );
+                getConsoleLogger().debug( testClasspath.getCompactLogMessage( "test(compact)" ) );
+                getConsoleLogger().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
+            }
 
             return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
                                              isForking(), false );
@@ -2194,7 +2238,7 @@ public abstract class AbstractSurefireMojo
      * @throws ArtifactNotFoundException   when it happens
      * @throws ArtifactResolutionException when it happens
      */
-    private Classpath generateTestClasspath()
+    private List<String> generateTestClasspath()
         throws InvalidVersionSpecificationException, MojoFailureException, ArtifactResolutionException,
         ArtifactNotFoundException, MojoExecutionException
     {
@@ -2250,7 +2294,7 @@ public abstract class AbstractSurefireMojo
             addTestNgUtilsArtifacts( classpath );
         }
 
-        return new Classpath( classpath );
+        return classpath;
     }
 
     private void addTestNgUtilsArtifacts( List<String> classpath )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
index 1c7626e..ce38be4 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
@@ -28,9 +28,16 @@ import org.apache.maven.surefire.booter.ForkedBooter;
 import org.apache.maven.surefire.booter.StartupConfiguration;
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
 import org.apache.maven.surefire.util.internal.ImmutableMap;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ModuleVisitor;
+import org.objectweb.asm.Opcodes;
 
+import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Iterator;
@@ -131,9 +138,9 @@ public class ForkConfiguration
     }
 
     /**
-     * @param classPath            cla the classpath arguments
+     * @param classPath            the classpath arguments
      * @param startupConfiguration The startup configuration
-     * @param threadNumber         the thread number, to be the replacement in the argLine   @return A commandline
+     * @param threadNumber         the thread number, to be the replacement in the argLine
      * @return CommandLine able to flush entire command going to be sent to forked JVM
      * @throws org.apache.maven.surefire.booter.SurefireBooterForkException
      *          when unable to perform the fork
@@ -143,15 +150,19 @@ public class ForkConfiguration
                                                                int threadNumber )
         throws SurefireBooterForkException
     {
-        return createCommandLine( classPath,
-                                  startupConfiguration.getClassLoaderConfiguration()
-                                      .isManifestOnlyJarRequestedAndUsable(),
-                                  startupConfiguration.isShadefire(), startupConfiguration.isProviderMainClass()
-            ? startupConfiguration.getActualClassName()
-            : ForkedBooter.class.getName(), threadNumber );
+        Classpath testModulePath = startupConfiguration.getClasspathConfiguration().getTestModulepath();
+        
+        return createCommandLine( classPath, 
+                              testModulePath != null ? testModulePath.getClassPath() : null, 
+                              startupConfiguration.getClasspathConfiguration().getModuleDescriptor(),
+                              startupConfiguration.getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable(),
+                              startupConfiguration.isShadefire(),
+                              startupConfiguration.isProviderMainClass() ? startupConfiguration.getActualClassName()
+         : ForkedBooter.class.getName(), threadNumber );
     }
 
-    OutputStreamFlushableCommandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire,
+    OutputStreamFlushableCommandline createCommandLine( List<String> classPath, List<String> modulePath,
+                                                        File moduleDescriptor, boolean useJar, boolean shadefire,
                                                         String providerThatHasMainMethod, int threadNumber )
         throws SurefireBooterForkException
     {
@@ -177,7 +188,20 @@ public class ForkConfiguration
             cli.createArg().setLine( getDebugLine() );
         }
 
-        if ( useJar )
+        if ( moduleDescriptor != null )
+        {
+            try
+            {
+                File argsFile = createArgsFile( moduleDescriptor, classPath, providerThatHasMainMethod );
+                
+                cli.createArg().setValue( "@" + escapeToPlatformPath( argsFile.getAbsolutePath() ) );
+            }
+            catch ( IOException e )
+            {
+                throw new SurefireBooterForkException( "Error creating args file", e );
+            }
+        }
+        else if ( useJar )
         {
             try
             {
@@ -316,6 +340,78 @@ public class ForkConfiguration
             jos.close();
         }
     }
+    
+    private File createArgsFile( File moduleDescriptor, List<String> classPath, String startClassName )
+        throws IOException
+    {
+        File file = File.createTempFile( "surefireargs", "", tempDirectory );
+        if ( !debug )
+        {
+            file.deleteOnExit();
+        }
+
+        final String moduleName = getModuleName( moduleDescriptor );
+        
+        BufferedWriter writer = null;
+        try 
+        {
+            final String ps = System.getProperty( "path.separator" );
+            
+            writer = new BufferedWriter( new FileWriter( file ) );
+            
+            writer.write( "--module-path" );
+            writer.newLine();
+            
+            for ( String cpEntry : classPath )
+            {
+                writer.append( cpEntry ).append( ps );
+            }
+            writer.newLine();
+            
+            writer.write( "--patch-module" );
+            writer.newLine();
+
+            // @TODO use testClassesDirectory
+            writer.append( moduleName ).append( '=' ).append( "target/classes" );
+            writer.newLine();
+            
+            writer.write( "--add-modules" );
+            writer.newLine();
+            
+            writer.write( moduleName );
+            writer.newLine();
+            
+            writer.write( "--add-reads" );
+            writer.newLine();
+            
+            writer.append( moduleName ).append( '=' ).append( "surefire.booter" );
+            writer.newLine();
+
+            // foreach package
+            for ( String pckg : Collections.singletonList( moduleName ) )
+            {
+                writer.write( "--add-exports" );
+                writer.newLine();
+
+                writer.append( moduleName ).append( '/' ).append( pckg ).append( '=' ).append( "surefire.booter" );
+                writer.newLine();
+            }
+
+            writer.write( "-m" );
+            writer.newLine();
+            
+            writer.append( "surefire.booter" ).append( '/' ).append( startClassName );
+        }
+        finally
+        {
+            if ( writer != null )
+            {
+                writer.close();
+            }
+        }
+        
+        return file;
+    }
 
     public boolean isDebug()
     {
@@ -364,4 +460,36 @@ public class ForkConfiguration
     {
         return map == null ? Collections.<K, V>emptyMap() : new ImmutableMap<K, V>( map );
     }
+    
+
+    private String getModuleName( File moduleDescriptor )
+    {
+        if ( moduleDescriptor == null )
+        {
+            return null;
+        }
+        
+        final StringBuilder sb = new StringBuilder();
+
+        try
+        {
+            new ClassReader( new FileInputStream( moduleDescriptor ) ).accept( new ClassVisitor( Opcodes.ASM6 )
+            {
+                @Override
+                public ModuleVisitor visitModule( String name, int access, String version )
+                {
+                    sb.append( name );
+                    return super.visitModule( name, access, version );
+                }
+            }, 0 );
+        }
+        catch ( IOException e )
+        {
+            // noop
+        }
+        
+        return sb.toString();
+    }
+
+
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
index 1e09d6f..836f198 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -45,7 +45,7 @@ public class ForkConfigurationTest
         File cpElement = getTempClasspathFile();
 
         Commandline cli =
-            config.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), true, false, null, 1 );
+            config.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), null, null, true, false, null, 1 );
 
         String line = StringUtils.join( cli.getCommandline(), " " );
         assertTrue( line.contains( "-jar" ) );
@@ -59,7 +59,7 @@ public class ForkConfigurationTest
         ForkConfiguration forkConfiguration = getForkConfiguration( "abc\ndef", null );
 
         final Commandline commandLine =
-            forkConfiguration.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), false, false,
+            forkConfiguration.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), null, null, false, false,
                                                  null, 1 );
         assertTrue( commandLine.toString().contains( "abc def" ) );
     }
@@ -76,7 +76,7 @@ public class ForkConfigurationTest
         File cwd = new File( baseDir, "fork_${surefire.forkNumber}" );
 
         ForkConfiguration config = getForkConfiguration( null, "java", cwd.getCanonicalFile() );
-        Commandline commandLine = config.createCommandLine( Collections.<String>emptyList(), true, false, null, 1 );
+        Commandline commandLine = config.createCommandLine( Collections.<String>emptyList(), null, null, true, false, null, 1 );
 
         File forkDirectory = new File( baseDir, "fork_1" );
         forkDirectory.deleteOnExit();
@@ -101,7 +101,7 @@ public class ForkConfigurationTest
 
         try
         {
-            config.createCommandLine( Collections.<String>emptyList(), true, false, null, 1 );
+            config.createCommandLine( Collections.<String>emptyList(), null, null, true, false, null, 1 );
         }
         catch ( SurefireBooterForkException sbfe )
         {
@@ -130,7 +130,7 @@ public class ForkConfigurationTest
 
         try
         {
-            config.createCommandLine( Collections.<String>emptyList(), true, false, null, 1 );
+            config.createCommandLine( Collections.<String>emptyList(), null, null, true, false, null, 1 );
         }
         catch ( SurefireBooterForkException sbfe )
         {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6ba5602..567e763 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>maven-parent</artifactId>
     <groupId>org.apache.maven</groupId>
-    <version>26</version>
+    <version>30</version>
     <relativePath>../pom/maven/pom.xml</relativePath>
   </parent>
 
@@ -86,11 +86,10 @@
   </distributionManagement>
 
   <properties>
-    <maven.compiler.source>1.6</maven.compiler.source>
-    <maven.compiler.target>1.6</maven.compiler.target>
+    <javaVersion>7</javaVersion>
     <mavenVersion>2.2.1</mavenVersion>
     <!-- <shadedVersion>2.12.4</shadedVersion> commented out due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
-    <mavenPluginPluginVersion>3.3</mavenPluginPluginVersion>
+    <mavenPluginPluginVersion>3.5</mavenPluginPluginVersion>
     <commonsLang3Version>3.5</commonsLang3Version>
     <commonsIoVersion>2.5</commonsIoVersion>
     <mavenSharedUtilsVersion>0.9</mavenSharedUtilsVersion>
@@ -353,7 +352,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>animal-sniffer-maven-plugin</artifactId>
-          <version>1.15</version>
+          <version>1.16</version>
           <executions>
             <execution>
               <id>signature-check</id>
@@ -388,7 +387,7 @@
         </plugin>
         <plugin>
           <artifactId>maven-shade-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.0</version>
         </plugin>
         <plugin>
           <artifactId>maven-plugin-plugin</artifactId>
@@ -447,6 +446,18 @@
               </rules>
             </configuration>
           </execution>
+          <execution>
+            <id>enforce-bytecode-version</id>
+            <configuration>
+             <rules>
+               <enforceBytecodeVersion>
+                 <ignoreClasses>
+                   <ignoreClass>module-info</ignoreClass>
+                 </ignoreClasses> 
+               </enforceBytecodeVersion>
+             </rules>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
       <plugin>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
index 0e84315..397955c 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
+import java.io.File;
+
 /**
  * Represents the classpaths for the BooterConfiguration.
  * <br>
@@ -40,6 +42,10 @@ public class ClasspathConfiguration
     private final Classpath classpathUrls;
 
     private final Classpath surefireClasspathUrls;
+    
+    private final Classpath modulepathUrls;
+    
+    private final File moduleDescriptor;
 
     /**
      * The surefire classpath to use when invoking in-process with the plugin
@@ -57,15 +63,15 @@ public class ClasspathConfiguration
 
     public ClasspathConfiguration( boolean enableAssertions, boolean childDelegation )
     {
-        this( Classpath.emptyClasspath(), Classpath.emptyClasspath(), Classpath.emptyClasspath(), enableAssertions,
-              childDelegation );
+        this( Classpath.emptyClasspath(), Classpath.emptyClasspath(), Classpath.emptyClasspath(), 
+              enableAssertions, childDelegation );
     }
 
     ClasspathConfiguration( PropertiesWrapper properties )
     {
         this( properties.getClasspath( CLASSPATH ), properties.getClasspath( SUREFIRE_CLASSPATH ),
-              Classpath.emptyClasspath(),
-              properties.getBooleanProperty( ENABLE_ASSERTIONS ), properties.getBooleanProperty( CHILD_DELEGATION ) );
+              Classpath.emptyClasspath(), properties.getBooleanProperty( ENABLE_ASSERTIONS ),
+              properties.getBooleanProperty( CHILD_DELEGATION ) );
     }
 
     public ClasspathConfiguration( Classpath testClasspath, Classpath surefireClassPathUrls, Classpath inprocClasspath,
@@ -76,6 +82,21 @@ public class ClasspathConfiguration
         this.inprocClasspath = inprocClasspath;
         this.classpathUrls = testClasspath;
         this.surefireClasspathUrls = surefireClassPathUrls;
+        this.moduleDescriptor = null;
+        this.modulepathUrls = null;
+    }
+
+    public ClasspathConfiguration( Classpath testClasspath, Classpath testModulepath, Classpath surefireClassPathUrls,
+                                   Classpath inprocClasspath, File moduleDescriptor, boolean enableAssertions,
+                                   boolean childDelegation )
+    {
+        this.enableAssertions = enableAssertions;
+        this.childDelegation = childDelegation;
+        this.inprocClasspath = inprocClasspath;
+        this.classpathUrls = testClasspath;
+        this.modulepathUrls = testModulepath;
+        this.surefireClasspathUrls = surefireClassPathUrls;
+        this.moduleDescriptor = moduleDescriptor;
     }
 
     public ClassLoader createMergedClassLoader()
@@ -94,6 +115,16 @@ public class ClasspathConfiguration
     {
         return classpathUrls;
     }
+    
+    public Classpath getTestModulepath()
+    {
+        return modulepathUrls;
+    }
+    
+    public File getModuleDescriptor()
+    {
+        return moduleDescriptor;
+    }
 
     public void trickClassPathWhenManifestOnlyClasspath()
         throws SurefireExecutionException

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/pom.xml b/surefire-integration-tests/pom.xml
index d9142de..75b5918 100644
--- a/surefire-integration-tests/pom.xml
+++ b/surefire-integration-tests/pom.xml
@@ -94,6 +94,7 @@
         <artifactId>maven-failsafe-plugin</artifactId>
         <version>2.12.4</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
         <configuration>
+          <jvm>${test.jre}/bin/java</jvm>
           <runOrder>alphabetical</runOrder>
           <threadCount>1</threadCount>
           <perCoreThreadCount>false</perCoreThreadCount>
@@ -115,6 +116,7 @@
             <useInterpolatedSettings>${useInterpolatedSettings}</useInterpolatedSettings>
             <testBuildDirectory>${project.build.testOutputDirectory}</testBuildDirectory>
             <verifier.forkMode>${verifier.forkMode}</verifier.forkMode>
+            <maven.compiler.executable>${test.jre}/bin/javac</maven.compiler.executable>
           </systemPropertyVariables>
           <redirectTestOutputToFile>false</redirectTestOutputToFile>
         </configuration>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
new file mode 100644
index 0000000..29b9f8f
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
@@ -0,0 +1,42 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * 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.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.junit.Test;
+
+public class ModulePathIT extends SurefireJUnit4IntegrationTestCase
+{
+    @Test
+    public void testModulePath()
+    {
+        String testJre = System.getProperty( "test.jre" );
+        
+        SurefireLauncher launcher = unpack( "/modulepath" );
+        
+        if ( testJre != null )
+        {
+            launcher.setLauncherJavaHome( testJre ).debugLogging();
+        }
+        
+        launcher.executeTest().verifyErrorFreeLog();
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/src/test/resources/modulepath/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/modulepath/pom.xml b/surefire-integration-tests/src/test/resources/modulepath/pom.xml
new file mode 100644
index 0000000..445dfdc
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/modulepath/pom.xml
@@ -0,0 +1,43 @@
+<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/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>foo</groupId>
+  <artifactId>app</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>app</name>
+
+  <properties>
+    <maven.compiler.release>9</maven.compiler.release>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.6.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>${surefire.version}</version>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>joda-time</groupId>
+      <artifactId>joda-time</artifactId>
+      <version>2.9.9</version>
+    </dependency>
+    <dependency>
+      <groupId>org.testng</groupId>
+      <artifactId>testng</artifactId>
+      <version>6.11</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
new file mode 100644
index 0000000..754e777
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
@@ -0,0 +1,33 @@
+package com.app;
+
+/*
+ * 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.joda.time.DateTime;
+
+public class Main {
+    public static void main( String[] args ) {
+
+	System.out.println("module path => " + System.getProperty("jdk.module.path"));
+	System.out.println(" class path => " + System.getProperty("java.class.path"));
+
+	DateTime dt = new DateTime();
+	System.out.println(dt);
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
new file mode 100644
index 0000000..5f3eed4
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+module com.app {
+    requires joda.time;
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/14191e51/surefire-integration-tests/src/test/resources/modulepath/src/test/java/com/app/AppTest.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/modulepath/src/test/java/com/app/AppTest.java b/surefire-integration-tests/src/test/resources/modulepath/src/test/java/com/app/AppTest.java
new file mode 100644
index 0000000..e3335aa
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/modulepath/src/test/java/com/app/AppTest.java
@@ -0,0 +1,39 @@
+package com.app;
+
+/*
+ * 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.testng.*;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class AppTest
+{
+    public void testNoop() throws Exception
+    {
+        assertTrue( true );
+    }
+
+    public void testMain() throws Exception
+    {
+        Main.main( new String[0] );
+        assertTrue( true );
+    }
+}