View Javadoc

1   package org.apache.maven.plugin.surefire.booterclient;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.booter.BooterConstants;
23  import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
24  import org.apache.maven.surefire.booter.PropertiesWrapper;
25  import org.apache.maven.surefire.booter.ProviderConfiguration;
26  import org.apache.maven.surefire.booter.StartupConfiguration;
27  import org.apache.maven.surefire.booter.SystemPropertyManager;
28  import org.apache.maven.surefire.report.ReporterConfiguration;
29  import org.apache.maven.surefire.testset.DirectoryScannerParameters;
30  import org.apache.maven.surefire.testset.TestArtifactInfo;
31  import org.apache.maven.surefire.testset.TestRequest;
32  import org.apache.maven.surefire.util.NestedRuntimeException;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  import java.io.ByteArrayOutputStream;
36  import java.io.File;
37  import java.io.IOException;
38  import java.util.ArrayList;
39  import java.util.List;
40  import java.util.Properties;
41  
42  /**
43   * Knows how to serialize and deserialize the booter configuration.
44   * <p/>
45   * The internal serialization format is through a properties file. The long-term goal of this
46   * class is not to expose this implementation information to its clients. This still leaks somewhat,
47   * and there are some cases where properties are being accessed as "Properties" instead of
48   * more representative domain objects.
49   * <p/>
50   *
51   * @author Jason van Zyl
52   * @author Emmanuel Venisse
53   * @author Brett Porter
54   * @author Dan Fabulich
55   * @author Kristian Rosenvold
56   * @version $Id$
57   */
58  public class BooterSerializer
59  {
60      private final ForkConfiguration forkConfiguration;
61  
62      private final PropertiesWrapper properties;
63  
64      public BooterSerializer( ForkConfiguration forkConfiguration, Properties properties )
65      {
66          this.forkConfiguration = forkConfiguration;
67          this.properties = new PropertiesWrapper( properties );
68      }
69  
70  
71      public File serialize( ProviderConfiguration booterConfiguration, StartupConfiguration providerConfiguration,
72                             Object testSet )
73          throws IOException
74      {
75          List params = new ArrayList();
76          params.add(
77              new Object[]{ BooterConstants.DIRSCANNER_OPTIONS, booterConfiguration.getDirScannerParamsArray() } );
78          addPropertiesForTypeHolder( params, properties.getProperties(), BooterConstants.DIRSCANNER_PROPERTY_PREFIX );
79  
80          providerConfiguration.getClasspathConfiguration().setForkProperties( properties);
81  
82          TestArtifactInfo testNg = booterConfiguration.getTestArtifact();
83          if ( testNg != null )
84          {
85              properties.setProperty( BooterConstants.TESTARTIFACT_VERSION, testNg.getVersion() );
86              properties.setProperty( BooterConstants.TESTARTIFACT_CLASSIFIER, testNg.getClassifier() );
87          }
88  
89          properties.setProperty( BooterConstants.FORKTESTSET, getTypeEncoded( testSet ) );
90          TestRequest testSuiteDefinition = booterConfiguration.getTestSuiteDefinition();
91          if ( testSuiteDefinition != null )
92          {
93              properties.setProperty( BooterConstants.SOURCE_DIRECTORY, testSuiteDefinition.getTestSourceDirectory() );
94              properties.addList( testSuiteDefinition.getSuiteXmlFiles(), BooterConstants.TEST_SUITE_XML_FILES );
95              properties.setProperty( BooterConstants.REQUESTEDTEST, testSuiteDefinition.getRequestedTest() );
96              properties.setProperty( BooterConstants.REQUESTEDTESTMETHOD, testSuiteDefinition.getRequestedTestMethod() );
97          }
98  
99          DirectoryScannerParameters directoryScannerParameters = booterConfiguration.getDirScannerParams();
100         if ( directoryScannerParameters != null )
101         {
102             properties.setProperty( BooterConstants.FAILIFNOTESTS,
103                                     String.valueOf( directoryScannerParameters.isFailIfNoTests() ) );
104             properties.addList( directoryScannerParameters.getIncludes(), BooterConstants.INCLUDES_PROPERTY_PREFIX );
105             properties.addList( directoryScannerParameters.getExcludes(), BooterConstants.EXCLUDES_PROPERTY_PREFIX );
106             properties.setProperty( BooterConstants.TEST_CLASSES_DIRECTORY,
107                                     directoryScannerParameters.getTestClassesDirectory() );
108             properties.setProperty( BooterConstants.RUN_ORDER, directoryScannerParameters.getRunOrder() );
109         }
110 
111         ReporterConfiguration reporterConfiguration = booterConfiguration.getReporterConfiguration();
112         addList( reporterConfiguration.getReports(), properties.getProperties(),
113                  BooterConstants.REPORT_PROPERTY_PREFIX );
114 
115         Boolean rep = reporterConfiguration.isTrimStackTrace();
116         properties.setProperty( BooterConstants.ISTRIMSTACKTRACE, rep );
117         properties.setProperty( BooterConstants.REPORTSDIRECTORY, reporterConfiguration.getReportsDirectory() );
118         properties.setProperty( BooterConstants.FORKTIMEOUT, reporterConfiguration.getForkTimeout() );
119         ClassLoaderConfiguration classLoaderConfiguration = providerConfiguration.getClassLoaderConfiguration();
120         properties.setProperty( BooterConstants.USESYSTEMCLASSLOADER,
121                                 String.valueOf( classLoaderConfiguration.isUseSystemClassLoader() ) );
122         properties.setProperty( BooterConstants.USEMANIFESTONLYJAR,
123                                 String.valueOf( classLoaderConfiguration.isUseManifestOnlyJar() ) );
124         properties.setProperty( BooterConstants.FAILIFNOTESTS,
125                                 String.valueOf( booterConfiguration.isFailIfNoTests() ) );
126         properties.setProperty( BooterConstants.PROVIDER_CONFIGURATION, providerConfiguration.getProviderClassName() );
127 
128         return SystemPropertyManager.writePropertiesFile( properties.getProperties(),
129                                                           forkConfiguration.getTempDirectory(), "surefire",
130                                                           forkConfiguration.isDebug() );
131     }
132 
133 
134     private String getTypeEncoded( Object value )
135     {
136         if ( value == null )
137         {
138             return null;
139         }
140         String valueToUse;
141         if ( value instanceof Class )
142         {
143             valueToUse = ( (Class) value ).getName();
144         }
145         else
146         {
147             valueToUse = value.toString();
148         }
149         return value.getClass().getName() + "|" + valueToUse;
150     }
151 
152     private void addPropertiesForTypeHolder( List typeHolderList, Properties properties, String propertyPrefix )
153     {
154         for ( int i = 0; i < typeHolderList.size(); i++ )
155         {
156             Object[] report = (Object[]) typeHolderList.get( i );
157 
158             String className = (String) report[0];
159             Object[] params = (Object[]) report[1];
160 
161             properties.setProperty( propertyPrefix + i, className );
162 
163             if ( params != null )
164             {
165                 String paramProperty = getValues( params );
166                 String typeProperty = getTypes( params );
167                 properties.setProperty( propertyPrefix + i + BooterConstants.PARAMS_SUFIX, paramProperty );
168                 properties.setProperty( propertyPrefix + i + BooterConstants.TYPES_SUFIX, typeProperty );
169             }
170         }
171     }
172 
173     private String getValues( Object[] params )
174     {
175         StringBuffer result = new StringBuffer();
176         if ( params != null && params.length > 0 )
177         {
178             result.append( convert( params[0] ) );
179             for ( int j = 1; j < params.length; j++ )
180             {
181                 result.append( "|" );
182                 if ( params[j] != null )
183                 {
184                     result.append( convert( params[j] ) );
185                 }
186             }
187         }
188         return result.toString();
189     }
190 
191     private String getTypes( Object[] params )
192     {
193         StringBuffer result = new StringBuffer();
194         if ( params != null && params.length > 0 )
195         {
196             result.append( params[0].getClass().getName() );
197             for ( int j = 1; j < params.length; j++ )
198             {
199                 result.append( "|" );
200                 if ( params[j] != null )
201                 {
202                     result.append( params[j].getClass().getName() );
203                 }
204             }
205         }
206         return result.toString();
207     }
208 
209     private static String convert( Object param )
210     {
211         if ( param instanceof File[] )
212         {
213             File[] files = (File[]) param;
214             return "[" + StringUtils.join( files, "," ) + "]";
215         }
216         else if ( param instanceof Properties )
217         {
218             ByteArrayOutputStream baos = new ByteArrayOutputStream();
219             try
220             {
221                 ( (Properties) param ).store( baos, "" );
222                 return new String( baos.toByteArray(), "8859_1" );
223             }
224             catch ( Exception e )
225             {
226                 throw new NestedRuntimeException( "bug in property conversion", e );
227             }
228         }
229         else
230         {
231             return param.toString();
232         }
233     }
234 
235     private void addList( List items, Properties properties, String propertyPrefix )
236     {
237         for ( int i = 0; i < items.size(); i++ )
238         {
239             Object item = items.get( i );
240             if ( item == null )
241             {
242                 throw new NullPointerException( propertyPrefix + i + " has null value" );
243             }
244             properties.setProperty( propertyPrefix + i, item.toString() );
245         }
246     }
247 
248 }