All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.surefire.booter.SurefireBooter Maven / Gradle / Ivy

package org.apache.maven.surefire.booter;

/*
 * 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 java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.maven.surefire.Surefire;
import org.apache.maven.surefire.booter.output.FileOutputConsumerProxy;
import org.apache.maven.surefire.booter.output.ForkingStreamConsumer;
import org.apache.maven.surefire.booter.output.OutputConsumer;
import org.apache.maven.surefire.booter.output.StandardOutputConsumer;
import org.apache.maven.surefire.booter.output.SupressFooterOutputConsumerProxy;
import org.apache.maven.surefire.booter.output.SupressHeaderOutputConsumerProxy;
import org.apache.maven.surefire.testset.TestSetFailedException;
import org.apache.maven.surefire.util.NestedRuntimeException;
import org.apache.maven.surefire.util.UrlUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
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;

/**
 * @author Jason van Zyl
 * @author Emmanuel Venisse
 * @version $Id: SurefireBooter.java 980568 2010-07-29 20:56:29Z krosenvold $
 */
public class SurefireBooter
{
    private static final String TEST_SUITE_PROPERTY_PREFIX = "testSuite.";
    private static final String REPORT_PROPERTY_PREFIX = "report.";
    private static final String PARAMS_SUFIX = ".params";
    private static final String TYPES_SUFIX = ".types";

    private List reports = new ArrayList();

    private List classPathUrls = new ArrayList();

    private List surefireClassPathUrls = new ArrayList();

    private List surefireBootClassPathUrls = new ArrayList();

    private List testSuites = new ArrayList();
    
    private boolean failIfNoTests = false;
    
    private int forkedProcessTimeoutInSeconds = 0;

    private boolean redirectTestOutputToFile = false;

    // ----------------------------------------------------------------------
    //
    // ----------------------------------------------------------------------

    private ForkConfiguration forkConfiguration;

    public static final int TESTS_SUCCEEDED_EXIT_CODE = 0;

    public static final int TESTS_FAILED_EXIT_CODE = 255;
    
    public static final int NO_TESTS_EXIT_CODE = 254;

    private static Method assertionStatusMethod;

    /**
     * @deprecated because the IsolatedClassLoader is really isolated - no parent.
     */
    private boolean childDelegation = true;

    private File reportsDirectory;

    /**
     * This field is set to true if it's running from main. It's used to help decide what classloader to use.
     */
    private final boolean isForked;

    /**
     * Whether to enable assertions or not (can be affected by the fork arguments, and the ability to do so based on the
     * JVM).
     */
    private boolean enableAssertions;

    static
    {
        try
        {
            assertionStatusMethod =
                ClassLoader.class.getMethod( "setDefaultAssertionStatus", new Class[] { boolean.class } );
        }
        catch ( NoSuchMethodException e )
        {
            assertionStatusMethod = null;
        }
    }

    public SurefireBooter()
    {
        isForked = false;
    }

    private SurefireBooter( boolean isForked )
    {
        this.isForked = isForked;
    }

    // ----------------------------------------------------------------------
    // Accessors
    // ----------------------------------------------------------------------

    public void addReport( String report )
    {
        addReport( report, null );
    }

    public void addReport( String report, Object[] constructorParams )
    {
        reports.add( new Object[] { report, constructorParams } );
    }

    public void addTestSuite( String suiteClassName, Object[] constructorParams )
    {
        testSuites.add( new Object[] { suiteClassName, constructorParams } );
    }

    public void addClassPathUrl( String path )
    {
        if ( !classPathUrls.contains( path ) )
        {
            classPathUrls.add( path );
        }
    }

    public void addSurefireClassPathUrl( String path )
    {
        if ( !surefireClassPathUrls.contains( path ) )
        {
            surefireClassPathUrls.add( path );
        }
    }

    public void addSurefireBootClassPathUrl( String path )
    {
        if ( !surefireBootClassPathUrls.contains( path ) )
        {
            surefireBootClassPathUrls.add( path );
        }
    }

    /**
     * Setting this to true will cause a failure if there are no tests to run
     *
     * @param redirectTestOutputToFile
     */
    public void setFailIfNoTests( boolean failIfNoTests )
    {
        this.failIfNoTests = failIfNoTests;
    }
    
    /**
     * When forking, setting this to true will make the test output to be saved in a file instead of showing it on the
     * standard output
     *
     * @param redirectTestOutputToFile
     */
    public void setRedirectTestOutputToFile( boolean redirectTestOutputToFile )
    {
        this.redirectTestOutputToFile = redirectTestOutputToFile;
    }

    /**
     * Set the directory where reports will be saved
     *
     * @param reportsDirectory the directory
     */
    public void setReportsDirectory( File reportsDirectory )
    {
        this.reportsDirectory = reportsDirectory;
    }

    /**
     * Get the directory where reports will be saved
     */
    public File getReportsDirectory()
    {
        return reportsDirectory;
    }

    public void setForkConfiguration( ForkConfiguration forkConfiguration )
    {
        this.forkConfiguration = forkConfiguration;
    }
    
    public boolean isForking()
    {
        return forkConfiguration.isForking();
    }

    public int run()
        throws SurefireBooterForkException, SurefireExecutionException
    {
        int result;

        if (  ForkConfiguration.FORK_NEVER.equals( forkConfiguration.getForkMode() ) )
        {
            result = runSuitesInProcess();
        }
        else if ( ForkConfiguration.FORK_ONCE.equals( forkConfiguration.getForkMode() ) )
        {
            result = runSuitesForkOnce();
        }
        else if ( ForkConfiguration.FORK_ALWAYS.equals( forkConfiguration.getForkMode() ) )
        {
            result = runSuitesForkPerTestSet();
        }
        else
        {
            throw new SurefireExecutionException( "Unknown forkmode: " + forkConfiguration.getForkMode(), null );
        }
        return result;
    }

    private int runSuitesInProcess( String testSet, Properties results )
        throws SurefireExecutionException
    {
        if ( testSuites.size() != 1 )
        {
            throw new IllegalArgumentException( "Cannot only specify testSet for single test suites" );
        }

        // TODO: replace with plexus

        // noinspection CatchGenericClass,OverlyBroadCatchBlock
        ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
        try
        {
            ClassLoader testsClassLoader =
                useSystemClassLoader() ? ClassLoader.getSystemClassLoader() : createClassLoader( classPathUrls, null,
                                                                                                 childDelegation );

            // TODO: assertions = true shouldn't be required for this CL if we had proper separation (see TestNG)
            ClassLoader surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader );

            Class surefireClass = surefireClassLoader.loadClass( Surefire.class.getName() );

            Object surefire = surefireClass.newInstance();

            Method run =
                surefireClass.getMethod( "run", new Class[] { List.class, Object[].class, String.class,
                    ClassLoader.class, ClassLoader.class, Properties.class, Boolean.class } );

            Thread.currentThread().setContextClassLoader( testsClassLoader );

            Integer result =
                (Integer) run.invoke( surefire, new Object[] { reports, testSuites.get( 0 ), testSet,
                    surefireClassLoader, testsClassLoader, results, new Boolean( failIfNoTests ) } );

            return result.intValue();
        }
        catch ( InvocationTargetException e )
        {
            throw new SurefireExecutionException( e.getTargetException().getMessage(), e.getTargetException() );
        }
        catch ( Exception e )
        {
            throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
        }
        finally
        {
            Thread.currentThread().setContextClassLoader( oldContextClassLoader );
        }
    }

    private int runSuitesInProcess()
        throws SurefireExecutionException
    {
        // TODO: replace with plexus

        // 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;
            testsClassLoader = this.getClass().getClassLoader();
            
            ClassLoader surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader );

            Class surefireClass = surefireClassLoader.loadClass( Surefire.class.getName() );

            Object surefire = surefireClass.newInstance();

            Method run =
                surefireClass.getMethod( "run", new Class[] { List.class, List.class, ClassLoader.class,
                    ClassLoader.class, Boolean.class } );

            Thread.currentThread().setContextClassLoader( testsClassLoader );

            Integer result =
                (Integer) run.invoke( surefire, new Object[] { reports, testSuites, surefireClassLoader,
                    testsClassLoader, new Boolean( failIfNoTests ) } );

            return result.intValue();
        }
        catch ( InvocationTargetException e )
        {
            throw new SurefireExecutionException( e.getTargetException().getMessage(), e.getTargetException() );
        }
        catch ( Exception e )
        {
            throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
        }
        finally
        {
            Thread.currentThread().setContextClassLoader( oldContextClassLoader );
        }
    }

    
    
    private String getTestClassPathAsString()
    {
        StringBuffer sb = new StringBuffer();
        for ( int i = 0; i < classPathUrls.size(); i++ )
        {
            sb.append( classPathUrls.get( i ) ).append( File.pathSeparatorChar );
        }
        return sb.toString();
    }
    
    private int runSuitesForkOnce()
        throws SurefireBooterForkException
    {
        return forkSuites( testSuites, true, true );
    }

    private int runSuitesForkPerTestSet()
        throws SurefireBooterForkException
    {
        ClassLoader testsClassLoader;
        ClassLoader surefireClassLoader;
        try
        {
            testsClassLoader = createClassLoader( classPathUrls, null, false );
            // TODO: assertions = true shouldn't be required if we had proper separation (see TestNG)
            surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader, false );
        }
        catch ( MalformedURLException e )
        {
            throw new SurefireBooterForkException( "Unable to create classloader to find test suites", e );
        }

        int globalResult = 0;

        boolean showHeading = true;
        Properties properties = new Properties();
        for ( Iterator i = testSuites.iterator(); i.hasNext(); )
        {
            Object[] testSuite = (Object[]) i.next();

            Map testSets = getTestSets( testSuite, testsClassLoader, surefireClassLoader );

            for ( Iterator j = testSets.keySet().iterator(); j.hasNext(); )
            {
                Object testSet = j.next();
                boolean showFooter = !j.hasNext() && !i.hasNext();
                int result = forkSuite( testSuite, testSet, showHeading, showFooter, properties );
                if ( result > globalResult )
                {
                    globalResult = result;
                }
                showHeading = false;
            }
        }

        return globalResult;
    }

    private Map getTestSets( Object[] testSuite, ClassLoader testsClassLoader, ClassLoader surefireClassLoader )
        throws SurefireBooterForkException
    {
        String className = (String) testSuite[0];

        Object[] params = (Object[]) testSuite[1];

        Object suite;
        try
        {
            suite = Surefire.instantiateObject( className, params, surefireClassLoader );
        }
        catch ( TestSetFailedException e )
        {
            throw new SurefireBooterForkException( e.getMessage(), e.getCause() );
        }
        catch ( ClassNotFoundException e )
        {
            throw new SurefireBooterForkException( "Unable to find class for test suite '" + className + "'", e );
        }
        catch ( NoSuchMethodException e )
        {
            throw new SurefireBooterForkException( "Unable to find appropriate constructor for test suite '"
                + className + "': " + e.getMessage(), e );
        }

        Map testSets;
        try
        {
            Method m = suite.getClass().getMethod( "locateTestSets", new Class[] { ClassLoader.class } );

            testSets = (Map) m.invoke( suite, new Object[] { testsClassLoader } );
        }
        catch ( IllegalAccessException e )
        {
            throw new SurefireBooterForkException( "Error obtaining test sets", e );
        }
        catch ( NoSuchMethodException e )
        {
            throw new SurefireBooterForkException( "Error obtaining test sets", e );
        }
        catch ( InvocationTargetException e )
        {
            throw new SurefireBooterForkException( e.getTargetException().getMessage(), e.getTargetException() );
        }
        return testSets;
    }

    private int forkSuites( List testSuites, boolean showHeading, boolean showFooter )
        throws SurefireBooterForkException
    {
        Properties properties = new Properties();

        setForkProperties( testSuites, properties );

        return fork( properties, showHeading, showFooter );
    }

    private int forkSuite( Object[] testSuite, Object testSet, boolean showHeading, boolean showFooter,
                               Properties properties )
        throws SurefireBooterForkException
    {
        setForkProperties( Collections.singletonList( testSuite ), properties );

        if ( testSet instanceof String )
        {
            properties.setProperty( "testSet", (String) testSet );
        }

        return fork( properties, showHeading, showFooter );
    }

    private void setForkProperties( List testSuites, Properties properties )
    {
        addPropertiesForTypeHolder( reports, properties, REPORT_PROPERTY_PREFIX );
        addPropertiesForTypeHolder( testSuites, properties, TEST_SUITE_PROPERTY_PREFIX );

        for ( int i = 0; i < classPathUrls.size(); i++ )
        {
            String url = (String) classPathUrls.get( i );
            properties.setProperty( "classPathUrl." + i, url );
        }

        for ( int i = 0; i < surefireClassPathUrls.size(); i++ )
        {
            String url = (String) surefireClassPathUrls.get( i );
            properties.setProperty( "surefireClassPathUrl." + i, url );
        }

        properties.setProperty( "childDelegation", String.valueOf( childDelegation ) );
        properties.setProperty( "enableAssertions", String.valueOf( enableAssertions ) );
        properties.setProperty( "useSystemClassLoader", String.valueOf( useSystemClassLoader() ) );
        properties.setProperty( "useManifestOnlyJar", String.valueOf( useManifestOnlyJar() ) );
        properties.setProperty( "failIfNoTests", String.valueOf( failIfNoTests ) );
    }

    private File writePropertiesFile( String name, Properties properties )
        throws IOException
    {
        File file = File.createTempFile( name, "tmp" );
        if ( !forkConfiguration.isDebug() )
        {
            file.deleteOnExit();
        }

        writePropertiesFile( file, name, properties );

        return file;
    }

    private void writePropertiesFile( File file, String name, Properties properties )
        throws IOException
    {
        FileOutputStream out = new FileOutputStream( file );

        try
        {
            properties.store( out, name );
        }
        finally
        {
            IOUtil.close( out );
        }
    }

    private void addPropertiesForTypeHolder( List typeHolderList, Properties properties, String propertyPrefix )
    {
        for ( int i = 0; i < typeHolderList.size(); i++ )
        {
            Object[] report = (Object[]) typeHolderList.get( i );

            String className = (String) report[0];
            Object[] params = (Object[]) report[1];

            properties.setProperty( propertyPrefix + i, className );

            if ( params != null )
            {
                String paramProperty = convert( params[0] );
                String typeProperty = params[0].getClass().getName();
                for ( int j = 1; j < params.length; j++ )
                {
                    paramProperty += "|";
                    typeProperty += "|";
                    if ( params[j] != null )
                    {
                        paramProperty += convert( params[j] );
                        typeProperty += params[j].getClass().getName();
                    }
                }
                properties.setProperty( propertyPrefix + i + PARAMS_SUFIX, paramProperty );
                properties.setProperty( propertyPrefix + i + TYPES_SUFIX, typeProperty );
            }
        }
    }

    private static String convert( Object param )
    {
        if ( param instanceof File[] )
        {
            File[] files = (File[]) param;
            return "[" + StringUtils.join( files, "," ) + "]";
        }
        else if ( param instanceof Properties )
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try
            {
                ( (Properties) param ).store( baos, "" );
                return new String( baos.toByteArray(), "8859_1" );
            }
            catch ( Exception e )
            {
                throw new RuntimeException ( "bug in property conversion", e );
            }
        }
        else
        {
            return param.toString();
        }
    }

    private boolean useSystemClassLoader()
    {
        return forkConfiguration.isUseSystemClassLoader() && ( isForked || forkConfiguration.isForking() );
    }
    
    private boolean useManifestOnlyJar()
    {
        return forkConfiguration.isUseSystemClassLoader() && forkConfiguration.isUseManifestOnlyJar();
    }

    private int fork( Properties properties, boolean showHeading, boolean showFooter )
        throws SurefireBooterForkException
    {
        File surefireProperties;
        File systemProperties = null;
        try
        {
            surefireProperties = writePropertiesFile( "surefire", properties );
            if ( forkConfiguration.getSystemProperties() != null )
            {
                systemProperties = writePropertiesFile( "surefire", forkConfiguration.getSystemProperties() );
            }
        }
        catch ( IOException e )
        {
            throw new SurefireBooterForkException( "Error creating properties files for forking", e );
        }

        List bootClasspath = new ArrayList( surefireBootClassPathUrls.size() + classPathUrls.size() );

        bootClasspath.addAll( surefireBootClassPathUrls );

        if ( useSystemClassLoader() )
        {
            bootClasspath.addAll( classPathUrls );
        }

        Commandline cli = forkConfiguration.createCommandLine( bootClasspath, useManifestOnlyJar() );

        cli.createArg().setFile( surefireProperties );

        if ( systemProperties != null )
        {
            cli.createArg().setFile( systemProperties );
        }

        
        ForkingStreamConsumer out = getForkingStreamConsumer( showHeading, showFooter, redirectTestOutputToFile );

        StreamConsumer err;
        
        if ( redirectTestOutputToFile )
        {
            err = out;
        }
        else
        { 
            err = getForkingStreamConsumer( showHeading, showFooter, redirectTestOutputToFile );
        }

        if ( forkConfiguration.isDebug() )
        {
            System.out.println( "Forking command line: " + cli );
        }

        int returnCode;

        try
        {
            returnCode = CommandLineUtils.executeCommandLine( cli, out, err, forkedProcessTimeoutInSeconds );
        }
        catch ( CommandLineException e )
        {
            throw new SurefireBooterForkException( "Error while executing forked tests.", e );
        }

        if ( redirectTestOutputToFile )
        {
            // ensure the FileOutputConsumerProxy flushes/closes the output file
            try
            {
                out.getOutputConsumer().testSetCompleted();
            }
            catch ( Exception e )
            {
                // the FileOutputConsumerProxy might throw an IllegalStateException but that's not of interest now
            }
        }

        if ( surefireProperties != null && surefireProperties.exists() )
        {
            FileInputStream inStream = null;
            try
            {
                inStream = new FileInputStream( surefireProperties );

                properties.load( inStream );
            }
            catch ( FileNotFoundException e )
            {
                throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
            }
            catch ( IOException e )
            {
                throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
            }
            finally
            {
                IOUtil.close( inStream );
            }
        }

        return returnCode;
    }

    private ClassLoader createClassLoader( List classPathUrls, ClassLoader parent )
        throws MalformedURLException
    {
        return createClassLoader( classPathUrls, parent, false );
    }

    private ClassLoader createClassLoader( List classPathUrls, ClassLoader parent, boolean childDelegation )
        throws MalformedURLException
    {
        List urls = new ArrayList();

        for ( Iterator i = classPathUrls.iterator(); i.hasNext(); )
        {
            String url = (String) i.next();

            if ( url != null )
            {
                File f = new File( url );
                urls.add( UrlUtils.getURL( f ) );
            }
        }

        IsolatedClassLoader classLoader = new IsolatedClassLoader( parent, childDelegation );
        if ( assertionStatusMethod != null )
        {
            try
            {
                Object[] args = new Object[] { enableAssertions ? Boolean.TRUE : Boolean.FALSE };
                if ( parent != null )
                {
                    assertionStatusMethod.invoke( parent, args );
                }
                assertionStatusMethod.invoke( classLoader, args );
            }
            catch ( IllegalAccessException e )
            {
                throw new NestedRuntimeException( "Unable to access the assertion enablement method", e );
            }
            catch ( InvocationTargetException e )
            {
                throw new NestedRuntimeException( "Unable to invoke the assertion enablement method", e );
            }
        }
        for ( Iterator iter = urls.iterator(); iter.hasNext(); )
        {
            URL url = (URL) iter.next();
            classLoader.addURL( url );
        }
        return classLoader;
    }

    private static List processStringList( String stringList )
    {
        String sl = stringList;

        if ( sl.startsWith( "[" ) && sl.endsWith( "]" ) )
        {
            sl = sl.substring( 1, sl.length() - 1 );
        }

        List list = new ArrayList();

        String[] stringArray = StringUtils.split( sl, "," );

        for ( int i = 0; i < stringArray.length; i++ )
        {
            list.add( stringArray[i].trim() );
        }
        return list;
    }

    private static Properties loadProperties( File file )
        throws IOException
    {
        Properties p = new Properties();

        if ( file != null && file.exists() )
        {
            FileInputStream inStream = new FileInputStream( file );
            try
            {
                p.load( inStream );
            }
            finally
            {
                IOUtil.close( inStream );
            }
        }

        return p;
    }

    private static void setSystemProperties( File file )
        throws IOException
    {
        Properties p = loadProperties( file );

        for ( Iterator i = p.keySet().iterator(); i.hasNext(); )
        {
            String key = (String) i.next();

            System.setProperty( key, p.getProperty( key ) );
        }
    }

    private static Object[] constructParamObjects( String paramProperty, String typeProperty )
    {
        Object[] paramObjects = null;
        if ( paramProperty != null )
        {
            // bit of a glitch that it need sto be done twice to do an odd number of vertical bars (eg |||, |||||).
            String[] params =
                StringUtils.split( StringUtils.replace( StringUtils.replace( paramProperty, "||", "| |" ),
                                                        "||", "| |" ), "|" );
            String[] types =
                StringUtils.split( StringUtils.replace( StringUtils.replace( typeProperty, "||", "| |" ),
                                                        "||", "| |" ), "|" );

            paramObjects = new Object[params.length];

            for ( int i = 0; i < types.length; i++ )
            {
                if ( types[i].trim().length() == 0 )
                {
                    params[i] = null;
                }
                else if ( types[i].equals( String.class.getName() ) )
                {
                    paramObjects[i] = params[i];
                }
                else if ( types[i].equals( File.class.getName() ) )
                {
                    paramObjects[i] = new File( params[i] );
                }
                else if ( types[i].equals( File[].class.getName() ) )
                {
                    List stringList = processStringList( params[i] );
                    File[] fileList = new File[stringList.size()];
                    for ( int j = 0; j < stringList.size(); j++ )
                    {
                        fileList[j] = new File( (String) stringList.get( j ) );
                    }
                    paramObjects[i] = fileList;
                }
                else if ( types[i].equals( ArrayList.class.getName() ) )
                {
                    paramObjects[i] = processStringList( params[i] );
                }
                else if ( types[i].equals( Boolean.class.getName() ) )
                {
                    paramObjects[i] = Boolean.valueOf( params[i] );
                }
                else if ( types[i].equals( Integer.class.getName() ) )
                {
                    paramObjects[i] = Integer.valueOf( params[i] );
                }
                else if ( types[i].equals( Properties.class.getName() ) )
                {
                    final Properties result = new Properties();
                    final String value = params[i];
                    try
                    {
                        ByteArrayInputStream bais = new ByteArrayInputStream( value.getBytes( "8859_1" ) );
                        result.load( bais );
                    }
                    catch ( Exception e )
                    {
                        throw new RuntimeException( "bug in property conversion", e );
                    }
                    paramObjects[i] = result;
                }
                else
                {
                    // TODO: could attempt to construct with a String constructor if needed
                    throw new IllegalArgumentException( "Unknown parameter type: " + types[i] );
                }
            }
        }
        return paramObjects;
    }

    /**
     * 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. 

The system exit code will be 1 if an exception is thrown. * * @param args */ public static void main( String[] args ) throws Throwable { // noinspection CatchGenericClass,OverlyBroadCatchBlock try { if ( args.length > 1 ) { setSystemProperties( new File( args[1] ) ); } File surefirePropertiesFile = new File( args[0] ); Properties p = loadProperties( surefirePropertiesFile ); SortedMap classPathUrls = new TreeMap(); SortedMap surefireClassPathUrls = new TreeMap(); SurefireBooter surefireBooter = new SurefireBooter( true ); ForkConfiguration forkConfiguration = new ForkConfiguration(); forkConfiguration.setForkMode( "never" ); surefireBooter.setForkConfiguration( forkConfiguration ); for ( Enumeration e = p.propertyNames(); e.hasMoreElements(); ) { String name = (String) e.nextElement(); if ( name.startsWith( REPORT_PROPERTY_PREFIX ) && !name.endsWith( PARAMS_SUFIX ) && !name.endsWith( TYPES_SUFIX ) ) { String className = p.getProperty( name ); String params = p.getProperty( name + PARAMS_SUFIX ); String types = p.getProperty( name + TYPES_SUFIX ); surefireBooter.addReport( className, constructParamObjects( params, types ) ); } else if ( name.startsWith( TEST_SUITE_PROPERTY_PREFIX ) && !name.endsWith( PARAMS_SUFIX ) && !name.endsWith( TYPES_SUFIX ) ) { String className = p.getProperty( name ); String params = p.getProperty( name + PARAMS_SUFIX ); String types = p.getProperty( name + TYPES_SUFIX ); surefireBooter.addTestSuite( className, constructParamObjects( params, types ) ); } else if ( name.startsWith( "classPathUrl." ) ) { classPathUrls.put( Integer.valueOf( name.substring( name.indexOf( '.' ) + 1 ) ), p.getProperty( name ) ); } else if ( name.startsWith( "surefireClassPathUrl." ) ) { surefireClassPathUrls.put( Integer.valueOf( name.substring( name.indexOf( '.' ) + 1 ) ), p.getProperty( name ) ); } else if ( name.startsWith( "surefireBootClassPathUrl." ) ) { surefireBooter.addSurefireBootClassPathUrl( p.getProperty( name ) ); } else if ( "childDelegation".equals( name ) ) { surefireBooter.childDelegation = Boolean.valueOf( p.getProperty( "childDelegation" ) ).booleanValue(); } else if ( "enableAssertions".equals( name ) ) { surefireBooter.enableAssertions = Boolean.valueOf( p.getProperty( "enableAssertions" ) ).booleanValue(); } else if ( "useSystemClassLoader".equals( name ) ) { boolean value = Boolean.valueOf( p.getProperty( "useSystemClassLoader" ) ).booleanValue(); surefireBooter.forkConfiguration.setUseSystemClassLoader( value ); } else if ( "useManifestOnlyJar".equals( name ) ) { boolean value = Boolean.valueOf( p.getProperty( "useManifestOnlyJar" ) ).booleanValue(); surefireBooter.forkConfiguration.setUseManifestOnlyJar( value ); } else if ( "failIfNoTests".equals( name ) ) { boolean value = Boolean.valueOf( p.getProperty( "failIfNoTests" ) ).booleanValue(); surefireBooter.setFailIfNoTests( value ); } } for ( Iterator cpi = classPathUrls.keySet().iterator(); cpi.hasNext(); ) { String url = (String) classPathUrls.get( cpi.next() ); surefireBooter.addClassPathUrl( url ); } for ( Iterator scpi = surefireClassPathUrls.keySet().iterator(); scpi.hasNext(); ) { String url = (String) surefireClassPathUrls.get( scpi.next() ); surefireBooter.addSurefireClassPathUrl( url ); } String testSet = p.getProperty( "testSet" ); int result; if ( testSet != null ) { result = surefireBooter.runSuitesInProcess( testSet, p ); } else { result = surefireBooter.runSuitesInProcess(); } surefireBooter.writePropertiesFile( surefirePropertiesFile, "surefire", p ); // noinspection CallToSystemExit System.exit( result ); } catch ( Throwable t ) { // Just throwing does getMessage() and a local trace - we want to call printStackTrace for a full trace // noinspection UseOfSystemOutOrSystemErr t.printStackTrace( System.err ); // noinspection ProhibitedExceptionThrown,CallToSystemExit System.exit( 1 ); } } public void setChildDelegation( boolean childDelegation ) { this.childDelegation = childDelegation; } private ForkingStreamConsumer getForkingStreamConsumer( boolean showHeading, boolean showFooter, boolean redirectTestOutputToFile ) { OutputConsumer outputConsumer = new StandardOutputConsumer(); if ( redirectTestOutputToFile ) { outputConsumer = new FileOutputConsumerProxy( outputConsumer, getReportsDirectory() ); } if ( !showHeading ) { outputConsumer = new SupressHeaderOutputConsumerProxy( outputConsumer ); } if ( !showFooter ) { outputConsumer = new SupressFooterOutputConsumerProxy( outputConsumer ); } return new ForkingStreamConsumer( outputConsumer ); } public void setEnableAssertions( boolean enableAssertions ) { this.enableAssertions = enableAssertions; } public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds ) { this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy