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