You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ke...@apache.org on 2006/12/19 03:38:10 UTC

svn commit: r488508 - in /maven/sandbox/surefire-plugin-merge: maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/ surefire-booter/ surefire-booter/src/main/java/org/apache/maven/surefire/booter/

Author: kenney
Date: Mon Dec 18 18:38:09 2006
New Revision: 488508

URL: http://svn.apache.org/viewvc?view=rev&rev=488508
Log:
PR: MSUREFIRE-115, MSUREFIRE-121

Add boolean parameter 'useSystemClassLoader', used when forking tests, to put all tests
in the System classloader.

I also found a nice way to circumvent the possibly long commandline arguments when specifying
all classpath elements (and dependencies) at the '-classpath' parameter: I create an empty
uncompressed jar with a Main-Class attribute for SurefireBooter and a Class-Path entry containing
all the classpath elements. The fork is then done using 'java -jar'.

I do NOT allow a partial classpath to be specified with -classpath since that either requires 
duplicate classpath entries, or all dependencies to be specified on the commandline too.

Modified:
    maven/sandbox/surefire-plugin-merge/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
    maven/sandbox/surefire-plugin-merge/surefire-booter/pom.xml
    maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkConfiguration.java
    maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireBooter.java

Modified: maven/sandbox/surefire-plugin-merge/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
URL: http://svn.apache.org/viewvc/maven/sandbox/surefire-plugin-merge/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java?view=diff&rev=488508&r1=488507&r2=488508
==============================================================================
--- maven/sandbox/surefire-plugin-merge/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java (original)
+++ maven/sandbox/surefire-plugin-merge/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java Mon Dec 18 18:38:09 2006
@@ -98,6 +98,7 @@
      */
     private File basedir;
 
+    // FIXME this field is not used
     /**
      * The directory containing generated classes of the project being tested.
      *
@@ -373,27 +374,20 @@
      */
     private boolean disableXmlReport;
 
+    /**
+     * Option to pass dependencies to the system's classloader instead of using an isolated class loader when
+     * forking. Prevents problems with JDKs which implement the service provider lookup mechanism by using
+     * the system's classloader.
+     *
+     * @parameter expression="${surefire.useSystemClassLoader}" default-value="false"
+     */
+    private boolean useSystemClassLoader;
+
     public void execute()
         throws MojoExecutionException, MojoFailureException
     {
-        if ( skip || skipExec )
-        {
-            getLog().info( "Tests are skipped." );
-        }
-        else if ( !testClassesDirectory.exists() )
-        {
-            getLog().info( "No tests to run." );
-        }
-        else
+        if ( verifyParameters() )
         {
-            if ( parallel )
-            {
-                if ( threadCount < 1 )
-                {
-                    throw new MojoFailureException( "Must have at least one thread in parallel mode" );
-                }
-            }
-
             SurefireBooter surefireBooter = constructSurefireBooter();
 
             getLog().info( "Surefire report directory: " + reportsDirectory );
@@ -434,6 +428,36 @@
         }
     }
 
+    private boolean verifyParameters()
+        throws MojoFailureException
+    {
+        if ( skip || skipExec )
+        {
+            getLog().info( "Tests are skipped." );
+            return false;
+        }
+        else if ( !testClassesDirectory.exists() )
+        {
+            getLog().info( "No tests to run." );
+            return false;
+        }
+
+        if ( parallel )
+        {
+            if ( threadCount < 1 )
+            {
+                throw new MojoFailureException( "Must have at least one thread in parallel mode" );
+            }
+        }
+
+        if ( useSystemClassLoader && ForkConfiguration.FORK_NEVER.equals( forkMode ) )
+        {
+            getLog().warn( "useSystemClassloader=true setting has no effect when not forking" );
+        }
+
+        return true;
+    }
+
     private SurefireBooter constructSurefireBooter()
         throws MojoExecutionException, MojoFailureException
     {
@@ -646,6 +670,8 @@
         surefireBooter.setChildDelegation( childDelegation );
 
         surefireBooter.setReportsDirectory( reportsDirectory );
+
+        surefireBooter.setUseSystemClassLoader( useSystemClassLoader );
 
         addReporters( surefireBooter, fork.isForking() );
 

Modified: maven/sandbox/surefire-plugin-merge/surefire-booter/pom.xml
URL: http://svn.apache.org/viewvc/maven/sandbox/surefire-plugin-merge/surefire-booter/pom.xml?view=diff&rev=488508&r1=488507&r2=488508
==============================================================================
--- maven/sandbox/surefire-plugin-merge/surefire-booter/pom.xml (original)
+++ maven/sandbox/surefire-plugin-merge/surefire-booter/pom.xml Mon Dec 18 18:38:09 2006
@@ -33,6 +33,17 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-archiver</artifactId>
+      <version>1.0-alpha-7</version>
+      <exclusions> <!-- exclude plexus-utils since it's 1.2 and we need 1.1 -->
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>3.8.1</version>

Modified: maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkConfiguration.java
URL: http://svn.apache.org/viewvc/maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkConfiguration.java?view=diff&rev=488508&r1=488507&r2=488508
==============================================================================
--- maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkConfiguration.java (original)
+++ maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkConfiguration.java Mon Dec 18 18:38:09 2006
@@ -16,9 +16,14 @@
  * limitations under the License.
  */
 
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+import org.codehaus.plexus.archiver.jar.Manifest;
+import org.codehaus.plexus.archiver.jar.ManifestException;
 import org.codehaus.plexus.util.StringUtils;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -29,6 +34,7 @@
  * Configuration for forking tests.
  *
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
  */
 public class ForkConfiguration
 {
@@ -112,7 +118,18 @@
         return systemProperties;
     }
 
+    /**
+     * @throws SurefireBooterForkException
+     * @deprecated use the 2-arg alternative.
+     */
     public Commandline createCommandLine( List classPath )
+        throws SurefireBooterForkException
+    {
+        return createCommandLine( classPath, false );
+    }
+
+    public Commandline createCommandLine( List classPath, boolean useJar )
+        throws SurefireBooterForkException
     {
         Commandline cli = new Commandline();
 
@@ -143,15 +160,84 @@
                 "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005" );
         }
 
-        cli.createArgument().setValue( "-classpath" );
+        if ( useJar )
+        {
+            File jarFile;
+            try
+            {
+                jarFile = createJar( classPath );
+            }
+            catch ( IOException e )
+            {
+                throw new SurefireBooterForkException( "Error creating archive file", e );
+            }
+            catch ( ManifestException e )
+            {
+                throw new SurefireBooterForkException( "Error creating manifest", e );
+            }
+            catch ( ArchiverException e )
+            {
+                throw new SurefireBooterForkException( "Error creating archive", e );
+            }
+
+            cli.createArgument().setValue( "-jar" );
+
+            cli.createArgument().setValue( jarFile.getAbsolutePath() );
+        }
+        else
+        {
+            cli.createArgument().setValue( "-classpath" );
 
-        cli.createArgument().setValue( StringUtils.join( classPath.iterator(), File.pathSeparator ) );
+            cli.createArgument().setValue( StringUtils.join( classPath.iterator(), File.pathSeparator ) );
 
-        cli.createArgument().setValue( SurefireBooter.class.getName() );
+            cli.createArgument().setValue( SurefireBooter.class.getName() );
+        }
 
         cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
 
         return cli;
+    }
+
+    /**
+     * Create a jar with just a manifest containing a Main-Class entry for SurefireBooter and a Class-Path entry
+     * for all classpath elements.
+     * @param classPath List&lt;String> of all classpath elements.
+     * @return
+     * @throws IOException
+     * @throws ManifestException
+     * @throws ArchiverException
+     */
+    private static File createJar( List classPath )
+        throws IOException, ManifestException, ArchiverException
+    {
+        JarArchiver jar = new JarArchiver();
+        jar.setCompress( false ); // for speed
+        File file = File.createTempFile( "surefirebooter", ".jar" );
+        file.deleteOnExit();
+        jar.setDestFile( file );
+
+        Manifest manifest = new Manifest();
+
+        // we can't use StringUtils.join here since we need to add a '/' to
+        // the end of directory entries - otherwise the jvm will ignore them.
+        String cp = "";
+        for ( Iterator it = classPath.iterator(); it.hasNext(); )
+        {
+            String el = (String) it.next();
+            cp += " " + el + ( new File( el ).isDirectory() ? "/" : "" );
+        }
+
+        Manifest.Attribute attr = new Manifest.Attribute( "Class-Path", cp.trim() );
+        manifest.addConfiguredAttribute( attr );
+
+        attr =new Manifest.Attribute("Main-Class", SurefireBooter.class.getName() );
+        manifest.addConfiguredAttribute( attr );
+
+        jar.addConfiguredManifest( manifest );
+
+        jar.createArchive();
+
+        return file;
     }
 
     public void setDebug( boolean debug )

Modified: maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireBooter.java
URL: http://svn.apache.org/viewvc/maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireBooter.java?view=diff&rev=488508&r1=488507&r2=488508
==============================================================================
--- maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireBooter.java (original)
+++ maven/sandbox/surefire-plugin-merge/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireBooter.java Mon Dec 18 18:38:09 2006
@@ -68,6 +68,8 @@
 
     private boolean redirectTestOutputToFile = false;
 
+    private boolean useSystemClassLoader = false;
+
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
@@ -176,6 +178,11 @@
         this.forkConfiguration = forkConfiguration;
     }
 
+    public void setUseSystemClassLoader( boolean useSystemClassLoader )
+    {
+        this.useSystemClassLoader = useSystemClassLoader;
+    }
+
     public boolean run()
         throws SurefireBooterForkException, SurefireExecutionException
     {
@@ -214,7 +221,9 @@
         ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
         try
         {
-            ClassLoader testsClassLoader = createClassLoader( classPathUrls, null, childDelegation, true );
+            ClassLoader testsClassLoader = useSystemClassLoader
+                ? ClassLoader.getSystemClassLoader()
+                : createClassLoader( classPathUrls, null, childDelegation, true );
 
             // TODO: assertions = true shouldn't be required for this CL if we had proper separation (see TestNG)
             ClassLoader surefireClassLoader =
@@ -242,7 +251,7 @@
         {
             throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
         }
-        finally 
+        finally
         {
             Thread.currentThread().setContextClassLoader( oldContextClassLoader );
         }
@@ -255,12 +264,14 @@
 
         //noinspection CatchGenericClass,OverlyBroadCatchBlock
         ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
-        
+
         try
         {
             // The test classloader must be constructed first to avoid issues with commons-logging until we properly
             // separate the TestNG classloader
-            ClassLoader testsClassLoader = createClassLoader( classPathUrls, null, childDelegation, true );
+            ClassLoader testsClassLoader = useSystemClassLoader
+                ? getClass().getClassLoader()//ClassLoader.getSystemClassLoader()
+                : createClassLoader( classPathUrls, null, childDelegation, true );
 
             ClassLoader surefireClassLoader =
                 createClassLoader( surefireClassPathUrls, testsClassLoader, true );
@@ -272,7 +283,6 @@
             Method run = surefireClass.getMethod( "run", new Class[]{List.class, List.class, ClassLoader.class,
                 ClassLoader.class} );
 
-
             Thread.currentThread().setContextClassLoader( testsClassLoader );
 
             Boolean result = (Boolean) run.invoke( surefire, new Object[]{reports, testSuites, surefireClassLoader,
@@ -288,7 +298,7 @@
         {
             throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
         }
-        finally 
+        finally
         {
             Thread.currentThread().setContextClassLoader( oldContextClassLoader );
         }
@@ -416,7 +426,7 @@
         addPropertiesForTypeHolder( reports, properties, "report." );
         addPropertiesForTypeHolder( testSuites, properties, "testSuite." );
 
-        for ( int i = 0; i < classPathUrls.size(); i++ )
+        for ( int i = 0; i < classPathUrls.size() && !useSystemClassLoader; i++ )
         {
             String url = (String) classPathUrls.get( i );
             properties.setProperty( "classPathUrl." + i, url );
@@ -428,13 +438,8 @@
             properties.setProperty( "surefireClassPathUrl." + i, url );
         }
 
-        for ( int i = 0; i < surefireBootClassPathUrls.size(); i++ )
-        {
-            String url = (String) surefireBootClassPathUrls.get( i );
-            properties.setProperty( "surefireBootClassPathUrl." + i, url );
-        }
-
         properties.setProperty( "childDelegation", String.valueOf( childDelegation ) );
+        properties.setProperty( "useSystemClassLoader", String.valueOf( useSystemClassLoader ) );
     }
 
     private File writePropertiesFile( String name, Properties properties )
@@ -512,7 +517,16 @@
             throw new SurefireBooterForkException( "Error creating properties files for forking", e );
         }
 
-        Commandline cli = forkConfiguration.createCommandLine( surefireBootClassPathUrls );
+        List bootClasspath = new ArrayList( surefireBootClassPathUrls.size() + classPathUrls.size() );
+
+        bootClasspath.addAll( surefireBootClassPathUrls );
+
+        if ( useSystemClassLoader )
+        {
+            bootClasspath.addAll( classPathUrls );
+        }
+
+        Commandline cli = forkConfiguration.createCommandLine( bootClasspath, useSystemClassLoader  );
 
         cli.createArgument().setFile( surefireProperties );
 
@@ -783,6 +797,11 @@
                 {
                     surefireBooter.childDelegation =
                         Boolean.valueOf( p.getProperty( "childDelegation" ) ).booleanValue();
+                }
+                else if ( "useSystemClassLoader".equals( name ) )
+                {
+                    surefireBooter.useSystemClassLoader =
+                        Boolean.valueOf( p.getProperty( "useSystemClassLoader" ) ).booleanValue();
                 }
             }