Author: jvanzyl
Date: Sat Dec 3 14:50:06 2005
New Revision: 352042
URL: http://svn.apache.org/viewcvs?rev=352042&view=rev
Log:
o adding support for forking
Added:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
(with props)
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
(with props)
Modified:
maven/surefire/trunk/surefire-booter/pom.xml
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooter.java
Modified: maven/surefire/trunk/surefire-booter/pom.xml
URL:
http://svn.apache.org/viewcvs/maven/surefire/trunk/surefire-booter/pom.xml?rev=352042&r1=352041&r2=352042&view=diff
==============================================================================
--- maven/surefire/trunk/surefire-booter/pom.xml (original)
+++ maven/surefire/trunk/surefire-booter/pom.xml Sat Dec 3 14:50:06 2005
@@ -14,5 +14,23 @@
<artifactId>surefire</artifactId>
<version>1.5-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact-manager</artifactId>
+ <version>2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
Added:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
URL:
http://svn.apache.org/viewcvs/maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java?rev=352042&view=auto
==============================================================================
---
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
(added)
+++
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
Sat Dec 3 14:50:06 2005
@@ -0,0 +1,177 @@
+package org.codehaus.surefire;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is executed when SurefireBooter forks surefire JUnit processes
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Andy Glick</a>
+ * @version $Id$
+ */
+public class ForkedSurefireRunner
+{
+ public static String FORK_ONCE = "once";
+
+ public static String FORK_PERTEST = "pertest";
+
+ static int TESTS_SUCCEEDED = 0;
+
+ static int TESTS_FAILED = 255;
+
+ static int ILLEGAL_ARGUMENT_EXCEPTION = 100;
+
+ static int OTHER_EXCEPTION = 200;
+
+ private static Class thisClass = ForkedSurefireRunner.class;
+
+ private ForkedSurefireRunner()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a Map from a set of strings of the form <key>=<value>
+ *
+ * @param args an array of strings composed of name/value pairs
+ * @return Map keyed by the names with the respective values
+ */
+ private static Map getArgMap( String[] args )
+ {
+ Map argMap = new LinkedHashMap();
+
+ for ( int i = 0; i < args.length; i++ )
+ {
+ String[] mapArgs = args[i].split( "=" );
+
+ argMap.put( mapArgs[0], mapArgs[1] );
+ }
+
+ return argMap;
+ }
+
+ /**
+ * This method is invoked when Surefire is forked - this method parses and
+ * organizes the arguments passed to it and then calls the Surefire class'
+ * run method.
+ *
+ * @param args
+ * @throws Exception
+ */
+ public static void main( String[] args )
+ throws Exception
+ {
+ Map argMap = getArgMap( args );
+
+ ClassLoader surefireClassLoader = thisClass.getClassLoader();
+
+ String batteryExecutorName = (String) argMap.get(
"batteryExecutorName" );
+
+ Class batteryExecutorClass = surefireClassLoader.loadClass(
batteryExecutorName );
+
+ Object batteryExecutor = batteryExecutorClass.newInstance();
+
+ String reports = (String) argMap.get( "reportClassNames" );
+
+ String[] reportClasses = reports.split( "," );
+
+ List reportList = Arrays.asList( reportClasses );
+
+ String batteryConfig = (String) argMap.get( "batteryConfig" );
+
+ String[] batteryParts = batteryConfig.split( "\\|" );
+
+ String batteryClassName = batteryParts[0];
+
+ Object[] batteryParms;
+
+ String forkMode = (String) argMap.get( "forkMode" );
+
+ if ( forkMode.equals( FORK_ONCE ) )
+ {
+ batteryParms = new Object[batteryParts.length - 1];
+
+ batteryParms[0] = new File( batteryParts[1] );
+
+ String stringList = batteryParts[2];
+
+ if ( stringList.startsWith( "[" ) && stringList.endsWith( "]" ) )
+ {
+ stringList = stringList.substring( 1, stringList.length() - 1
);
+ }
+
+ ArrayList includesList = new ArrayList();
+
+ String[] stringArray = stringList.split( "," );
+
+ for ( int i = 0; i < stringArray.length; i++ )
+ {
+ includesList.add( stringArray[i].trim() );
+ }
+
+ batteryParms[1] = includesList;
+
+ stringList = batteryParts[3];
+
+ ArrayList excludesList = new ArrayList();
+
+ if ( stringList.startsWith( "[" ) && stringList.endsWith( "]" ) )
+ {
+ stringList = stringList.substring( 1, stringList.length() - 1
);
+ }
+
+ stringArray = stringList.split( "," );
+
+ for ( int i = 0; i < stringArray.length; i++ )
+ {
+ excludesList.add( stringArray[i].trim() );
+ }
+
+ batteryParms[2] = excludesList;
+ }
+ else
+ {
+ batteryParms = new Object[1];
+
+ batteryParms[0] = batteryParts[1];
+ }
+
+ List batteryHolders = new ArrayList();
+
+ batteryHolders.add( new Object[]{batteryClassName, batteryParms} );
+
+ String reportsDirectory = (String) argMap.get( "reportsDirectory" );
+
+ Method run = batteryExecutorClass.getMethod( "run", new
Class[]{List.class, List.class, String.class} );
+
+ Object[] parms = new Object[]{reportList, batteryHolders,
reportsDirectory};
+
+ int returnCode = TESTS_FAILED;
+
+ try
+ {
+ boolean result = ( (Boolean) run.invoke( batteryExecutor, parms )
).booleanValue();
+
+ if ( result )
+ {
+ returnCode = TESTS_SUCCEEDED;
+ }
+
+ }
+ catch ( IllegalArgumentException e )
+ {
+ returnCode = ILLEGAL_ARGUMENT_EXCEPTION;
+ }
+ catch ( Exception e )
+ {
+ returnCode = OTHER_EXCEPTION;
+ }
+
+ System.exit( returnCode );
+ }
+}
Propchange:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/ForkedSurefireRunner.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Modified:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooter.java
URL:
http://svn.apache.org/viewcvs/maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooter.java?rev=352042&r1=352041&r2=352042&view=diff
==============================================================================
---
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooter.java
(original)
+++
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooter.java
Sat Dec 3 14:50:06 2005
@@ -16,17 +16,31 @@
* limitations under the License.
*/
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.codehaus.plexus.util.cli.StreamConsumer;
+import org.codehaus.plexus.util.cli.WriterStreamConsumer;
+
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-import java.util.StringTokenizer;
+/**
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a>
+ * @author <a href="mail-to:[EMAIL PROTECTED]">Emmanuel Venisse</a>
+ * @version $Id$
+ */
public class SurefireBooter
{
+ private static String RUNNER =
"org.codehaus.surefire.ForkedSurefireRunner";
+
private List batteries = new ArrayList();
private List reports = new ArrayList();
@@ -35,6 +49,10 @@
private String reportsDirectory;
+ private String forkMode;
+
+ private String basedir;
+
public SurefireBooter()
{
}
@@ -44,14 +62,19 @@
this.reportsDirectory = reportsDirectory;
}
+ public String getReportsDirectory()
+ {
+ return this.reportsDirectory;
+ }
+
public void addBattery( String battery, Object[] params )
{
- batteries.add( new Object[]{ battery, params } );
+ batteries.add( new Object[]{battery, params} );
}
public void addBattery( String battery )
{
- batteries.add( new Object[]{ battery, null } );
+ batteries.add( new Object[]{battery, null} );
}
public void addReport( String report )
@@ -72,12 +95,36 @@
this.classpathUrls = classpathUrls;
}
+ public void setForkMode( String forkMode )
+ {
+ this.forkMode = forkMode;
+ }
+
public boolean run()
throws Exception
{
- ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
+ boolean result = false;
+
+ if ( "once".equals( forkMode ) )
+ {
+ result = runTestsForkOnce();
+ }
+ else if ( "none".equals( forkMode ) )
+ {
+ result = runTestsInProcess();
+ }
+ else if ( "pertest".equals( forkMode ) )
+ {
+ result = runTestsForkEach();
+ }
- IsolatedClassLoader surefireClassLoader = new IsolatedClassLoader(
systemLoader );
+ return result;
+ }
+
+ private IsolatedClassLoader createClassLoader()
+ throws Exception
+ {
+ IsolatedClassLoader surefireClassLoader = new IsolatedClassLoader(
ClassLoader.getSystemClassLoader() );
for ( Iterator i = classpathUrls.iterator(); i.hasNext(); )
{
@@ -93,142 +140,278 @@
surefireClassLoader.addURL( f.toURL() );
}
+ return surefireClassLoader;
+ }
+
+ private boolean runTestsInProcess()
+ throws Exception
+ {
+ IsolatedClassLoader surefireClassLoader = createClassLoader();
+
Class batteryExecutorClass = surefireClassLoader.loadClass(
"org.codehaus.surefire.Surefire" );
Object batteryExecutor = batteryExecutorClass.newInstance();
- Method run = batteryExecutorClass.getMethod( "run", new Class[] {
List.class, List.class, ClassLoader.class, String.class } );
+ Method run = batteryExecutorClass.getMethod( "run", new
Class[]{List.class, List.class, ClassLoader.class, String.class} );
- ClassLoader oldContextClassLoader =
Thread.currentThread().getContextClassLoader();
+ ClassLoader oldContextClassLoader = Thread.currentThread()
.getContextClassLoader();
Thread.currentThread().setContextClassLoader( surefireClassLoader );
- Boolean result = (Boolean) run.invoke( batteryExecutor, new Object[]{
reports, batteries, surefireClassLoader, reportsDirectory } );
+ Boolean result = (Boolean) run.invoke( batteryExecutor, new
Object[]{reports, batteries, surefireClassLoader, reportsDirectory} );
Thread.currentThread().setContextClassLoader( oldContextClassLoader );
return result.booleanValue();
}
- public void reset()
- {
- batteries.clear();
+ protected static final String EOL = System.getProperty( "line.separator" );
- reports.clear();
+ protected static final String PS = System.getProperty( "path.separator" );
- classpathUrls.clear();
+ private boolean runTestsForkOnce()
+ throws Exception
+ {
+ return fork( getForkOnceArgs() );
}
- // ----------------------------------------------------------------------
- // Main
- // ----------------------------------------------------------------------
+ private boolean runTestsForkEach()
+ throws Exception
+ {
+ boolean noFailures = true;
+
+ List testClasses = getTestClasses();
+
+ for ( Iterator i = testClasses.iterator(); i.hasNext(); )
+ {
+ String testClass = (String) i.next();
+
+ boolean result = fork( getForkPerTestArgs( testClass ) );
- public static void main( String[] args )
+ if ( !result )
+ {
+ noFailures = false;
+ }
+ }
+
+ return noFailures;
+ }
+
+ private boolean fork( String[] args )
throws Exception
{
- // 0: basedir
- String basedir = args[0];
+ String executable = "java";
- System.setProperty( "basedir", basedir );
+ File workingDirectory = new File( "." );
- // 1; testClassesDirectory
- String testClassesDirectory = args[1];
+ Commandline cli = new Commandline();
- // 2; includes
+ basedir = workingDirectory.getAbsolutePath();
- // 3: excludes
+ cli.setWorkingDirectory( basedir );
+ cli.setExecutable( executable );
- String mavenRepoLocal = args[1];
+ cli.addArguments( args );
- File dependenciesFile = new File( args[2] );
+ Writer stringWriter = new StringWriter();
- List dependencies = new ArrayList();
+ StreamConsumer out = new WriterStreamConsumer( stringWriter );
- BufferedReader buf = new BufferedReader( new FileReader(
dependenciesFile ) );
+ StreamConsumer err = new WriterStreamConsumer( stringWriter );
- String line;
+ int returnCode;
- while ( ( line = buf.readLine() ) != null )
+ try
{
- dependencies.add( line );
+ returnCode = CommandLineUtils.executeCommandLine( cli, out, err );
+ }
+ catch ( CommandLineException e )
+ {
+ throw new Exception( "Error while executing forked tests.", e );
+ }
+ catch ( Exception e )
+ {
+ throw new SurefireBooterForkException( "Error while executing
forked tests.", e );
}
- buf.close();
+ String string = stringWriter.toString();
- File includesFile = new File( args[3] );
+ if ( string != null && string.length() > 0 )
+ {
+ StringReader sr = new StringReader( string );
- List includes = new ArrayList();
+ BufferedReader br = new BufferedReader( sr );
- buf = new BufferedReader( new FileReader( includesFile ) );
+ while ( ( string = br.readLine() ) != null )
+ {
+ System.out.println( string );
+ }
+ }
- line = buf.readLine();
+ if ( returnCode != 0 )
+ {
+ return false;
+ }
- String includesStr = line.substring( line.indexOf( "@" ) + 1 );
+ return true;
+ }
+
+ private List getTestClasses()
+ throws Exception
+ {
- StringTokenizer st = new StringTokenizer( includesStr, "," );
+ IsolatedClassLoader classLoader = createClassLoader();
- while ( st.hasMoreTokens() )
+ List instantiatedBatteries = Surefire.instantiateBatteries( batteries,
classLoader );
+
+ List testClasses = new ArrayList();
+
+ for ( Iterator i = instantiatedBatteries.iterator(); i.hasNext(); )
{
- String inc = st.nextToken().trim();
+ Object o = i.next();
+
+ Method m = o.getClass().getMethod( "getSubBatteryClassNames", new
Class[]{} );
- includes.add( inc );
+ List tests = (List) m.invoke( o, new Object[]{} );
+
+ // This class comes from a different classloader then the isolated
classloader.
+ // This is the battery class that is from a different loader.
+
+ testClasses.addAll( tests );
}
- buf.close();
+ return testClasses;
+ }
- File excludesFile = new File( args[4] );
+ private String[] getForkOnceArgs()
+ throws Exception
+ {
+ // List reports
+ // List batteryHolders
+ // List classpathUrls
+ // String reportsDirectory
+ // String forkMode
- List excludes = new ArrayList();
+ String pathSeparator = System.getProperty( "path.separator" );
- buf = new BufferedReader( new FileReader( excludesFile ) );
+ String classpathEntries = getListOfStringsAsString( classpathUrls,
pathSeparator );
- line = buf.readLine();
+ String reportClassNames = getListOfStringsAsString( reports, "," );
- String excludesStr = line.substring( line.indexOf( "@" ) + 1 );
+ String[] batteryConfig = getStringArrayFromBatteries();
- st = new StringTokenizer( excludesStr, "," );
+ String[] argArray =
+ {
+ "-classpath",
+ classpathEntries,
+ RUNNER,
+ "reportClassNames=" + reportClassNames,
+ "reportsDirectory=" + reportsDirectory,
+ "batteryExecutorName=" + "org.codehaus.surefire.Surefire",
+ "forkMode=" + forkMode,
+ "batteryConfig=" + batteryConfig[0]
+ };
- while ( st.hasMoreTokens() )
- {
- excludes.add( st.nextToken().trim() );
- }
+ return argArray;
+ }
- buf.close();
+ private String[] getForkPerTestArgs( String testClass )
+ throws Exception
+ {
+ // List reports
+ // List batteryHolders
+ // List classpathUrls
+ // String reportsDirectory
+ // String forkMode
- SurefireBooter surefireBooter = new SurefireBooter();
+ String pathSeparator = System.getProperty( "path.separator" );
- System.out.println( "testClassesDirectory = " + testClassesDirectory );
+ String classpathEntries = getListOfStringsAsString( classpathUrls,
pathSeparator );
- System.out.println( "includes = " + includes );
+ String reportClassNames = getListOfStringsAsString( reports, "," );
- System.out.println( "excludes = " + excludes );
+ String batteryConfig =
"org.codehaus.surefire.battery.SingleTestBattery|" + testClass;
- surefireBooter.addBattery(
"org.codehaus.surefire.battery.DirectoryBattery", new Object[]{
testClassesDirectory, includes, excludes } );
+ String[] argArray =
+ {
+ "-classpath",
+ classpathEntries,
+ RUNNER,
+ "reportClassNames=" + reportClassNames,
+ "reportsDirectory=" + reportsDirectory,
+ "batteryExecutorName=" + "org.codehaus.surefire.Surefire",
+ "forkMode=" + forkMode,
+ "batteryConfig=" + batteryConfig
+ };
- surefireBooter.addClassPathUrl( new File( mavenRepoLocal,
"junit/jars/junit-3.8.1.jar" ).getPath() );
+ return argArray;
+ }
- surefireBooter.addClassPathUrl( new File( mavenRepoLocal,
"surefire/jars/surefire-1.3-SNAPSHOT.jar" ).getPath() );
+ public void reset()
+ {
+ batteries.clear();
- surefireBooter.addClassPathUrl( new File( testClassesDirectory,
"target/classes/" ).getPath() );
+ reports.clear();
- surefireBooter.addClassPathUrl( new File( testClassesDirectory,
"target/test-classes/" ).getPath() );
+ classpathUrls.clear();
+ }
- processDependencies( dependencies, surefireBooter );
+ private String getListOfStringsAsString( List listOfStrings,
+ String delimiterParm )
+ {
+ StringBuffer stringBuffer = new StringBuffer();
- surefireBooter.addReport( "org.codehaus.surefire.report.ConsoleReport"
);
+ Iterator listOfStringsIterator = listOfStrings.iterator();
+
+ String delimiter = "";
+
+ while ( listOfStringsIterator.hasNext() )
+ {
+ String string = (String) listOfStringsIterator.next();
- surefireBooter.run();
+ stringBuffer.append( delimiter );
+
+ stringBuffer.append( string );
+
+ delimiter = delimiterParm;
+ }
+
+ return new String( stringBuffer );
}
- private static void processDependencies( List dependencies, SurefireBooter
sureFire )
- throws Exception
+ private String[] getStringArrayFromBatteries()
{
- for ( Iterator i = dependencies.iterator(); i.hasNext(); )
+ String[] batteryConfig = new String[batteries.size()];
+
+ StringBuffer batteryBuffer = new StringBuffer();
+
+ String delimiter = "";
+
+ int batteryCounter = 0;
+
+ for ( Iterator j = batteries.iterator(); j.hasNext(); )
{
- String dep = (String) i.next();
-
- sureFire.addClassPathUrl( new File( dep ).getPath() );
+ Object[] batteryArray = (Object[]) j.next();
+
+ batteryBuffer.append( (String) batteryArray[0] );
+
+ if ( batteryArray[1] != null )
+ {
+ Object[] batteryParms = (Object[]) batteryArray[1];
+
+ for ( int i = 0; i < 3; i++ )
+ {
+ batteryBuffer.append( "|" );
+
+ batteryBuffer.append( batteryParms[i] );
+ }
+ }
+
+ batteryConfig[batteryCounter++] = new String( batteryBuffer );
}
+
+ return batteryConfig;
}
}
+
Added:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
URL:
http://svn.apache.org/viewcvs/maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java?rev=352042&view=auto
==============================================================================
---
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
(added)
+++
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
Sat Dec 3 14:50:06 2005
@@ -0,0 +1,35 @@
+package org.codehaus.surefire;
+
+/*
+ * Copyright 2001-2005 The Codehaus.
+ *
+ * Licensed 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.
+ */
+
+public class SurefireBooterForkException extends Exception
+{
+ public SurefireBooterForkException(String message)
+ {
+ super(message);
+ }
+
+ public SurefireBooterForkException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public SurefireBooterForkException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
Propchange:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
maven/surefire/trunk/surefire-booter/src/main/java/org/codehaus/surefire/SurefireBooterForkException.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"