1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileNotFoundException;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.Enumeration;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Properties;
40 import java.util.SortedMap;
41 import java.util.TreeMap;
42
43 import org.apache.maven.surefire.Surefire;
44 import org.apache.maven.surefire.booter.output.FileOutputConsumerProxy;
45 import org.apache.maven.surefire.booter.output.ForkingStreamConsumer;
46 import org.apache.maven.surefire.booter.output.OutputConsumer;
47 import org.apache.maven.surefire.booter.output.StandardOutputConsumer;
48 import org.apache.maven.surefire.booter.output.SupressFooterOutputConsumerProxy;
49 import org.apache.maven.surefire.booter.output.SupressHeaderOutputConsumerProxy;
50 import org.apache.maven.surefire.testset.TestSetFailedException;
51 import org.apache.maven.surefire.util.NestedRuntimeException;
52 import org.apache.maven.surefire.util.UrlUtils;
53 import org.codehaus.plexus.util.IOUtil;
54 import org.codehaus.plexus.util.StringUtils;
55 import org.codehaus.plexus.util.cli.CommandLineException;
56 import org.codehaus.plexus.util.cli.CommandLineUtils;
57 import org.codehaus.plexus.util.cli.Commandline;
58 import org.codehaus.plexus.util.cli.StreamConsumer;
59
60
61
62
63
64
65 public class SurefireBooter
66 {
67 private static final String TEST_SUITE_PROPERTY_PREFIX = "testSuite.";
68 private static final String REPORT_PROPERTY_PREFIX = "report.";
69 private static final String PARAMS_SUFIX = ".params";
70 private static final String TYPES_SUFIX = ".types";
71
72 private List reports = new ArrayList();
73
74 private List classPathUrls = new ArrayList();
75
76 private List surefireClassPathUrls = new ArrayList();
77
78 private List surefireBootClassPathUrls = new ArrayList();
79
80 private List testSuites = new ArrayList();
81
82 private boolean failIfNoTests = false;
83
84 private int forkedProcessTimeoutInSeconds = 0;
85
86 private boolean redirectTestOutputToFile = false;
87
88
89
90
91
92 private ForkConfiguration forkConfiguration;
93
94 public static final int TESTS_SUCCEEDED_EXIT_CODE = 0;
95
96 public static final int TESTS_FAILED_EXIT_CODE = 255;
97
98 public static final int NO_TESTS_EXIT_CODE = 254;
99
100 private static Method assertionStatusMethod;
101
102
103
104
105 private boolean childDelegation = true;
106
107 private File reportsDirectory;
108
109
110
111
112 private final boolean isForked;
113
114
115
116
117
118 private boolean enableAssertions;
119
120 static
121 {
122 try
123 {
124 assertionStatusMethod =
125 ClassLoader.class.getMethod( "setDefaultAssertionStatus", new Class[] { boolean.class } );
126 }
127 catch ( NoSuchMethodException e )
128 {
129 assertionStatusMethod = null;
130 }
131 }
132
133 public SurefireBooter()
134 {
135 isForked = false;
136 }
137
138 private SurefireBooter( boolean isForked )
139 {
140 this.isForked = isForked;
141 }
142
143
144
145
146
147 public void addReport( String report )
148 {
149 addReport( report, null );
150 }
151
152 public void addReport( String report, Object[] constructorParams )
153 {
154 reports.add( new Object[] { report, constructorParams } );
155 }
156
157 public void addTestSuite( String suiteClassName, Object[] constructorParams )
158 {
159 testSuites.add( new Object[] { suiteClassName, constructorParams } );
160 }
161
162 public void addClassPathUrl( String path )
163 {
164 if ( !classPathUrls.contains( path ) )
165 {
166 classPathUrls.add( path );
167 }
168 }
169
170 public void addSurefireClassPathUrl( String path )
171 {
172 if ( !surefireClassPathUrls.contains( path ) )
173 {
174 surefireClassPathUrls.add( path );
175 }
176 }
177
178 public void addSurefireBootClassPathUrl( String path )
179 {
180 if ( !surefireBootClassPathUrls.contains( path ) )
181 {
182 surefireBootClassPathUrls.add( path );
183 }
184 }
185
186
187
188
189
190
191 public void setFailIfNoTests( boolean failIfNoTests )
192 {
193 this.failIfNoTests = failIfNoTests;
194 }
195
196
197
198
199
200
201
202 public void setRedirectTestOutputToFile( boolean redirectTestOutputToFile )
203 {
204 this.redirectTestOutputToFile = redirectTestOutputToFile;
205 }
206
207
208
209
210
211
212 public void setReportsDirectory( File reportsDirectory )
213 {
214 this.reportsDirectory = reportsDirectory;
215 }
216
217
218
219
220 public File getReportsDirectory()
221 {
222 return reportsDirectory;
223 }
224
225 public void setForkConfiguration( ForkConfiguration forkConfiguration )
226 {
227 this.forkConfiguration = forkConfiguration;
228 }
229
230 public boolean isForking()
231 {
232 return forkConfiguration.isForking();
233 }
234
235 public int run()
236 throws SurefireBooterForkException, SurefireExecutionException
237 {
238 int result;
239
240 if ( ForkConfiguration.FORK_NEVER.equals( forkConfiguration.getForkMode() ) )
241 {
242 result = runSuitesInProcess();
243 }
244 else if ( ForkConfiguration.FORK_ONCE.equals( forkConfiguration.getForkMode() ) )
245 {
246 result = runSuitesForkOnce();
247 }
248 else if ( ForkConfiguration.FORK_ALWAYS.equals( forkConfiguration.getForkMode() ) )
249 {
250 result = runSuitesForkPerTestSet();
251 }
252 else
253 {
254 throw new SurefireExecutionException( "Unknown forkmode: " + forkConfiguration.getForkMode(), null );
255 }
256 return result;
257 }
258
259 private int runSuitesInProcess( String testSet, Properties results )
260 throws SurefireExecutionException
261 {
262 if ( testSuites.size() != 1 )
263 {
264 throw new IllegalArgumentException( "Cannot only specify testSet for single test suites" );
265 }
266
267
268
269
270 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
271 try
272 {
273 ClassLoader testsClassLoader =
274 useSystemClassLoader() ? ClassLoader.getSystemClassLoader() : createClassLoader( classPathUrls, null,
275 childDelegation );
276
277
278 ClassLoader surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader );
279
280 Class surefireClass = surefireClassLoader.loadClass( Surefire.class.getName() );
281
282 Object surefire = surefireClass.newInstance();
283
284 Method run =
285 surefireClass.getMethod( "run", new Class[] { List.class, Object[].class, String.class,
286 ClassLoader.class, ClassLoader.class, Properties.class, Boolean.class } );
287
288 Thread.currentThread().setContextClassLoader( testsClassLoader );
289
290 Integer result =
291 (Integer) run.invoke( surefire, new Object[] { reports, testSuites.get( 0 ), testSet,
292 surefireClassLoader, testsClassLoader, results, new Boolean( failIfNoTests ) } );
293
294 return result.intValue();
295 }
296 catch ( InvocationTargetException e )
297 {
298 throw new SurefireExecutionException( e.getTargetException().getMessage(), e.getTargetException() );
299 }
300 catch ( Exception e )
301 {
302 throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
303 }
304 finally
305 {
306 Thread.currentThread().setContextClassLoader( oldContextClassLoader );
307 }
308 }
309
310 private int runSuitesInProcess()
311 throws SurefireExecutionException
312 {
313
314
315
316 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
317
318 try
319 {
320
321
322 ClassLoader testsClassLoader;
323 String testClassPath = getTestClassPathAsString();
324 System.setProperty( "surefire.test.class.path", testClassPath );
325 if ( useManifestOnlyJar() )
326 {
327 testsClassLoader = getClass().getClassLoader();
328
329
330 System.setProperty( "surefire.real.class.path", System.getProperty( "java.class.path" ) );
331 System.setProperty( "java.class.path", testClassPath );
332 }
333 else
334 {
335 testsClassLoader = createClassLoader( classPathUrls, null, childDelegation );
336 }
337
338 ClassLoader surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader );
339
340 Class surefireClass = surefireClassLoader.loadClass( Surefire.class.getName() );
341
342 Object surefire = surefireClass.newInstance();
343
344 Method run =
345 surefireClass.getMethod( "run", new Class[] { List.class, List.class, ClassLoader.class,
346 ClassLoader.class, Boolean.class } );
347
348 Thread.currentThread().setContextClassLoader( testsClassLoader );
349
350 Integer result =
351 (Integer) run.invoke( surefire, new Object[] { reports, testSuites, surefireClassLoader,
352 testsClassLoader, new Boolean( failIfNoTests ) } );
353
354 return result.intValue();
355 }
356 catch ( InvocationTargetException e )
357 {
358 throw new SurefireExecutionException( e.getTargetException().getMessage(), e.getTargetException() );
359 }
360 catch ( Exception e )
361 {
362 throw new SurefireExecutionException( "Unable to instantiate and execute Surefire", e );
363 }
364 finally
365 {
366 Thread.currentThread().setContextClassLoader( oldContextClassLoader );
367 }
368 }
369
370
371
372 private String getTestClassPathAsString()
373 {
374 StringBuffer sb = new StringBuffer();
375 for ( int i = 0; i < classPathUrls.size(); i++ )
376 {
377 sb.append( classPathUrls.get( i ) ).append( File.pathSeparatorChar );
378 }
379 return sb.toString();
380 }
381
382 private int runSuitesForkOnce()
383 throws SurefireBooterForkException
384 {
385 return forkSuites( testSuites, true, true );
386 }
387
388 private int runSuitesForkPerTestSet()
389 throws SurefireBooterForkException
390 {
391 ClassLoader testsClassLoader;
392 ClassLoader surefireClassLoader;
393 try
394 {
395 testsClassLoader = createClassLoader( classPathUrls, null, false );
396
397 surefireClassLoader = createClassLoader( surefireClassPathUrls, testsClassLoader, false );
398 }
399 catch ( MalformedURLException e )
400 {
401 throw new SurefireBooterForkException( "Unable to create classloader to find test suites", e );
402 }
403
404 int globalResult = 0;
405
406 boolean showHeading = true;
407 Properties properties = new Properties();
408 for ( Iterator i = testSuites.iterator(); i.hasNext(); )
409 {
410 Object[] testSuite = (Object[]) i.next();
411
412 Map testSets = getTestSets( testSuite, testsClassLoader, surefireClassLoader );
413
414 for ( Iterator j = testSets.keySet().iterator(); j.hasNext(); )
415 {
416 Object testSet = j.next();
417 boolean showFooter = !j.hasNext() && !i.hasNext();
418 int result = forkSuite( testSuite, testSet, showHeading, showFooter, properties );
419 if ( result > globalResult )
420 {
421 globalResult = result;
422 }
423 showHeading = false;
424 }
425 }
426
427 return globalResult;
428 }
429
430 private Map getTestSets( Object[] testSuite, ClassLoader testsClassLoader, ClassLoader surefireClassLoader )
431 throws SurefireBooterForkException
432 {
433 String className = (String) testSuite[0];
434
435 Object[] params = (Object[]) testSuite[1];
436
437 Object suite;
438 try
439 {
440 suite = Surefire.instantiateObject( className, params, surefireClassLoader );
441 }
442 catch ( TestSetFailedException e )
443 {
444 throw new SurefireBooterForkException( e.getMessage(), e.getCause() );
445 }
446 catch ( ClassNotFoundException e )
447 {
448 throw new SurefireBooterForkException( "Unable to find class for test suite '" + className + "'", e );
449 }
450 catch ( NoSuchMethodException e )
451 {
452 throw new SurefireBooterForkException( "Unable to find appropriate constructor for test suite '"
453 + className + "': " + e.getMessage(), e );
454 }
455
456 Map testSets;
457 try
458 {
459 Method m = suite.getClass().getMethod( "locateTestSets", new Class[] { ClassLoader.class } );
460
461 testSets = (Map) m.invoke( suite, new Object[] { testsClassLoader } );
462 }
463 catch ( IllegalAccessException e )
464 {
465 throw new SurefireBooterForkException( "Error obtaining test sets", e );
466 }
467 catch ( NoSuchMethodException e )
468 {
469 throw new SurefireBooterForkException( "Error obtaining test sets", e );
470 }
471 catch ( InvocationTargetException e )
472 {
473 throw new SurefireBooterForkException( e.getTargetException().getMessage(), e.getTargetException() );
474 }
475 return testSets;
476 }
477
478 private int forkSuites( List testSuites, boolean showHeading, boolean showFooter )
479 throws SurefireBooterForkException
480 {
481 Properties properties = new Properties();
482
483 setForkProperties( testSuites, properties );
484
485 return fork( properties, showHeading, showFooter );
486 }
487
488 private int forkSuite( Object[] testSuite, Object testSet, boolean showHeading, boolean showFooter,
489 Properties properties )
490 throws SurefireBooterForkException
491 {
492 setForkProperties( Collections.singletonList( testSuite ), properties );
493
494 if ( testSet instanceof String )
495 {
496 properties.setProperty( "testSet", (String) testSet );
497 }
498
499 return fork( properties, showHeading, showFooter );
500 }
501
502 private void setForkProperties( List testSuites, Properties properties )
503 {
504 addPropertiesForTypeHolder( reports, properties, REPORT_PROPERTY_PREFIX );
505 addPropertiesForTypeHolder( testSuites, properties, TEST_SUITE_PROPERTY_PREFIX );
506
507 for ( int i = 0; i < classPathUrls.size(); i++ )
508 {
509 String url = (String) classPathUrls.get( i );
510 properties.setProperty( "classPathUrl." + i, url );
511 }
512
513 for ( int i = 0; i < surefireClassPathUrls.size(); i++ )
514 {
515 String url = (String) surefireClassPathUrls.get( i );
516 properties.setProperty( "surefireClassPathUrl." + i, url );
517 }
518
519 properties.setProperty( "childDelegation", String.valueOf( childDelegation ) );
520 properties.setProperty( "enableAssertions", String.valueOf( enableAssertions ) );
521 properties.setProperty( "useSystemClassLoader", String.valueOf( useSystemClassLoader() ) );
522 properties.setProperty( "useManifestOnlyJar", String.valueOf( useManifestOnlyJar() ) );
523 properties.setProperty( "failIfNoTests", String.valueOf( failIfNoTests ) );
524 }
525
526 private File writePropertiesFile( String name, Properties properties )
527 throws IOException
528 {
529 File file = File.createTempFile( name, "tmp" );
530 if ( !forkConfiguration.isDebug() )
531 {
532 file.deleteOnExit();
533 }
534
535 writePropertiesFile( file, name, properties );
536
537 return file;
538 }
539
540 private void writePropertiesFile( File file, String name, Properties properties )
541 throws IOException
542 {
543 FileOutputStream out = new FileOutputStream( file );
544
545 try
546 {
547 properties.store( out, name );
548 }
549 finally
550 {
551 IOUtil.close( out );
552 }
553 }
554
555 private void addPropertiesForTypeHolder( List typeHolderList, Properties properties, String propertyPrefix )
556 {
557 for ( int i = 0; i < typeHolderList.size(); i++ )
558 {
559 Object[] report = (Object[]) typeHolderList.get( i );
560
561 String className = (String) report[0];
562 Object[] params = (Object[]) report[1];
563
564 properties.setProperty( propertyPrefix + i, className );
565
566 if ( params != null )
567 {
568 String paramProperty = convert( params[0] );
569 String typeProperty = params[0].getClass().getName();
570 for ( int j = 1; j < params.length; j++ )
571 {
572 paramProperty += "|";
573 typeProperty += "|";
574 if ( params[j] != null )
575 {
576 paramProperty += convert( params[j] );
577 typeProperty += params[j].getClass().getName();
578 }
579 }
580 properties.setProperty( propertyPrefix + i + PARAMS_SUFIX, paramProperty );
581 properties.setProperty( propertyPrefix + i + TYPES_SUFIX, typeProperty );
582 }
583 }
584 }
585
586 private static String convert( Object param )
587 {
588 if ( param instanceof File[] )
589 {
590 File[] files = (File[]) param;
591 return "[" + StringUtils.join( files, "," ) + "]";
592 }
593 else if ( param instanceof Properties )
594 {
595 ByteArrayOutputStream baos = new ByteArrayOutputStream();
596 try
597 {
598 ( (Properties) param ).store( baos, "" );
599 return new String( baos.toByteArray(), "8859_1" );
600 }
601 catch ( Exception e )
602 {
603 throw new RuntimeException ( "bug in property conversion", e );
604 }
605 }
606 else
607 {
608 return param.toString();
609 }
610 }
611
612 private boolean useSystemClassLoader()
613 {
614 return forkConfiguration.isUseSystemClassLoader() && ( isForked || forkConfiguration.isForking() );
615 }
616
617 private boolean useManifestOnlyJar()
618 {
619 return forkConfiguration.isUseSystemClassLoader() && forkConfiguration.isUseManifestOnlyJar();
620 }
621
622 private int fork( Properties properties, boolean showHeading, boolean showFooter )
623 throws SurefireBooterForkException
624 {
625 File surefireProperties;
626 File systemProperties = null;
627 try
628 {
629 surefireProperties = writePropertiesFile( "surefire", properties );
630 if ( forkConfiguration.getSystemProperties() != null )
631 {
632 systemProperties = writePropertiesFile( "surefire", forkConfiguration.getSystemProperties() );
633 }
634 }
635 catch ( IOException e )
636 {
637 throw new SurefireBooterForkException( "Error creating properties files for forking", e );
638 }
639
640 List bootClasspath = new ArrayList( surefireBootClassPathUrls.size() + classPathUrls.size() );
641
642 bootClasspath.addAll( surefireBootClassPathUrls );
643
644 if ( useSystemClassLoader() )
645 {
646 bootClasspath.addAll( classPathUrls );
647 }
648
649 Commandline cli = forkConfiguration.createCommandLine( bootClasspath, useManifestOnlyJar() );
650
651 cli.createArg().setFile( surefireProperties );
652
653 if ( systemProperties != null )
654 {
655 cli.createArg().setFile( systemProperties );
656 }
657
658
659 ForkingStreamConsumer out = getForkingStreamConsumer( showHeading, showFooter, redirectTestOutputToFile );
660
661 StreamConsumer err;
662
663 if ( redirectTestOutputToFile )
664 {
665 err = out;
666 }
667 else
668 {
669 err = getForkingStreamConsumer( showHeading, showFooter, redirectTestOutputToFile );
670 }
671
672 if ( forkConfiguration.isDebug() )
673 {
674 System.out.println( "Forking command line: " + cli );
675 }
676
677 int returnCode;
678
679 try
680 {
681 returnCode = CommandLineUtils.executeCommandLine( cli, out, err, forkedProcessTimeoutInSeconds );
682 }
683 catch ( CommandLineException e )
684 {
685 throw new SurefireBooterForkException( "Error while executing forked tests.", e );
686 }
687
688 if ( redirectTestOutputToFile )
689 {
690
691 try
692 {
693 out.getOutputConsumer().testSetCompleted();
694 }
695 catch ( Exception e )
696 {
697
698 }
699 }
700
701 if ( surefireProperties != null && surefireProperties.exists() )
702 {
703 FileInputStream inStream = null;
704 try
705 {
706 inStream = new FileInputStream( surefireProperties );
707
708 properties.load( inStream );
709 }
710 catch ( FileNotFoundException e )
711 {
712 throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
713 }
714 catch ( IOException e )
715 {
716 throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
717 }
718 finally
719 {
720 IOUtil.close( inStream );
721 }
722 }
723
724 return returnCode;
725 }
726
727 private ClassLoader createClassLoader( List classPathUrls, ClassLoader parent )
728 throws MalformedURLException
729 {
730 return createClassLoader( classPathUrls, parent, false );
731 }
732
733 private ClassLoader createClassLoader( List classPathUrls, ClassLoader parent, boolean childDelegation )
734 throws MalformedURLException
735 {
736 List urls = new ArrayList();
737
738 for ( Iterator i = classPathUrls.iterator(); i.hasNext(); )
739 {
740 String url = (String) i.next();
741
742 if ( url != null )
743 {
744 File f = new File( url );
745 urls.add( UrlUtils.getURL( f ) );
746 }
747 }
748
749 IsolatedClassLoader classLoader = new IsolatedClassLoader( parent, childDelegation );
750 if ( assertionStatusMethod != null )
751 {
752 try
753 {
754 Object[] args = new Object[] { enableAssertions ? Boolean.TRUE : Boolean.FALSE };
755 if ( parent != null )
756 {
757 assertionStatusMethod.invoke( parent, args );
758 }
759 assertionStatusMethod.invoke( classLoader, args );
760 }
761 catch ( IllegalAccessException e )
762 {
763 throw new NestedRuntimeException( "Unable to access the assertion enablement method", e );
764 }
765 catch ( InvocationTargetException e )
766 {
767 throw new NestedRuntimeException( "Unable to invoke the assertion enablement method", e );
768 }
769 }
770 for ( Iterator iter = urls.iterator(); iter.hasNext(); )
771 {
772 URL url = (URL) iter.next();
773 classLoader.addURL( url );
774 }
775 return classLoader;
776 }
777
778 private static List processStringList( String stringList )
779 {
780 String sl = stringList;
781
782 if ( sl.startsWith( "[" ) && sl.endsWith( "]" ) )
783 {
784 sl = sl.substring( 1, sl.length() - 1 );
785 }
786
787 List list = new ArrayList();
788
789 String[] stringArray = StringUtils.split( sl, "," );
790
791 for ( int i = 0; i < stringArray.length; i++ )
792 {
793 list.add( stringArray[i].trim() );
794 }
795 return list;
796 }
797
798 private static Properties loadProperties( File file )
799 throws IOException
800 {
801 Properties p = new Properties();
802
803 if ( file != null && file.exists() )
804 {
805 FileInputStream inStream = new FileInputStream( file );
806 try
807 {
808 p.load( inStream );
809 }
810 finally
811 {
812 IOUtil.close( inStream );
813 }
814 }
815
816 return p;
817 }
818
819 private static void setSystemProperties( File file )
820 throws IOException
821 {
822 Properties p = loadProperties( file );
823
824 for ( Iterator i = p.keySet().iterator(); i.hasNext(); )
825 {
826 String key = (String) i.next();
827
828 System.setProperty( key, p.getProperty( key ) );
829 }
830 }
831
832 private static Object[] constructParamObjects( String paramProperty, String typeProperty )
833 {
834 Object[] paramObjects = null;
835 if ( paramProperty != null )
836 {
837
838 String[] params =
839 StringUtils.split( StringUtils.replace( StringUtils.replace( paramProperty, "||", "| |" ),
840 "||", "| |" ), "|" );
841 String[] types =
842 StringUtils.split( StringUtils.replace( StringUtils.replace( typeProperty, "||", "| |" ),
843 "||", "| |" ), "|" );
844
845 paramObjects = new Object[params.length];
846
847 for ( int i = 0; i < types.length; i++ )
848 {
849 if ( types[i].trim().length() == 0 )
850 {
851 params[i] = null;
852 }
853 else if ( types[i].equals( String.class.getName() ) )
854 {
855 paramObjects[i] = params[i];
856 }
857 else if ( types[i].equals( File.class.getName() ) )
858 {
859 paramObjects[i] = new File( params[i] );
860 }
861 else if ( types[i].equals( File[].class.getName() ) )
862 {
863 List stringList = processStringList( params[i] );
864 File[] fileList = new File[stringList.size()];
865 for ( int j = 0; j < stringList.size(); j++ )
866 {
867 fileList[j] = new File( (String) stringList.get( j ) );
868 }
869 paramObjects[i] = fileList;
870 }
871 else if ( types[i].equals( ArrayList.class.getName() ) )
872 {
873 paramObjects[i] = processStringList( params[i] );
874 }
875 else if ( types[i].equals( Boolean.class.getName() ) )
876 {
877 paramObjects[i] = Boolean.valueOf( params[i] );
878 }
879 else if ( types[i].equals( Integer.class.getName() ) )
880 {
881 paramObjects[i] = Integer.valueOf( params[i] );
882 }
883 else if ( types[i].equals( Properties.class.getName() ) )
884 {
885 final Properties result = new Properties();
886 final String value = params[i];
887 try
888 {
889 ByteArrayInputStream bais = new ByteArrayInputStream( value.getBytes( "8859_1" ) );
890 result.load( bais );
891 }
892 catch ( Exception e )
893 {
894 throw new RuntimeException( "bug in property conversion", e );
895 }
896 paramObjects[i] = result;
897 }
898 else
899 {
900
901 throw new IllegalArgumentException( "Unknown parameter type: " + types[i] );
902 }
903 }
904 }
905 return paramObjects;
906 }
907
908
909
910
911
912
913
914 public static void main( String[] args )
915 throws Throwable
916 {
917
918 try
919 {
920 if ( args.length > 1 )
921 {
922 setSystemProperties( new File( args[1] ) );
923 }
924
925 File surefirePropertiesFile = new File( args[0] );
926 Properties p = loadProperties( surefirePropertiesFile );
927
928 SortedMap classPathUrls = new TreeMap();
929
930 SortedMap surefireClassPathUrls = new TreeMap();
931
932 SurefireBooter surefireBooter = new SurefireBooter( true );
933
934 ForkConfiguration forkConfiguration = new ForkConfiguration();
935 forkConfiguration.setForkMode( "never" );
936 surefireBooter.setForkConfiguration( forkConfiguration );
937
938 for ( Enumeration e = p.propertyNames(); e.hasMoreElements(); )
939 {
940 String name = (String) e.nextElement();
941
942 if ( name.startsWith( REPORT_PROPERTY_PREFIX ) && !name.endsWith( PARAMS_SUFIX )
943 && !name.endsWith( TYPES_SUFIX ) )
944 {
945 String className = p.getProperty( name );
946
947 String params = p.getProperty( name + PARAMS_SUFIX );
948 String types = p.getProperty( name + TYPES_SUFIX );
949 surefireBooter.addReport( className, constructParamObjects( params, types ) );
950 }
951 else if ( name.startsWith( TEST_SUITE_PROPERTY_PREFIX ) && !name.endsWith( PARAMS_SUFIX )
952 && !name.endsWith( TYPES_SUFIX ) )
953 {
954 String className = p.getProperty( name );
955
956 String params = p.getProperty( name + PARAMS_SUFIX );
957 String types = p.getProperty( name + TYPES_SUFIX );
958 surefireBooter.addTestSuite( className, constructParamObjects( params, types ) );
959 }
960 else if ( name.startsWith( "classPathUrl." ) )
961 {
962 classPathUrls.put( Integer.valueOf( name.substring( name.indexOf( '.' ) + 1 ) ),
963 p.getProperty( name ) );
964 }
965 else if ( name.startsWith( "surefireClassPathUrl." ) )
966 {
967 surefireClassPathUrls.put( Integer.valueOf( name.substring( name.indexOf( '.' ) + 1 ) ),
968 p.getProperty( name ) );
969 }
970 else if ( name.startsWith( "surefireBootClassPathUrl." ) )
971 {
972 surefireBooter.addSurefireBootClassPathUrl( p.getProperty( name ) );
973 }
974 else if ( "childDelegation".equals( name ) )
975 {
976 surefireBooter.childDelegation =
977 Boolean.valueOf( p.getProperty( "childDelegation" ) ).booleanValue();
978 }
979 else if ( "enableAssertions".equals( name ) )
980 {
981 surefireBooter.enableAssertions =
982 Boolean.valueOf( p.getProperty( "enableAssertions" ) ).booleanValue();
983 }
984 else if ( "useSystemClassLoader".equals( name ) )
985 {
986 boolean value = Boolean.valueOf( p.getProperty( "useSystemClassLoader" ) ).booleanValue();
987 surefireBooter.forkConfiguration.setUseSystemClassLoader( value );
988 }
989 else if ( "useManifestOnlyJar".equals( name ) )
990 {
991 boolean value = Boolean.valueOf( p.getProperty( "useManifestOnlyJar" ) ).booleanValue();
992 surefireBooter.forkConfiguration.setUseManifestOnlyJar( value );
993 }
994 else if ( "failIfNoTests".equals( name ) )
995 {
996 boolean value = Boolean.valueOf( p.getProperty( "failIfNoTests" ) ).booleanValue();
997 surefireBooter.setFailIfNoTests( value );
998 }
999 }
1000
1001 for ( Iterator cpi = classPathUrls.keySet().iterator(); cpi.hasNext(); )
1002 {
1003 String url = (String) classPathUrls.get( cpi.next() );
1004 surefireBooter.addClassPathUrl( url );
1005 }
1006
1007 for ( Iterator scpi = surefireClassPathUrls.keySet().iterator(); scpi.hasNext(); )
1008 {
1009 String url = (String) surefireClassPathUrls.get( scpi.next() );
1010 surefireBooter.addSurefireClassPathUrl( url );
1011 }
1012
1013 String testSet = p.getProperty( "testSet" );
1014 int result;
1015 if ( testSet != null )
1016 {
1017 result = surefireBooter.runSuitesInProcess( testSet, p );
1018 }
1019 else
1020 {
1021 result = surefireBooter.runSuitesInProcess();
1022 }
1023
1024 surefireBooter.writePropertiesFile( surefirePropertiesFile, "surefire", p );
1025
1026
1027 System.exit( result );
1028 }
1029 catch ( Throwable t )
1030 {
1031
1032
1033 t.printStackTrace( System.err );
1034
1035 System.exit( 1 );
1036 }
1037 }
1038
1039 public void setChildDelegation( boolean childDelegation )
1040 {
1041 this.childDelegation = childDelegation;
1042 }
1043
1044 private ForkingStreamConsumer getForkingStreamConsumer( boolean showHeading, boolean showFooter,
1045 boolean redirectTestOutputToFile )
1046 {
1047 OutputConsumer outputConsumer = new StandardOutputConsumer();
1048
1049 if ( redirectTestOutputToFile )
1050 {
1051 outputConsumer = new FileOutputConsumerProxy( outputConsumer, getReportsDirectory() );
1052 }
1053
1054 if ( !showHeading )
1055 {
1056 outputConsumer = new SupressHeaderOutputConsumerProxy( outputConsumer );
1057 }
1058 if ( !showFooter )
1059 {
1060 outputConsumer = new SupressFooterOutputConsumerProxy( outputConsumer );
1061 }
1062
1063 return new ForkingStreamConsumer( outputConsumer );
1064 }
1065
1066 public void setEnableAssertions( boolean enableAssertions )
1067 {
1068 this.enableAssertions = enableAssertions;
1069 }
1070
1071 public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
1072 {
1073 this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
1074 }
1075 }