blob: c5d36c55df1a2ad9b6734230ab841e08d83b6ef6 [file] [log] [blame]
package org.apache.maven.plugin.surefire.booterclient;
/*
* 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.plugin.surefire.SurefireProperties;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.KeyValueSource;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
import org.apache.maven.surefire.testset.RunOrderParameters;
import org.apache.maven.surefire.testset.TestArtifactInfo;
import org.apache.maven.surefire.testset.TestListResolver;
import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.RunOrder;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import static org.apache.maven.surefire.booter.AbstractPathConfiguration.CHILD_DELEGATION;
import static org.apache.maven.surefire.booter.AbstractPathConfiguration.CLASSPATH;
import static org.apache.maven.surefire.booter.AbstractPathConfiguration.ENABLE_ASSERTIONS;
import static org.apache.maven.surefire.booter.AbstractPathConfiguration.SUREFIRE_CLASSPATH;
import static org.apache.maven.surefire.booter.BooterConstants.EXCLUDES_PROPERTY_PREFIX;
import static org.apache.maven.surefire.booter.BooterConstants.FAIL_FAST_COUNT;
import static org.apache.maven.surefire.booter.BooterConstants.FAILIFNOTESTS;
import static org.apache.maven.surefire.booter.BooterConstants.FORKTESTSET;
import static org.apache.maven.surefire.booter.BooterConstants.FORKTESTSET_PREFER_TESTS_FROM_IN_STREAM;
import static org.apache.maven.surefire.booter.BooterConstants.INCLUDES_PROPERTY_PREFIX;
import static org.apache.maven.surefire.booter.BooterConstants.ISTRIMSTACKTRACE;
import static org.apache.maven.surefire.booter.BooterConstants.MAIN_CLI_OPTIONS;
import static org.apache.maven.surefire.booter.BooterConstants.PLUGIN_PID;
import static org.apache.maven.surefire.booter.BooterConstants.PROVIDER_CONFIGURATION;
import static org.apache.maven.surefire.booter.BooterConstants.REPORTSDIRECTORY;
import static org.apache.maven.surefire.booter.BooterConstants.REQUESTEDTEST;
import static org.apache.maven.surefire.booter.BooterConstants.RERUN_FAILING_TESTS_COUNT;
import static org.apache.maven.surefire.booter.BooterConstants.RUN_ORDER;
import static org.apache.maven.surefire.booter.BooterConstants.RUN_STATISTICS_FILE;
import static org.apache.maven.surefire.booter.BooterConstants.SHUTDOWN;
import static org.apache.maven.surefire.booter.BooterConstants.SOURCE_DIRECTORY;
import static org.apache.maven.surefire.booter.BooterConstants.SPECIFIC_TEST_PROPERTY_PREFIX;
import static org.apache.maven.surefire.booter.BooterConstants.SYSTEM_EXIT_TIMEOUT;
import static org.apache.maven.surefire.booter.BooterConstants.TEST_CLASSES_DIRECTORY;
import static org.apache.maven.surefire.booter.BooterConstants.TEST_SUITE_XML_FILES;
import static org.apache.maven.surefire.booter.BooterConstants.TESTARTIFACT_CLASSIFIER;
import static org.apache.maven.surefire.booter.BooterConstants.TESTARTIFACT_VERSION;
import static org.apache.maven.surefire.booter.BooterConstants.USEMANIFESTONLYJAR;
import static org.apache.maven.surefire.booter.BooterConstants.USESYSTEMCLASSLOADER;
import static org.apache.maven.surefire.booter.SystemPropertyManager.writePropertiesFile;
/**
* Knows how to serialize and deserialize the booter configuration.
* <br>
* The internal serialization format is through a properties file. The long-term goal of this
* class is not to expose this implementation information to its clients. This still leaks somewhat,
* and there are some cases where properties are being accessed as "Properties" instead of
* more representative domain objects.
* <br>
*
* @author Jason van Zyl
* @author Emmanuel Venisse
* @author Brett Porter
* @author Dan Fabulich
* @author Kristian Rosenvold
*/
class BooterSerializer
{
private final ForkConfiguration forkConfiguration;
BooterSerializer( ForkConfiguration forkConfiguration )
{
this.forkConfiguration = forkConfiguration;
}
/**
* Does not modify sourceProperties
*/
File serialize( KeyValueSource sourceProperties, ProviderConfiguration booterConfiguration,
StartupConfiguration providerConfiguration, Object testSet, boolean readTestsFromInStream,
Long pid )
throws IOException
{
SurefireProperties properties = new SurefireProperties( sourceProperties );
properties.setProperty( PLUGIN_PID, pid );
AbstractPathConfiguration cp = providerConfiguration.getClasspathConfiguration();
properties.setClasspath( CLASSPATH, cp.getTestClasspath() );
properties.setClasspath( SUREFIRE_CLASSPATH, cp.getProviderClasspath() );
properties.setProperty( ENABLE_ASSERTIONS, toString( cp.isEnableAssertions() ) );
properties.setProperty( CHILD_DELEGATION, toString( cp.isChildDelegation() ) );
TestArtifactInfo testNg = booterConfiguration.getTestArtifact();
if ( testNg != null )
{
properties.setProperty( TESTARTIFACT_VERSION, testNg.getVersion() );
properties.setNullableProperty( TESTARTIFACT_CLASSIFIER, testNg.getClassifier() );
}
properties.setProperty( FORKTESTSET_PREFER_TESTS_FROM_IN_STREAM, readTestsFromInStream );
properties.setNullableProperty( FORKTESTSET, getTypeEncoded( testSet ) );
TestRequest testSuiteDefinition = booterConfiguration.getTestSuiteDefinition();
if ( testSuiteDefinition != null )
{
properties.setProperty( SOURCE_DIRECTORY, testSuiteDefinition.getTestSourceDirectory() );
if ( testSet instanceof File )
{
properties.addList( Collections.singletonList( (File) testSet ), TEST_SUITE_XML_FILES );
}
else
{
properties.addList( testSuiteDefinition.getSuiteXmlFiles(), TEST_SUITE_XML_FILES );
}
TestListResolver testFilter = testSuiteDefinition.getTestListResolver();
properties.setProperty( REQUESTEDTEST, testFilter == null ? "" : testFilter.getPluginParameterTest() );
int rerunFailingTestsCount = testSuiteDefinition.getRerunFailingTestsCount();
properties.setNullableProperty( RERUN_FAILING_TESTS_COUNT, toString( rerunFailingTestsCount ) );
}
DirectoryScannerParameters directoryScannerParameters = booterConfiguration.getDirScannerParams();
if ( directoryScannerParameters != null )
{
properties.setProperty( FAILIFNOTESTS, toString( directoryScannerParameters.isFailIfNoTests() ) );
properties.addList( directoryScannerParameters.getIncludes(), INCLUDES_PROPERTY_PREFIX );
properties.addList( directoryScannerParameters.getExcludes(), EXCLUDES_PROPERTY_PREFIX );
properties.addList( directoryScannerParameters.getSpecificTests(), SPECIFIC_TEST_PROPERTY_PREFIX );
properties.setProperty( TEST_CLASSES_DIRECTORY, directoryScannerParameters.getTestClassesDirectory() );
}
final RunOrderParameters runOrderParameters = booterConfiguration.getRunOrderParameters();
if ( runOrderParameters != null )
{
properties.setProperty( RUN_ORDER, RunOrder.asString( runOrderParameters.getRunOrder() ) );
properties.setProperty( RUN_STATISTICS_FILE, runOrderParameters.getRunStatisticsFile() );
}
ReporterConfiguration reporterConfiguration = booterConfiguration.getReporterConfiguration();
boolean rep = reporterConfiguration.isTrimStackTrace();
properties.setProperty( ISTRIMSTACKTRACE, rep );
properties.setProperty( REPORTSDIRECTORY, reporterConfiguration.getReportsDirectory() );
ClassLoaderConfiguration classLoaderConfig = providerConfiguration.getClassLoaderConfiguration();
properties.setProperty( USESYSTEMCLASSLOADER, toString( classLoaderConfig.isUseSystemClassLoader() ) );
properties.setProperty( USEMANIFESTONLYJAR, toString( classLoaderConfig.isUseManifestOnlyJar() ) );
properties.setProperty( FAILIFNOTESTS, toString( booterConfiguration.isFailIfNoTests() ) );
properties.setProperty( PROVIDER_CONFIGURATION, providerConfiguration.getProviderClassName() );
properties.setProperty( FAIL_FAST_COUNT, toString( booterConfiguration.getSkipAfterFailureCount() ) );
properties.setProperty( SHUTDOWN, booterConfiguration.getShutdown().name() );
List<CommandLineOption> mainCliOptions = booterConfiguration.getMainCliOptions();
if ( mainCliOptions != null )
{
properties.addList( mainCliOptions, MAIN_CLI_OPTIONS );
}
properties.setNullableProperty( SYSTEM_EXIT_TIMEOUT, toString( booterConfiguration.getSystemExitTimeout() ) );
File surefireTmpDir = forkConfiguration.getTempDirectory();
boolean debug = forkConfiguration.isDebug();
return writePropertiesFile( properties, surefireTmpDir, "surefire", debug );
}
/**
* This method is complementary to
* {@link org.apache.maven.surefire.booter.TypeEncodedValue#getDecodedValue(ClassLoader)}.
*
* @param value a value to encode
* @return encoded value
*/
private static String getTypeEncoded( Object value )
{
if ( value == null )
{
return null;
}
Class<?> type = value.getClass();
final String valueToUse;
if ( type == Class.class )
{
valueToUse = ( (Class<?>) value ).getName();
}
else if ( type == String.class )
{
valueToUse = (String) value;
}
else if ( type == File.class )
{
valueToUse = ( (File) value ).getAbsolutePath();
}
else if ( type == File[].class )
{
StringBuilder paths = new StringBuilder();
File[] files = (File[]) value;
for ( int i = 0; i < files.length; i++ )
{
paths.append( files[i].getAbsolutePath() );
if ( i != files.length - 1 )
{
paths.append( '|' );
}
}
valueToUse = paths.toString();
}
else if ( type == Boolean.class || type == boolean.class
|| type == Integer.class || type == int.class )
{
valueToUse = value.toString();
}
else if ( type == Properties.class )
{
StringBuilder stream = new StringBuilder();
Properties p = (Properties) value;
for ( String key : p.stringPropertyNames() )
{
String val = p.getProperty( key );
stream.append( key )
.append( '=' )
.append( val == null ? "" : val )
.append( '\n' );
}
valueToUse = stream.toString();
}
else
{
valueToUse = value.toString();
}
return type.getCanonicalName() + "|" + valueToUse;
}
private static String toString( Object o )
{
return String.valueOf( o );
}
}