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