View Javadoc

1   package org.apache.maven.it;
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 junit.framework.Assert;
23  import org.apache.maven.it.util.FileUtils;
24  import org.apache.maven.it.util.IOUtil;
25  import org.apache.maven.it.util.StringUtils;
26  import org.apache.maven.it.util.cli.CommandLineException;
27  import org.apache.maven.it.util.cli.CommandLineUtils;
28  import org.apache.maven.it.util.cli.Commandline;
29  import org.apache.maven.it.util.cli.StreamConsumer;
30  import org.apache.maven.it.util.cli.WriterStreamConsumer;
31  import org.xml.sax.InputSource;
32  import org.xml.sax.SAXException;
33  import org.xml.sax.SAXParseException;
34  import org.xml.sax.helpers.DefaultHandler;
35  
36  import javax.xml.parsers.ParserConfigurationException;
37  import javax.xml.parsers.SAXParser;
38  import javax.xml.parsers.SAXParserFactory;
39  import java.io.BufferedReader;
40  import java.io.ByteArrayOutputStream;
41  import java.io.File;
42  import java.io.FileInputStream;
43  import java.io.FileNotFoundException;
44  import java.io.FileReader;
45  import java.io.FileWriter;
46  import java.io.FilenameFilter;
47  import java.io.IOException;
48  import java.io.InputStream;
49  import java.io.InputStreamReader;
50  import java.io.PrintStream;
51  import java.io.Writer;
52  import java.net.MalformedURLException;
53  import java.net.URL;
54  import java.text.DecimalFormat;
55  import java.text.NumberFormat;
56  import java.util.ArrayList;
57  import java.util.Arrays;
58  import java.util.Collections;
59  import java.util.Iterator;
60  import java.util.List;
61  import java.util.Map;
62  import java.util.Properties;
63  import java.util.StringTokenizer;
64  import java.util.regex.Matcher;
65  import java.util.regex.Pattern;
66  
67  /**
68   * @author Jason van Zyl
69   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
70   * @version $Id: Verifier.java 1134539 2011-06-11 07:47:41Z olamy $
71   * @noinspection UseOfSystemOutOrSystemErr, RefusedBequest
72   */
73  public class Verifier
74  {
75      private static final String LOG_FILENAME = "log.txt";
76  
77      public String localRepo;
78  
79      private final String basedir;
80  
81      private final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
82  
83      private final ByteArrayOutputStream errStream = new ByteArrayOutputStream();
84  
85      private PrintStream originalOut;
86  
87      private PrintStream originalErr;
88  
89      private List cliOptions = new ArrayList();
90  
91      private Properties systemProperties = new Properties();
92  
93      private Properties environmentVariables = new Properties();
94  
95      private Properties verifierProperties = new Properties();
96  
97      private boolean autoclean = true;
98  
99      private String localRepoLayout = "default";
100 
101     private boolean debug;
102 
103     private Boolean forkJvm;
104 
105     private String logFileName = LOG_FILENAME;
106 
107     private String defaultMavenHome;
108 
109     // will launch mvn with --debug 
110     private boolean mavenDebug = false;
111 
112     private String forkMode;
113 
114     private boolean debugJvm = false;
115 
116     private static MavenLauncher embeddedLauncher;
117 
118     public Verifier( String basedir )
119         throws VerificationException
120     {
121         this( basedir, null );
122     }
123 
124     public Verifier( String basedir, boolean debug )
125         throws VerificationException
126     {
127         this( basedir, null, debug );
128     }
129 
130     public Verifier( String basedir, String settingsFile )
131         throws VerificationException
132     {
133         this( basedir, settingsFile, false );
134     }
135 
136     public Verifier( String basedir, String settingsFile, boolean debug )
137         throws VerificationException
138     {
139         this( basedir, settingsFile, debug, null );
140     }
141 
142     public Verifier( String basedir, String settingsFile, boolean debug, boolean forkJvm )
143         throws VerificationException
144     {
145         this( basedir, settingsFile, debug, Boolean.valueOf( forkJvm ) );
146     }
147 
148     private Verifier( String basedir, String settingsFile, boolean debug, Boolean forkJvm )
149         throws VerificationException
150     {
151         this.basedir = basedir;
152 
153         this.debug = debug;
154 
155         this.forkJvm = forkJvm;
156         this.forkMode = System.getProperty( "verifier.forkMode" );
157 
158         if ( !debug )
159         {
160             originalOut = System.out;
161 
162             System.setOut( new PrintStream( outStream ) );
163 
164             originalErr = System.err;
165 
166             System.setErr( new PrintStream( errStream ) );
167         }
168 
169         findLocalRepo( settingsFile );
170         findDefaultMavenHome();
171 
172         if ( StringUtils.isEmpty( defaultMavenHome ) && StringUtils.isEmpty( forkMode ) )
173         {
174             forkMode = "auto";
175         }
176     }
177 
178     private void findDefaultMavenHome()
179         throws VerificationException
180     {
181         defaultMavenHome = System.getProperty( "maven.home" );
182 
183         if ( defaultMavenHome == null )
184         {
185             try
186             {
187                 Properties envVars = CommandLineUtils.getSystemEnvVars();
188                 defaultMavenHome = envVars.getProperty( "M2_HOME" );
189             }
190             catch ( IOException e )
191             {
192                 throw new VerificationException( "Cannot read system environment variables.", e );
193             }
194         }
195 
196         if ( defaultMavenHome == null )
197         {
198             File f = new File( System.getProperty( "user.home" ), "m2" );
199             if ( new File( f, "bin/mvn" ).isFile() )
200             {
201                 defaultMavenHome = f.getAbsolutePath();
202             }
203         }
204     }
205 
206     public void setLocalRepo( String localRepo )
207     {
208         this.localRepo = localRepo;
209     }
210 
211     public void resetStreams()
212     {
213         if ( !debug )
214         {
215             System.setOut( originalOut );
216 
217             System.setErr( originalErr );
218         }
219     }
220 
221     public void displayStreamBuffers()
222     {
223         String out = outStream.toString();
224 
225         if ( out != null && out.trim().length() > 0 )
226         {
227             System.out.println( "----- Standard Out -----" );
228 
229             System.out.println( out );
230         }
231 
232         String err = errStream.toString();
233 
234         if ( err != null && err.trim().length() > 0 )
235         {
236             System.err.println( "----- Standard Error -----" );
237 
238             System.err.println( err );
239         }
240     }
241 
242     // ----------------------------------------------------------------------
243     //
244     // ----------------------------------------------------------------------
245 
246     public void verify( boolean chokeOnErrorOutput )
247         throws VerificationException
248     {
249         List lines = loadFile( getBasedir(), "expected-results.txt", false );
250 
251         for ( Iterator i = lines.iterator(); i.hasNext(); )
252         {
253             String line = (String) i.next();
254 
255             verifyExpectedResult( line );
256         }
257 
258         if ( chokeOnErrorOutput )
259         {
260             verifyErrorFreeLog();
261         }
262     }
263 
264     public void verifyErrorFreeLog()
265         throws VerificationException
266     {
267         List lines;
268         lines = loadFile( getBasedir(), getLogFileName(), false );
269 
270         for ( Iterator i = lines.iterator(); i.hasNext(); )
271         {
272             String line = (String) i.next();
273 
274             // A hack to keep stupid velocity resource loader errors from triggering failure
275             if ( line.indexOf( "[ERROR]" ) >= 0 && !isVelocityError( line ) )
276             {
277                 throw new VerificationException( "Error in execution: " + line );
278             }
279         }
280     }
281 
282     /**
283      * Checks whether the specified line is just an error message from Velocity. Especially old versions of Doxia employ
284      * a very noisy Velocity instance.
285      *
286      * @param line The log line to check, must not be <code>null</code>.
287      * @return <code>true</code> if the line appears to be a Velocity error, <code>false</code> otherwise.
288      */
289     private static boolean isVelocityError( String line )
290     {
291         if ( line.indexOf( "VM_global_library.vm" ) >= 0 )
292         {
293             return true;
294         }
295         if ( line.indexOf( "VM #" ) >= 0 && line.indexOf( "macro" ) >= 0 )
296         {
297             // [ERROR] VM #displayTree: error : too few arguments to macro. Wanted 2 got 0
298             return true;
299         }
300         return false;
301     }
302 
303     /**
304      * Throws an exception if the text is not present in the log.
305      *
306      * @param text
307      * @throws VerificationException
308      */
309     public void verifyTextInLog( String text )
310         throws VerificationException
311     {
312         List lines;
313         lines = loadFile( getBasedir(), getLogFileName(), false );
314 
315         boolean result = false;
316         for ( Iterator i = lines.iterator(); i.hasNext(); )
317         {
318             String line = (String) i.next();
319             if ( line.indexOf( text ) >= 0 )
320             {
321                 result = true;
322                 break;
323             }
324         }
325         if ( !result )
326         {
327             throw new VerificationException( "Text not found in log: " + text );
328         }
329     }
330 
331     public Properties loadProperties( String filename )
332         throws VerificationException
333     {
334         Properties properties = new Properties();
335 
336         try
337         {
338             File propertiesFile = new File( getBasedir(), filename );
339             if ( propertiesFile.exists() )
340             {
341                 FileInputStream fis = new FileInputStream( propertiesFile );
342                 try
343                 {
344                     properties.load( fis );
345                 }
346                 finally
347                 {
348                     fis.close();
349                 }
350             }
351         }
352         catch ( FileNotFoundException e )
353         {
354             throw new VerificationException( "Error reading properties file", e );
355         }
356         catch ( IOException e )
357         {
358             throw new VerificationException( "Error reading properties file", e );
359         }
360 
361         return properties;
362     }
363 
364     /**
365      * Loads the (non-empty) lines of the specified text file.
366      *
367      * @param filename The path to the text file to load, relative to the base directory, must not be <code>null</code>.
368      * @param encoding The character encoding of the file, may be <code>null</code> or empty to use the platform default
369      *                 encoding.
370      * @return The list of (non-empty) lines from the text file, can be empty but never <code>null</code>.
371      * @throws IOException If the file could not be loaded.
372      * @since 1.2
373      */
374     public List loadLines( String filename, String encoding )
375         throws IOException
376     {
377         List lines = new ArrayList();
378 
379         File file = new File( getBasedir(), filename );
380 
381         BufferedReader reader = null;
382         try
383         {
384             if ( StringUtils.isNotEmpty( encoding ) )
385             {
386                 reader = new BufferedReader( new InputStreamReader( new FileInputStream( file ), encoding ) );
387             }
388             else
389             {
390                 reader = new BufferedReader( new FileReader( file ) );
391             }
392 
393             String line;
394             while ( ( line = reader.readLine() ) != null )
395             {
396                 if ( line.length() > 0 )
397                 {
398                     lines.add( line );
399                 }
400             }
401         }
402         finally
403         {
404             IOUtil.close( reader );
405         }
406 
407         return lines;
408     }
409 
410     public List loadFile( String basedir, String filename, boolean hasCommand )
411         throws VerificationException
412     {
413         return loadFile( new File( basedir, filename ), hasCommand );
414     }
415 
416     public List loadFile( File file, boolean hasCommand )
417         throws VerificationException
418     {
419         List lines = new ArrayList();
420 
421         BufferedReader reader = null;
422 
423         if ( file.exists() )
424         {
425             try
426             {
427                 reader = new BufferedReader( new FileReader( file ) );
428 
429                 String line = reader.readLine();
430 
431                 while ( line != null )
432                 {
433                     line = line.trim();
434 
435                     if ( !line.startsWith( "#" ) && line.length() != 0 )
436                     {
437                         lines.addAll( replaceArtifacts( line, hasCommand ) );
438                     }
439                     line = reader.readLine();
440                 }
441 
442                 reader.close();
443             }
444             catch ( FileNotFoundException e )
445             {
446                 throw new VerificationException( e );
447             }
448             catch ( IOException e )
449             {
450                 throw new VerificationException( e );
451             }
452             finally
453             {
454                 IOUtil.close( reader );
455             }
456         }
457 
458         return lines;
459     }
460 
461     private List replaceArtifacts( String line, boolean hasCommand )
462     {
463         String MARKER = "${artifact:";
464         int index = line.indexOf( MARKER );
465         if ( index >= 0 )
466         {
467             String newLine = line.substring( 0, index );
468             index = line.indexOf( "}", index );
469             if ( index < 0 )
470             {
471                 throw new IllegalArgumentException( "line does not contain ending artifact marker: '" + line + "'" );
472             }
473             String artifact = line.substring( newLine.length() + MARKER.length(), index );
474 
475             newLine += getArtifactPath( artifact );
476             newLine += line.substring( index + 1 );
477 
478             List l = new ArrayList();
479             l.add( newLine );
480 
481             int endIndex = newLine.lastIndexOf( '/' );
482 
483             String command = null;
484             String filespec;
485             if ( hasCommand )
486             {
487                 int startIndex = newLine.indexOf( ' ' );
488 
489                 command = newLine.substring( 0, startIndex );
490 
491                 filespec = newLine.substring( startIndex + 1, endIndex );
492             }
493             else
494             {
495                 filespec = newLine;
496             }
497 
498             File dir = new File( filespec );
499             addMetadataToList( dir, hasCommand, l, command );
500             addMetadataToList( dir.getParentFile(), hasCommand, l, command );
501 
502             return l;
503         }
504         else
505         {
506             return Collections.singletonList( line );
507         }
508     }
509 
510     private static void addMetadataToList( File dir, boolean hasCommand, List l, String command )
511     {
512         if ( dir.exists() && dir.isDirectory() )
513         {
514             String[] files = dir.list( new FilenameFilter()
515             {
516                 public boolean accept( File dir, String name )
517                 {
518                     return name.startsWith( "maven-metadata" ) && name.endsWith( ".xml" );
519 
520                 }
521             } );
522 
523             for ( int i = 0; i < files.length; i++ )
524             {
525                 if ( hasCommand )
526                 {
527                     l.add( command + " " + new File( dir, files[i] ).getPath() );
528                 }
529                 else
530                 {
531                     l.add( new File( dir, files[i] ).getPath() );
532                 }
533             }
534         }
535     }
536 
537     private String getArtifactPath( String artifact )
538     {
539         StringTokenizer tok = new StringTokenizer( artifact, ":" );
540         if ( tok.countTokens() != 4 )
541         {
542             throw new IllegalArgumentException( "Artifact must have 4 tokens: '" + artifact + "'" );
543         }
544 
545         String[] a = new String[4];
546         for ( int i = 0; i < 4; i++ )
547         {
548             a[i] = tok.nextToken();
549         }
550 
551         String org = a[0];
552         String name = a[1];
553         String version = a[2];
554         String ext = a[3];
555         return getArtifactPath( org, name, version, ext );
556     }
557 
558     public String getArtifactPath( String org, String name, String version, String ext )
559     {
560         return getArtifactPath( org, name, version, ext, null );
561     }
562 
563     /**
564      * Returns the absolute path to the artifact denoted by groupId, artifactId, version, extension and classifier.
565      *
566      * @param gid        The groupId, must not be null.
567      * @param aid        The artifactId, must not be null.
568      * @param version    The version, must not be null.
569      * @param ext        The extension, must not be null.
570      * @param classifier The classifier, may be null to be omitted.
571      * @return the absolute path to the artifact denoted by groupId, artifactId, version, extension and classifier,
572      *         never null.
573      */
574     public String getArtifactPath( String gid, String aid, String version, String ext, String classifier )
575     {
576         if ( classifier != null && classifier.length() == 0 )
577         {
578             classifier = null;
579         }
580         if ( "maven-plugin".equals( ext ) )
581         {
582             ext = "jar";
583         }
584         if ( "coreit-artifact".equals( ext ) )
585         {
586             ext = "jar";
587             classifier = "it";
588         }
589         if ( "test-jar".equals( ext ) )
590         {
591             ext = "jar";
592             classifier = "tests";
593         }
594 
595         String repositoryPath;
596         if ( "legacy".equals( localRepoLayout ) )
597         {
598             repositoryPath = gid + "/" + ext + "s/" + aid + "-" + version + "." + ext;
599         }
600         else if ( "default".equals( localRepoLayout ) )
601         {
602             repositoryPath = gid.replace( '.', '/' );
603             repositoryPath = repositoryPath + "/" + aid + "/" + version;
604             repositoryPath = repositoryPath + "/" + aid + "-" + version;
605             if ( classifier != null )
606             {
607                 repositoryPath = repositoryPath + "-" + classifier;
608             }
609             repositoryPath = repositoryPath + "." + ext;
610         }
611         else
612         {
613             throw new IllegalStateException( "Unknown layout: " + localRepoLayout );
614         }
615 
616         return localRepo + "/" + repositoryPath;
617     }
618 
619     public List getArtifactFileNameList( String org, String name, String version, String ext )
620     {
621         List files = new ArrayList();
622         String artifactPath = getArtifactPath( org, name, version, ext );
623         File dir = new File( artifactPath );
624         files.add( artifactPath );
625         addMetadataToList( dir, false, files, null );
626         addMetadataToList( dir.getParentFile(), false, files, null );
627         return files;
628     }
629 
630     /**
631      * Gets the path to the local artifact metadata. Note that the method does not check whether the returned path
632      * actually points to existing metadata.
633      *
634      * @param gid     The group id, must not be <code>null</code>.
635      * @param aid     The artifact id, must not be <code>null</code>.
636      * @param version The artifact version, may be <code>null</code>.
637      * @return The (absolute) path to the local artifact metadata, never <code>null</code>.
638      */
639     public String getArtifactMetadataPath( String gid, String aid, String version )
640     {
641         return getArtifactMetadataPath( gid, aid, version, "maven-metadata-local.xml" );
642     }
643 
644     /**
645      * Gets the path to a file in the local artifact directory. Note that the method does not check whether the returned
646      * path actually points to an existing file.
647      *
648      * @param gid      The group id, must not be <code>null</code>.
649      * @param aid      The artifact id, may be <code>null</code>.
650      * @param version  The artifact version, may be <code>null</code>.
651      * @param filename The filename to use, must not be <code>null</code>.
652      * @return The (absolute) path to the local artifact metadata, never <code>null</code>.
653      */
654     public String getArtifactMetadataPath( String gid, String aid, String version, String filename )
655     {
656         StringBuffer buffer = new StringBuffer( 256 );
657 
658         buffer.append( localRepo );
659         buffer.append( '/' );
660 
661         if ( "default".equals( localRepoLayout ) )
662         {
663             buffer.append( gid.replace( '.', '/' ) );
664             buffer.append( '/' );
665 
666             if ( aid != null )
667             {
668                 buffer.append( aid );
669                 buffer.append( '/' );
670 
671                 if ( version != null )
672                 {
673                     buffer.append( version );
674                     buffer.append( '/' );
675                 }
676             }
677 
678             buffer.append( filename );
679         }
680         else
681         {
682             throw new IllegalStateException( "Unsupported repository layout: " + localRepoLayout );
683         }
684 
685         return buffer.toString();
686     }
687 
688     /**
689      * Gets the path to the local artifact metadata. Note that the method does not check whether the returned path
690      * actually points to existing metadata.
691      *
692      * @param gid The group id, must not be <code>null</code>.
693      * @param aid The artifact id, must not be <code>null</code>.
694      * @return The (absolute) path to the local artifact metadata, never <code>null</code>.
695      */
696     public String getArtifactMetadataPath( String gid, String aid )
697     {
698         return getArtifactMetadataPath( gid, aid, null );
699     }
700 
701     public void executeHook( String filename )
702         throws VerificationException
703     {
704         try
705         {
706             File f = new File( getBasedir(), filename );
707 
708             if ( !f.exists() )
709             {
710                 return;
711             }
712 
713             List lines = loadFile( f, true );
714 
715             for ( Iterator i = lines.iterator(); i.hasNext(); )
716             {
717                 String line = resolveCommandLineArg( (String) i.next() );
718 
719                 executeCommand( line );
720             }
721         }
722         catch ( VerificationException e )
723         {
724             throw e;
725         }
726         catch ( Exception e )
727         {
728             throw new VerificationException( e );
729         }
730     }
731 
732     private void executeCommand( String line )
733         throws VerificationException
734     {
735         int index = line.indexOf( " " );
736 
737         String cmd;
738 
739         String args = null;
740 
741         if ( index >= 0 )
742         {
743             cmd = line.substring( 0, index );
744 
745             args = line.substring( index + 1 );
746         }
747         else
748         {
749             cmd = line;
750         }
751 
752         if ( "rm".equals( cmd ) )
753         {
754             System.out.println( "Removing file: " + args );
755 
756             File f = new File( args );
757 
758             if ( f.exists() && !f.delete() )
759             {
760                 throw new VerificationException( "Error removing file - delete failed" );
761             }
762         }
763         else if ( "rmdir".equals( cmd ) )
764         {
765             System.out.println( "Removing directory: " + args );
766 
767             try
768             {
769                 File f = new File( args );
770 
771                 FileUtils.deleteDirectory( f );
772             }
773             catch ( IOException e )
774             {
775                 throw new VerificationException( "Error removing directory - delete failed" );
776             }
777         }
778         else if ( "svn".equals( cmd ) )
779         {
780             launchSubversion( line, getBasedir() );
781         }
782         else
783         {
784             throw new VerificationException( "unknown command: " + cmd );
785         }
786     }
787 
788     public static void launchSubversion( String line, String basedir )
789         throws VerificationException
790     {
791         try
792         {
793             Commandline cli = new Commandline( line );
794 
795             cli.setWorkingDirectory( basedir );
796 
797             Writer logWriter = new FileWriter( new File( basedir, LOG_FILENAME ) );
798 
799             StreamConsumer out = new WriterStreamConsumer( logWriter );
800 
801             StreamConsumer err = new WriterStreamConsumer( logWriter );
802 
803             System.out.println( "Command: " + Commandline.toString( cli.getCommandline() ) );
804 
805             int ret = CommandLineUtils.executeCommandLine( cli, out, err );
806 
807             logWriter.close();
808 
809             if ( ret > 0 )
810             {
811                 System.err.println( "Exit code: " + ret );
812 
813                 throw new VerificationException();
814             }
815         }
816         catch ( CommandLineException e )
817         {
818             throw new VerificationException( e );
819         }
820         catch ( IOException e )
821         {
822             throw new VerificationException( e );
823         }
824     }
825 
826     private static String retrieveLocalRepo( String settingsXmlPath )
827         throws VerificationException
828     {
829         UserModelReader userModelReader = new UserModelReader();
830 
831         String userHome = System.getProperty( "user.home" );
832 
833         File userXml;
834 
835         String repo = null;
836 
837         if ( settingsXmlPath != null )
838         {
839             System.out.println( "Using settings from " + settingsXmlPath );
840             userXml = new File( settingsXmlPath );
841         }
842         else
843         {
844             userXml = new File( userHome, ".m2/settings.xml" );
845         }
846 
847         if ( userXml.exists() )
848         {
849             userModelReader.parse( userXml );
850 
851             String localRepository = userModelReader.getLocalRepository();
852             if ( localRepository != null )
853             {
854                 repo = new File( localRepository ).getAbsolutePath();
855             }
856         }
857 
858         return repo;
859     }
860 
861     public void deleteArtifact( String org, String name, String version, String ext )
862         throws IOException
863     {
864         List files = getArtifactFileNameList( org, name, version, ext );
865         for ( Iterator i = files.iterator(); i.hasNext(); )
866         {
867             String fileName = (String) i.next();
868             FileUtils.forceDelete( new File( fileName ) );
869         }
870     }
871 
872     /**
873      * Deletes all artifacts in the specified group id from the local repository.
874      *
875      * @param gid The group id whose artifacts should be deleted, must not be <code>null</code>.
876      * @throws IOException If the artifacts could not be deleted.
877      * @since 1.2
878      */
879     public void deleteArtifacts( String gid )
880         throws IOException
881     {
882         String path;
883         if ( "default".equals( localRepoLayout ) )
884         {
885             path = gid.replace( '.', '/' );
886         }
887         else if ( "legacy".equals( localRepoLayout ) )
888         {
889             path = gid;
890         }
891         else
892         {
893             throw new IllegalStateException( "Unsupported repository layout: " + localRepoLayout );
894         }
895 
896         FileUtils.deleteDirectory( new File( localRepo, path ) );
897     }
898 
899     /**
900      * Deletes all artifacts in the specified g:a:v from the local repository.
901      *
902      * @param gid     The group id whose artifacts should be deleted, must not be <code>null</code>.
903      * @param aid     The artifact id whose artifacts should be deleted, must not be <code>null</code>.
904      * @param version The (base) version whose artifacts should be deleted, must not be <code>null</code>.
905      * @throws IOException If the artifacts could not be deleted.
906      * @since 1.3
907      */
908     public void deleteArtifacts( String gid, String aid, String version )
909         throws IOException
910     {
911         String path;
912         if ( "default".equals( localRepoLayout ) )
913         {
914             path = gid.replace( '.', '/' ) + '/' + aid + '/' + version;
915         }
916         else
917         {
918             throw new IllegalStateException( "Unsupported repository layout: " + localRepoLayout );
919         }
920 
921         FileUtils.deleteDirectory( new File( localRepo, path ) );
922     }
923 
924     /**
925      * Deletes the specified directory.
926      *
927      * @param path The path to the directory to delete, relative to the base directory, must not be <code>null</code>.
928      * @throws IOException If the directory could not be deleted.
929      * @since 1.2
930      */
931     public void deleteDirectory( String path )
932         throws IOException
933     {
934         FileUtils.deleteDirectory( new File( getBasedir(), path ) );
935     }
936 
937     /**
938      * Writes a text file with the specified contents. The contents will be encoded using UTF-8.
939      *
940      * @param path     The path to the file, relative to the base directory, must not be <code>null</code>.
941      * @param contents The contents to write, must not be <code>null</code>.
942      * @throws IOException If the file could not be written.
943      * @since 1.2
944      */
945     public void writeFile( String path, String contents )
946         throws IOException
947     {
948         FileUtils.fileWrite( new File( getBasedir(), path ).getAbsolutePath(), "UTF-8", contents );
949     }
950 
951     /**
952      * Filters a text file by replacing some user-defined tokens.
953      *
954      * @param srcPath          The path to the input file, relative to the base directory, must not be <code>null</code>.
955      * @param dstPath          The path to the output file, relative to the base directory and possibly equal to the input file,
956      *                         must not be <code>null</code>.
957      * @param fileEncoding     The file encoding to use, may be <code>null</code> or empty to use the platform's default
958      *                         encoding.
959      * @param filterProperties The mapping from tokens to replacement values, must not be <code>null</code>.
960      * @return The path to the filtered output file, never <code>null</code>.
961      * @throws IOException If the file could not be filtered.
962      * @since 1.2
963      */
964     public File filterFile( String srcPath, String dstPath, String fileEncoding, Map filterProperties )
965         throws IOException
966     {
967         File srcFile = new File( getBasedir(), srcPath );
968         String data = FileUtils.fileRead( srcFile, fileEncoding );
969 
970         for ( Iterator it = filterProperties.keySet().iterator(); it.hasNext(); )
971         {
972             String token = (String) it.next();
973             String value = String.valueOf( filterProperties.get( token ) );
974             data = StringUtils.replace( data, token, value );
975         }
976 
977         File dstFile = new File( getBasedir(), dstPath );
978         dstFile.getParentFile().mkdirs();
979         FileUtils.fileWrite( dstFile.getPath(), fileEncoding, data );
980 
981         return dstFile;
982     }
983 
984     /**
985      * Gets a new copy of the default filter properties. These default filter properties map the tokens "@basedir@" and
986      * "@baseurl@" to the test's base directory and its base <code>file:</code> URL, respectively.
987      *
988      * @return The (modifiable) map with the default filter properties, never <code>null</code>.
989      * @since 1.2
990      */
991     public Properties newDefaultFilterProperties()
992     {
993         Properties filterProperties = new Properties();
994 
995         String basedir = new File( getBasedir() ).getAbsolutePath();
996         filterProperties.put( "@basedir@", basedir );
997 
998         /*
999          * NOTE: Maven fails to properly handle percent-encoded "file:" URLs (WAGON-111) so don't use File.toURI() here
1000          * and just do it the simple way.
1001          */
1002         String baseurl = basedir;
1003         if ( !baseurl.startsWith( "/" ) )
1004         {
1005             baseurl = '/' + baseurl;
1006         }
1007         baseurl = "file://" + baseurl.replace( '\\', '/' );
1008         filterProperties.put( "@baseurl@", baseurl );
1009 
1010         return filterProperties;
1011     }
1012 
1013     public void assertFilePresent( String file )
1014     {
1015         try
1016         {
1017             verifyExpectedResult( file, true );
1018         }
1019         catch ( VerificationException e )
1020         {
1021             Assert.fail( e.getMessage() );
1022         }
1023     }
1024 
1025     /**
1026      * Check that given file's content matches an regular expression. Note this method also checks that the file exists
1027      * and is readable.
1028      *
1029      * @param file  the file to check.
1030      * @param regex a regular expression.
1031      * @see Pattern
1032      */
1033     public void assertFileMatches( String file, String regex )
1034     {
1035         assertFilePresent( file );
1036         try
1037         {
1038             String content = FileUtils.fileRead( file );
1039             if ( !Pattern.matches( regex, content ) )
1040             {
1041                 Assert.fail( "Content of " + file + " does not match " + regex );
1042             }
1043         }
1044         catch ( IOException e )
1045         {
1046             Assert.fail( e.getMessage() );
1047         }
1048     }
1049 
1050     public void assertFileNotPresent( String file )
1051     {
1052         try
1053         {
1054             verifyExpectedResult( file, false );
1055         }
1056         catch ( VerificationException e )
1057         {
1058             Assert.fail( e.getMessage() );
1059         }
1060     }
1061 
1062     private void verifyArtifactPresence( boolean wanted, String org, String name, String version, String ext )
1063     {
1064         List files = getArtifactFileNameList( org, name, version, ext );
1065         for ( Iterator i = files.iterator(); i.hasNext(); )
1066         {
1067             String fileName = (String) i.next();
1068             try
1069             {
1070                 verifyExpectedResult( fileName, wanted );
1071             }
1072             catch ( VerificationException e )
1073             {
1074                 Assert.fail( e.getMessage() );
1075             }
1076         }
1077     }
1078 
1079     public void assertArtifactPresent( String org, String name, String version, String ext )
1080     {
1081         verifyArtifactPresence( true, org, name, version, ext );
1082     }
1083 
1084     public void assertArtifactNotPresent( String org, String name, String version, String ext )
1085     {
1086         verifyArtifactPresence( false, org, name, version, ext );
1087     }
1088 
1089     private void verifyExpectedResult( String line )
1090         throws VerificationException
1091     {
1092         boolean wanted = true;
1093         if ( line.startsWith( "!" ) )
1094         {
1095             line = line.substring( 1 );
1096             wanted = false;
1097         }
1098 
1099         verifyExpectedResult( line, wanted );
1100     }
1101 
1102     private void verifyExpectedResult( String line, boolean wanted )
1103         throws VerificationException
1104     {
1105         if ( line.indexOf( "!/" ) > 0 )
1106         {
1107             String urlString = "jar:file:" + getBasedir() + "/" + line;
1108 
1109             InputStream is = null;
1110             try
1111             {
1112                 URL url = new URL( urlString );
1113 
1114                 is = url.openStream();
1115 
1116                 if ( is == null )
1117                 {
1118                     if ( wanted )
1119                     {
1120                         throw new VerificationException( "Expected JAR resource was not found: " + line );
1121                     }
1122                 }
1123                 else
1124                 {
1125                     if ( !wanted )
1126                     {
1127                         throw new VerificationException( "Unwanted JAR resource was found: " + line );
1128                     }
1129                 }
1130             }
1131             catch ( MalformedURLException e )
1132             {
1133                 throw new VerificationException( "Error looking for JAR resource", e );
1134             }
1135             catch ( IOException e )
1136             {
1137                 throw new VerificationException( "Error looking for JAR resource", e );
1138             }
1139             finally
1140             {
1141                 if ( is != null )
1142                 {
1143                     try
1144                     {
1145                         is.close();
1146                     }
1147                     catch ( IOException e )
1148                     {
1149                         System.err.println( "WARN: error closing stream: " + e );
1150                     }
1151                 }
1152             }
1153         }
1154         else
1155         {
1156             File expectedFile = new File( line );
1157 
1158             // NOTE: On Windows, a path with a leading (back-)slash is relative to the current drive
1159             if ( !expectedFile.isAbsolute() && !expectedFile.getPath().startsWith( File.separator ) )
1160             {
1161                 expectedFile = new File( getBasedir(), line );
1162             }
1163 
1164             if ( line.indexOf( '*' ) > -1 )
1165             {
1166                 File parent = expectedFile.getParentFile();
1167 
1168                 if ( !parent.exists() )
1169                 {
1170                     if ( wanted )
1171                     {
1172                         throw new VerificationException(
1173                             "Expected file pattern was not found: " + expectedFile.getPath() );
1174                     }
1175                 }
1176                 else
1177                 {
1178                     String shortNamePattern = expectedFile.getName().replaceAll( "\\*", ".*" );
1179 
1180                     String[] candidates = parent.list();
1181 
1182                     boolean found = false;
1183 
1184                     if ( candidates != null )
1185                     {
1186                         for ( int i = 0; i < candidates.length; i++ )
1187                         {
1188                             if ( candidates[i].matches( shortNamePattern ) )
1189                             {
1190                                 found = true;
1191                                 break;
1192                             }
1193                         }
1194                     }
1195 
1196                     if ( !found && wanted )
1197                     {
1198                         throw new VerificationException(
1199                             "Expected file pattern was not found: " + expectedFile.getPath() );
1200                     }
1201                     else if ( found && !wanted )
1202                     {
1203                         throw new VerificationException( "Unwanted file pattern was found: " + expectedFile.getPath() );
1204                     }
1205                 }
1206             }
1207             else
1208             {
1209                 if ( !expectedFile.exists() )
1210                 {
1211                     if ( wanted )
1212                     {
1213                         throw new VerificationException( "Expected file was not found: " + expectedFile.getPath() );
1214                     }
1215                 }
1216                 else
1217                 {
1218                     if ( !wanted )
1219                     {
1220                         throw new VerificationException( "Unwanted file was found: " + expectedFile.getPath() );
1221                     }
1222                 }
1223             }
1224         }
1225     }
1226 
1227     // ----------------------------------------------------------------------
1228     //
1229     // ----------------------------------------------------------------------
1230 
1231     public void executeGoal( String goal )
1232         throws VerificationException
1233     {
1234         executeGoal( goal, environmentVariables );
1235     }
1236 
1237     public void executeGoal( String goal, Map envVars )
1238         throws VerificationException
1239     {
1240         executeGoals( Arrays.asList( new String[]{ goal } ), envVars );
1241     }
1242 
1243     public void executeGoals( List goals )
1244         throws VerificationException
1245     {
1246         executeGoals( goals, environmentVariables );
1247     }
1248 
1249     public String getExecutable()
1250     {
1251         // Use a strategy for finding the maven executable, John has a simple method like this
1252         // but a little strategy + chain of command would be nicer.
1253 
1254         String mavenHome = defaultMavenHome;
1255 
1256         if ( mavenHome != null )
1257         {
1258             return mavenHome + "/bin/mvn";
1259         }
1260         else
1261         {
1262             File f = new File( System.getProperty( "user.home" ), "m2/bin/mvn" );
1263 
1264             if ( f.exists() )
1265             {
1266                 return f.getAbsolutePath();
1267             }
1268             else
1269             {
1270                 return "mvn";
1271             }
1272         }
1273     }
1274 
1275     public void executeGoals( List goals, Map envVars )
1276         throws VerificationException
1277     {
1278         List allGoals = new ArrayList();
1279 
1280         if ( autoclean )
1281         {
1282             /*
1283              * NOTE: Neither test lifecycle binding nor prefix resolution here but call the goal directly.
1284              */
1285             allGoals.add( "org.apache.maven.plugins:maven-clean-plugin:clean" );
1286         }
1287 
1288         allGoals.addAll( goals );
1289 
1290         List args = new ArrayList();
1291 
1292         int ret;
1293 
1294         File logFile = new File( getBasedir(), getLogFileName() );
1295 
1296         for ( Iterator it = cliOptions.iterator(); it.hasNext(); )
1297         {
1298             String key = String.valueOf( it.next() );
1299 
1300             String resolvedArg = resolveCommandLineArg( key );
1301 
1302             try
1303             {
1304                 args.addAll( Arrays.asList( Commandline.translateCommandline( resolvedArg ) ) );
1305             }
1306             catch ( Exception e )
1307             {
1308                 e.printStackTrace();
1309             }
1310         }
1311 
1312         args.add( "-e" );
1313 
1314         args.add( "--batch-mode" );
1315 
1316         if ( this.mavenDebug )
1317         {
1318             args.add( "--debug" );
1319         }
1320 
1321         for ( Iterator i = systemProperties.keySet().iterator(); i.hasNext(); )
1322         {
1323             String key = (String) i.next();
1324             String value = systemProperties.getProperty( key );
1325             args.add( "-D" + key + "=" + value );
1326         }
1327 
1328         /*
1329          * NOTE: Unless explicitly requested by the caller, the forked builds should use the current local
1330          * repository. Otherwise, the forked builds would in principle leave the sandbox environment which has been
1331          * setup for the current build. In particular, using "maven.repo.local" will make sure the forked builds use
1332          * the same local repo as the parent build even if a custom user settings is provided.
1333          */
1334         boolean useMavenRepoLocal =
1335             Boolean.valueOf( verifierProperties.getProperty( "use.mavenRepoLocal", "true" ) ).booleanValue();
1336 
1337         if ( useMavenRepoLocal )
1338         {
1339             args.add( "-Dmaven.repo.local=" + localRepo );
1340         }
1341 
1342         args.addAll( allGoals );
1343 
1344         try
1345         {
1346             String[] cliArgs = (String[]) args.toArray( new String[args.size()] );
1347 
1348             boolean fork;
1349             if ( forkJvm != null )
1350             {
1351                 fork = forkJvm.booleanValue();
1352             }
1353             else if ( envVars.isEmpty() && "auto".equalsIgnoreCase( forkMode ) )
1354             {
1355                 fork = false;
1356 
1357                 try
1358                 {
1359                     initEmbeddedLauncher();
1360                 }
1361                 catch ( Exception e )
1362                 {
1363                     fork = true;
1364                 }
1365             }
1366             else
1367             {
1368                 fork = true;
1369             }
1370 
1371             if ( !fork )
1372             {
1373                 initEmbeddedLauncher();
1374 
1375                 ret = embeddedLauncher.run( cliArgs, getBasedir(), logFile );
1376             }
1377             else
1378             {
1379                 ForkedLauncher launcher = new ForkedLauncher( defaultMavenHome, debugJvm );
1380 
1381                 ret = launcher.run( cliArgs, envVars, getBasedir(), logFile );
1382             }
1383         }
1384         catch ( LauncherException e )
1385         {
1386             throw new VerificationException( "Failed to execute Maven: " + e.getMessage(), e );
1387         }
1388         catch ( IOException e )
1389         {
1390             throw new VerificationException( e );
1391         }
1392 
1393         if ( ret > 0 )
1394         {
1395             System.err.println( "Exit code: " + ret );
1396 
1397             throw new VerificationException( "Exit code was non-zero: " + ret + "; command line and log = \n"
1398                                                  + new File( defaultMavenHome, "bin/mvn" ) + " "
1399                                                  + StringUtils.join( args.iterator(), " " ) + "\n" + getLogContents(
1400                 logFile ) );
1401         }
1402     }
1403 
1404     private void initEmbeddedLauncher()
1405         throws LauncherException
1406     {
1407         if ( embeddedLauncher == null )
1408         {
1409             if ( StringUtils.isEmpty( defaultMavenHome ) )
1410             {
1411                 embeddedLauncher = new Classpath3xLauncher();
1412             }
1413             else
1414             {
1415                 embeddedLauncher = new Embedded3xLauncher( defaultMavenHome );
1416             }
1417         }
1418     }
1419 
1420     public String getMavenVersion()
1421         throws VerificationException
1422     {
1423         ForkedLauncher launcher = new ForkedLauncher( defaultMavenHome );
1424 
1425         File logFile;
1426         try
1427         {
1428             logFile = File.createTempFile( "maven", "log" );
1429         }
1430         catch ( IOException e )
1431         {
1432             throw new VerificationException( "Error creating temp file", e );
1433         }
1434 
1435         try
1436         {
1437             // disable EMMA runtime controller port allocation, should be harmless if EMMA is not used
1438             Map envVars = Collections.singletonMap( "MAVEN_OPTS", "-Demma.rt.control=false" );
1439             launcher.run( new String[]{ "--version" }, envVars, null, logFile );
1440         }
1441         catch ( LauncherException e )
1442         {
1443             throw new VerificationException( "Error running commandline " + e.toString(), e );
1444         }
1445         catch ( IOException e )
1446         {
1447             throw new VerificationException( "IO Error communicating with commandline " + e.toString(), e );
1448         }
1449 
1450         List logLines = loadFile( logFile, false );
1451         logFile.delete();
1452 
1453         String version = extractMavenVersion( logLines );
1454 
1455         if ( version == null )
1456         {
1457             throw new VerificationException(
1458                 "Illegal maven output: String 'Maven version: ' not found in the following output:\n"
1459                     + StringUtils.join( logLines.iterator(), "\n" ) );
1460         }
1461         else
1462         {
1463             return version;
1464         }
1465     }
1466 
1467     static String extractMavenVersion( List logLines )
1468     {
1469         String version = null;
1470 
1471         final Pattern MAVEN_VERSION = Pattern.compile( "(?i).*Maven [^0-9]*([0-9]\\S*).*" );
1472 
1473         for ( Iterator it = logLines.iterator(); version == null && it.hasNext(); )
1474         {
1475             String line = (String) it.next();
1476 
1477             Matcher m = MAVEN_VERSION.matcher( line );
1478             if ( m.matches() )
1479             {
1480                 version = m.group( 1 );
1481             }
1482         }
1483 
1484         return version;
1485     }
1486 
1487     private static String getLogContents( File logFile )
1488     {
1489         try
1490         {
1491             return FileUtils.fileRead( logFile );
1492         }
1493         catch ( IOException e )
1494         {
1495             // ignore
1496             return "(Error reading log contents: " + e.getMessage() + ")";
1497         }
1498     }
1499 
1500     private String resolveCommandLineArg( String key )
1501     {
1502         String result = key.replaceAll( "\\$\\{basedir\\}", getBasedir() );
1503         if ( result.indexOf( "\\\\" ) >= 0 )
1504         {
1505             result = result.replaceAll( "\\\\", "\\" );
1506         }
1507         result = result.replaceAll( "\\/\\/", "\\/" );
1508 
1509         return result;
1510     }
1511 
1512     private static List discoverIntegrationTests( String directory )
1513         throws VerificationException
1514     {
1515         try
1516         {
1517             ArrayList tests = new ArrayList();
1518 
1519             List subTests = FileUtils.getFiles( new File( directory ), "**/goals.txt", null );
1520 
1521             for ( Iterator i = subTests.iterator(); i.hasNext(); )
1522             {
1523                 File testCase = (File) i.next();
1524                 tests.add( testCase.getParent() );
1525             }
1526 
1527             return tests;
1528         }
1529         catch ( IOException e )
1530         {
1531             throw new VerificationException( directory + " is not a valid test case container", e );
1532         }
1533     }
1534 
1535     private void displayLogFile()
1536     {
1537         System.out.println( "Log file contents:" );
1538         BufferedReader reader = null;
1539         try
1540         {
1541             reader = new BufferedReader( new FileReader( new File( getBasedir(), getLogFileName() ) ) );
1542             String line = reader.readLine();
1543             while ( line != null )
1544             {
1545                 System.out.println( line );
1546                 line = reader.readLine();
1547             }
1548             reader.close();
1549         }
1550         catch ( FileNotFoundException e )
1551         {
1552             System.err.println( "Error: " + e );
1553         }
1554         catch ( IOException e )
1555         {
1556             System.err.println( "Error: " + e );
1557         }
1558         finally
1559         {
1560             IOUtil.close( reader );
1561         }
1562     }
1563 
1564     // ----------------------------------------------------------------------
1565     //
1566     // ----------------------------------------------------------------------
1567 
1568     public static void main( String args[] )
1569         throws VerificationException
1570     {
1571         String basedir = System.getProperty( "user.dir" );
1572 
1573         List tests = null;
1574 
1575         List argsList = new ArrayList();
1576 
1577         String settingsFile = null;
1578 
1579         // skip options
1580         for ( int i = 0; i < args.length; i++ )
1581         {
1582             if ( args[i].startsWith( "-D" ) )
1583             {
1584                 int index = args[i].indexOf( "=" );
1585                 if ( index >= 0 )
1586                 {
1587                     System.setProperty( args[i].substring( 2, index ), args[i].substring( index + 1 ) );
1588                 }
1589                 else
1590                 {
1591                     System.setProperty( args[i].substring( 2 ), "true" );
1592                 }
1593             }
1594             else if ( "-s".equals( args[i] ) || "--settings".equals( args[i] ) )
1595             {
1596                 if ( i == args.length - 1 )
1597                 {
1598                     // should have been detected before
1599                     throw new IllegalStateException( "missing argument to -s" );
1600                 }
1601                 i += 1;
1602 
1603                 settingsFile = args[i];
1604             }
1605             else if ( args[i].startsWith( "-" ) )
1606             {
1607                 System.out.println( "skipping unrecognised argument: " + args[i] );
1608             }
1609             else
1610             {
1611                 argsList.add( args[i] );
1612             }
1613         }
1614 
1615         if ( argsList.size() == 0 )
1616         {
1617             if ( FileUtils.fileExists( basedir + File.separator + "integration-tests.txt" ) )
1618             {
1619                 try
1620                 {
1621                     tests = FileUtils.loadFile( new File( basedir, "integration-tests.txt" ) );
1622                 }
1623                 catch ( IOException e )
1624                 {
1625                     System.err.println( "Unable to load integration tests file" );
1626 
1627                     System.err.println( e.getMessage() );
1628 
1629                     System.exit( 2 );
1630                 }
1631             }
1632             else
1633             {
1634                 tests = discoverIntegrationTests( "." );
1635             }
1636         }
1637         else
1638         {
1639             tests = new ArrayList( argsList.size() );
1640             NumberFormat fmt = new DecimalFormat( "0000" );
1641             for ( int i = 0; i < argsList.size(); i++ )
1642             {
1643                 String test = (String) argsList.get( i );
1644                 if ( test.endsWith( "," ) )
1645                 {
1646                     test = test.substring( 0, test.length() - 1 );
1647                 }
1648 
1649                 if ( StringUtils.isNumeric( test ) )
1650                 {
1651 
1652                     test = "it" + fmt.format( Integer.valueOf( test ) );
1653                     test.trim();
1654                     tests.add( test );
1655                 }
1656                 else if ( "it".startsWith( test ) )
1657                 {
1658                     test = test.trim();
1659                     if ( test.length() > 0 )
1660                     {
1661                         tests.add( test );
1662                     }
1663                 }
1664                 else if ( FileUtils.fileExists( test ) && new File( test ).isDirectory() )
1665                 {
1666                     tests.addAll( discoverIntegrationTests( test ) );
1667                 }
1668                 else
1669                 {
1670                     System.err.println(
1671                         "[WARNING] rejecting " + test + " as an invalid test or test source directory" );
1672                 }
1673             }
1674         }
1675 
1676         if ( tests.size() == 0 )
1677         {
1678             System.out.println( "No tests to run" );
1679         }
1680 
1681         int exitCode = 0;
1682 
1683         List failed = new ArrayList();
1684         for ( Iterator i = tests.iterator(); i.hasNext(); )
1685         {
1686             String test = (String) i.next();
1687 
1688             System.out.print( test + "... " );
1689 
1690             String dir = basedir + "/" + test;
1691 
1692             if ( !new File( dir, "goals.txt" ).exists() )
1693             {
1694                 System.err.println( "Test " + test + " in " + dir + " does not exist" );
1695 
1696                 System.exit( 2 );
1697             }
1698 
1699             Verifier verifier = new Verifier( dir );
1700             verifier.findLocalRepo( settingsFile );
1701 
1702             System.out.println( "Using default local repository: " + verifier.localRepo );
1703 
1704             try
1705             {
1706                 runIntegrationTest( verifier );
1707             }
1708             catch ( Throwable e )
1709             {
1710                 verifier.resetStreams();
1711 
1712                 System.out.println( "FAILED" );
1713 
1714                 verifier.displayStreamBuffers();
1715 
1716                 System.out.println( ">>>>>> Error Stacktrace:" );
1717                 e.printStackTrace( System.out );
1718                 System.out.println( "<<<<<< Error Stacktrace" );
1719 
1720                 verifier.displayLogFile();
1721 
1722                 exitCode = 1;
1723 
1724                 failed.add( test );
1725             }
1726         }
1727 
1728         System.out.println( tests.size() - failed.size() + "/" + tests.size() + " passed" );
1729         if ( !failed.isEmpty() )
1730         {
1731             System.out.println( "Failed tests: " + failed );
1732         }
1733 
1734         System.exit( exitCode );
1735     }
1736 
1737     private void findLocalRepo( String settingsFile )
1738         throws VerificationException
1739     {
1740         if ( localRepo == null )
1741         {
1742             localRepo = System.getProperty( "maven.repo.local" );
1743         }
1744 
1745         if ( localRepo == null )
1746         {
1747             localRepo = retrieveLocalRepo( settingsFile );
1748         }
1749 
1750         if ( localRepo == null )
1751         {
1752             localRepo = System.getProperty( "user.home" ) + "/.m2/repository";
1753         }
1754 
1755         File repoDir = new File( localRepo );
1756 
1757         if ( !repoDir.exists() )
1758         {
1759             repoDir.mkdirs();
1760         }
1761 
1762         // normalize path
1763         localRepo = repoDir.getAbsolutePath();
1764 
1765         localRepoLayout = System.getProperty( "maven.repo.local.layout", "default" );
1766     }
1767 
1768     private static void runIntegrationTest( Verifier verifier )
1769         throws VerificationException
1770     {
1771         verifier.executeHook( "prebuild-hook.txt" );
1772 
1773         Properties properties = verifier.loadProperties( "system.properties" );
1774 
1775         Properties controlProperties = verifier.loadProperties( "verifier.properties" );
1776 
1777         boolean chokeOnErrorOutput =
1778             Boolean.valueOf( controlProperties.getProperty( "failOnErrorOutput", "true" ) ).booleanValue();
1779 
1780         List goals = verifier.loadFile( verifier.getBasedir(), "goals.txt", false );
1781 
1782         List cliOptions = verifier.loadFile( verifier.getBasedir(), "cli-options.txt", false );
1783 
1784         verifier.setCliOptions( cliOptions );
1785 
1786         verifier.setSystemProperties( properties );
1787 
1788         verifier.setVerifierProperties( controlProperties );
1789 
1790         verifier.executeGoals( goals );
1791 
1792         verifier.executeHook( "postbuild-hook.txt" );
1793 
1794         System.out.println( "*** Verifying: fail when [ERROR] detected? " + chokeOnErrorOutput + " ***" );
1795 
1796         verifier.verify( chokeOnErrorOutput );
1797 
1798         verifier.resetStreams();
1799 
1800         System.out.println( "OK" );
1801     }
1802 
1803     public void assertArtifactContents( String org, String artifact, String version, String type, String contents )
1804         throws IOException
1805     {
1806         String fileName = getArtifactPath( org, artifact, version, type );
1807         Assert.assertEquals( contents, FileUtils.fileRead( fileName ) );
1808     }
1809 
1810     static class UserModelReader
1811         extends DefaultHandler
1812     {
1813         private String localRepository;
1814 
1815         private StringBuffer currentBody = new StringBuffer();
1816 
1817         public void parse( File file )
1818             throws VerificationException
1819         {
1820             try
1821             {
1822                 SAXParserFactory saxFactory = SAXParserFactory.newInstance();
1823 
1824                 SAXParser parser = saxFactory.newSAXParser();
1825 
1826                 InputSource is = new InputSource( new FileInputStream( file ) );
1827 
1828                 parser.parse( is, this );
1829             }
1830             catch ( FileNotFoundException e )
1831             {
1832                 throw new VerificationException( e );
1833             }
1834             catch ( IOException e )
1835             {
1836                 throw new VerificationException( e );
1837             }
1838             catch ( ParserConfigurationException e )
1839             {
1840                 throw new VerificationException( e );
1841             }
1842             catch ( SAXException e )
1843             {
1844                 throw new VerificationException( e );
1845             }
1846         }
1847 
1848         public void warning( SAXParseException spe )
1849         {
1850             printParseError( "Warning", spe );
1851         }
1852 
1853         public void error( SAXParseException spe )
1854         {
1855             printParseError( "Error", spe );
1856         }
1857 
1858         public void fatalError( SAXParseException spe )
1859         {
1860             printParseError( "Fatal Error", spe );
1861         }
1862 
1863         private final void printParseError( String type, SAXParseException spe )
1864         {
1865             System.err.println(
1866                 type + " [line " + spe.getLineNumber() + ", row " + spe.getColumnNumber() + "]: " + spe.getMessage() );
1867         }
1868 
1869         public String getLocalRepository()
1870         {
1871             return localRepository;
1872         }
1873 
1874         public void characters( char[] ch, int start, int length )
1875             throws SAXException
1876         {
1877             currentBody.append( ch, start, length );
1878         }
1879 
1880         public void endElement( String uri, String localName, String rawName )
1881             throws SAXException
1882         {
1883             if ( "localRepository".equals( rawName ) )
1884             {
1885                 if ( notEmpty( currentBody.toString() ) )
1886                 {
1887                     localRepository = currentBody.toString().trim();
1888                 }
1889                 else
1890                 {
1891                     throw new SAXException(
1892                         "Invalid mavenProfile entry. Missing one or more " + "fields: {localRepository}." );
1893                 }
1894             }
1895 
1896             currentBody = new StringBuffer();
1897         }
1898 
1899         private boolean notEmpty( String test )
1900         {
1901             return test != null && test.trim().length() > 0;
1902         }
1903 
1904         public void reset()
1905         {
1906             currentBody = null;
1907             localRepository = null;
1908         }
1909     }
1910 
1911     public List getCliOptions()
1912     {
1913         return cliOptions;
1914     }
1915 
1916     public void setCliOptions( List cliOptions )
1917     {
1918         this.cliOptions = cliOptions;
1919     }
1920 
1921     public void addCliOption( String option )
1922     {
1923         cliOptions.add( option );
1924     }
1925 
1926     public Properties getSystemProperties()
1927     {
1928         return systemProperties;
1929     }
1930 
1931     public void setSystemProperties( Properties systemProperties )
1932     {
1933         this.systemProperties = systemProperties;
1934     }
1935 
1936     public void setSystemProperty( String key, String value )
1937     {
1938         if ( value != null )
1939         {
1940             systemProperties.setProperty( key, value );
1941         }
1942         else
1943         {
1944             systemProperties.remove( key );
1945         }
1946     }
1947 
1948     public Properties getEnvironmentVariables()
1949     {
1950         return environmentVariables;
1951     }
1952 
1953     public void setEnvironmentVariables( Properties environmentVariables )
1954     {
1955         this.environmentVariables = environmentVariables;
1956     }
1957 
1958     public void setEnvironmentVariable( String key, String value )
1959     {
1960         if ( value != null )
1961         {
1962             environmentVariables.setProperty( key, value );
1963         }
1964         else
1965         {
1966             environmentVariables.remove( key );
1967         }
1968     }
1969 
1970     public Properties getVerifierProperties()
1971     {
1972         return verifierProperties;
1973     }
1974 
1975     public void setVerifierProperties( Properties verifierProperties )
1976     {
1977         this.verifierProperties = verifierProperties;
1978     }
1979 
1980     public boolean isAutoclean()
1981     {
1982         return autoclean;
1983     }
1984 
1985     public void setAutoclean( boolean autoclean )
1986     {
1987         this.autoclean = autoclean;
1988     }
1989 
1990     public String getBasedir()
1991     {
1992         return basedir;
1993     }
1994 
1995     /**
1996      * Gets the name of the file used to log build output.
1997      *
1998      * @return The name of the log file, relative to the base directory, never <code>null</code>.
1999      * @since 1.2
2000      */
2001     public String getLogFileName()
2002     {
2003         return this.logFileName;
2004     }
2005 
2006     /**
2007      * Sets the name of the file used to log build output.
2008      *
2009      * @param logFileName The name of the log file, relative to the base directory, must not be empty or
2010      *                    <code>null</code>.
2011      * @since 1.2
2012      */
2013     public void setLogFileName( String logFileName )
2014     {
2015         if ( StringUtils.isEmpty( logFileName ) )
2016         {
2017             throw new IllegalArgumentException( "log file name unspecified" );
2018         }
2019         this.logFileName = logFileName;
2020     }
2021 
2022     public void setDebug( boolean debug )
2023     {
2024         this.debug = debug;
2025     }
2026 
2027     public boolean isMavenDebug()
2028     {
2029         return mavenDebug;
2030     }
2031 
2032     public void setMavenDebug( boolean mavenDebug )
2033     {
2034         this.mavenDebug = mavenDebug;
2035     }
2036 
2037     public void setForkJvm( boolean forkJvm )
2038     {
2039         this.forkJvm = Boolean.valueOf( forkJvm );
2040     }
2041 
2042     public boolean isDebugJvm()
2043     {
2044         return debugJvm;
2045     }
2046 
2047     public void setDebugJvm( boolean debugJvm )
2048     {
2049         this.debugJvm = debugJvm;
2050     }
2051 
2052     public String getLocalRepoLayout()
2053     {
2054         return localRepoLayout;
2055     }
2056 
2057     public void setLocalRepoLayout( String localRepoLayout )
2058     {
2059         this.localRepoLayout = localRepoLayout;
2060     }
2061 
2062 }