1   package org.apache.maven.plugin.ear.it;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import junit.framework.TestCase;
23  import org.apache.maven.it.VerificationException;
24  import org.apache.maven.it.Verifier;
25  import org.apache.maven.it.util.ResourceExtractor;
26  import org.codehaus.plexus.util.ReaderFactory;
27  import org.custommonkey.xmlunit.Diff;
28  import org.custommonkey.xmlunit.XMLAssert;
29  import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
30  
31  import java.io.File;
32  import java.io.FilenameFilter;
33  import java.io.IOException;
34  import java.io.Reader;
35  import java.util.ArrayList;
36  import java.util.Arrays;
37  import java.util.List;
38  import java.util.Properties;
39  
40  /**
41   * Base class for ear test cases.
42   *
43   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
44   * @version $Id: AbstractEarPluginIT.java 746740 2009-02-22 15:44:32Z snicoll $
45   */
46  public abstract class AbstractEarPluginIT
47      extends TestCase
48  {
49  
50      protected final String FINAL_NAME_PREFIX = "maven-ear-plugin-test-";
51  
52      protected final String FINAL_NAME_SUFFIX = "-99.0";
53  
54      /**
55       * The base directory.
56       */
57      private File basedir;
58  
59      /**
60       * Test repository directory.
61       */
62      protected File localRepositoryDir = new File( getBasedir().getAbsolutePath(), "target/test-classes/m2repo" );
63  
64      protected File settingsFile = new File( getBasedir().getAbsolutePath(), "target/test-classes/settings.xml" );
65  
66  
67      /**
68       * Execute the EAR plugin for the specified project.
69       *
70       * @param projectName the name of the project
71       * @param properties  extra properties to be used by the embedder
72       * @return the base directory of the project
73       * @throws Exception if an error occured
74       */
75      protected File executeMojo( final String projectName, final Properties properties, boolean expectNoError )
76          throws Exception
77      {
78          System.out.println( "  Building: " + projectName );
79  
80          File testDir = getTestDir( projectName );
81          Verifier verifier = new Verifier( testDir.getAbsolutePath() );
82          // Let's add alternate settings.xml setting so that the latest dependencies are used
83          verifier.getCliOptions().add( "-s \"" + settingsFile.getAbsolutePath() + "\"" );
84          verifier.getCliOptions().add( "-X" );
85          verifier.localRepo = localRepositoryDir.getAbsolutePath();
86  
87          // On linux and macOSX, an exception is thrown if a build failure occurs underneath
88          try
89          {
90              verifier.executeGoal( "package" );
91          }
92          catch ( VerificationException e )
93          {
94              //@TODO needs to be handled nicely in the verifier
95              if ( expectNoError || e.getMessage().indexOf( "Exit code was non-zero" ) == -1 )
96              {
97                  throw e;
98              }
99          }
100 
101         // If no error is expected make sure that error logs are free
102         if ( expectNoError )
103         {
104             verifier.verifyErrorFreeLog();
105         }
106         verifier.resetStreams();
107         return testDir;
108     }
109 
110     /**
111      * Execute the EAR plugin for the specified project.
112      *
113      * @param projectName the name of the project
114      * @param properties  extra properties to be used by the embedder
115      * @return the base directory of the project
116      * @throws Exception if an error occured
117      */
118     protected File executeMojo( final String projectName, final Properties properties )
119         throws Exception
120     {
121         return executeMojo( projectName, properties, true );
122     }
123 
124 
125     /**
126      * Executes the specified projects and asserts the given artifacts.
127      *
128      * @param projectName               the project to test
129      * @param expectedArtifacts         the list of artifacts to be found in the EAR archive
130      * @param artifactsDirectory        whether the artifact is an exploded artifactsDirectory or not
131      * @param testDeploymentDescriptors whether we should test deployemnt descriptors
132      * @return the base directory of the project
133      * @throws Exception
134      */
135     protected File doTestProject( final String projectName, final String[] expectedArtifacts,
136                                   final boolean[] artifactsDirectory, boolean testDeploymentDescriptors )
137         throws Exception
138     {
139         final File baseDir = executeMojo( projectName, new Properties() );
140         assertEarArchive( baseDir, projectName );
141         assertEarDirectory( baseDir, projectName );
142 
143         assertArchiveContent( baseDir, projectName, expectedArtifacts, artifactsDirectory );
144 
145         if ( testDeploymentDescriptors )
146         {
147             assertDeploymentDescriptors( baseDir, projectName );
148         }
149 
150         return baseDir;
151 
152     }
153 
154     /**
155      * Executes the specified projects and asserts the given artifacts. Assert the
156      * deployment descriptors are valid
157      *
158      * @param projectName        the project to test
159      * @param expectedArtifacts  the list of artifacts to be found in the EAR archive
160      * @param artifactsDirectory whether the artifact is an exploded artifactsDirectory or not
161      * @return the base directory of the project
162      * @throws Exception
163      */
164     protected File doTestProject( final String projectName, final String[] expectedArtifacts,
165                                   final boolean[] artifactsDirectory )
166         throws Exception
167     {
168         return doTestProject( projectName, expectedArtifacts, artifactsDirectory, true );
169 
170     }
171 
172     /**
173      * Executes the specified projects and asserts the given artifacts as
174      * artifacts (non directory)
175      *
176      * @param projectName               the project to test
177      * @param expectedArtifacts         the list of artifacts to be found in the EAR archive
178      * @param testDeploymentDescriptors whether we should test deployemnt descriptors
179      * @return the base directory of the project
180      * @throws Exception
181      */
182     protected File doTestProject( final String projectName, final String[] expectedArtifacts,
183                                   boolean testDeploymentDescriptors )
184         throws Exception
185     {
186         return doTestProject( projectName, expectedArtifacts, new boolean[expectedArtifacts.length] );
187     }
188 
189     /**
190      * Executes the specified projects and asserts the given artifacts as
191      * artifacts (non directory). Assert the deployment descriptors are valid
192      *
193      * @param projectName       the project to test
194      * @param expectedArtifacts the list of artifacts to be found in the EAR archive
195      * @return the base directory of the project
196      * @throws Exception
197      */
198     protected File doTestProject( final String projectName, final String[] expectedArtifacts )
199         throws Exception
200     {
201         return doTestProject( projectName, expectedArtifacts, true );
202     }
203 
204     protected void assertEarArchive( final File baseDir, final String projectName )
205     {
206         assertTrue( "EAR archive does not exist", getEarArchive( baseDir, projectName ).exists() );
207     }
208 
209     protected void assertEarDirectory( final File baseDir, final String projectName )
210     {
211         assertTrue( "EAR archive directory does not exist", getEarDirectory( baseDir, projectName ).exists() );
212     }
213 
214     protected File getTargetDirectory( final File basedir )
215     {
216         return new File( basedir, "target" );
217     }
218 
219     protected File getEarArchive( final File baseDir, final String projectName )
220     {
221         return new File( getTargetDirectory( baseDir ), buildFinalName( projectName ) + ".ear" );
222     }
223 
224     protected File getEarDirectory( final File baseDir, final String projectName )
225     {
226         return new File( getTargetDirectory( baseDir ), buildFinalName( projectName ) );
227     }
228 
229     protected String buildFinalName( final String projectName )
230     {
231         return FINAL_NAME_PREFIX + projectName + FINAL_NAME_SUFFIX;
232     }
233 
234     protected void assertArchiveContent( final File baseDir, final String projectName, final String[] artifactNames,
235                                          final boolean[] artifactsDirectory )
236     {
237         // sanity check
238         assertEquals( "Wrong parameter, artifacts mismatch directory flags", artifactNames.length,
239                       artifactsDirectory.length );
240 
241         File dir = getEarDirectory( baseDir, projectName );
242 
243         // Let's build the expected directories sort list
244         final List expectedDirectories = new ArrayList();
245         for ( int i = 0; i < artifactsDirectory.length; i++ )
246         {
247             if ( artifactsDirectory[i] )
248             {
249                 expectedDirectories.add( new File( dir, artifactNames[i] ) );
250             }
251         }
252 
253         final List actualFiles = buildArchiveContentFiles( dir, expectedDirectories );
254         assertEquals( "Artifacts mismatch " + actualFiles, artifactNames.length, actualFiles.size() );
255         for ( int i = 0; i < artifactNames.length; i++ )
256         {
257             String artifactName = artifactNames[i];
258             final boolean isDirectory = artifactsDirectory[i];
259             File expectedFile = new File( dir, artifactName );
260 
261             assertEquals( "Artifact[" + artifactName + "] not in the right form (exploded/archive", isDirectory,
262                           expectedFile.isDirectory() );
263             assertTrue( "Artifact[" + artifactName + "] not found in ear archive",
264                         actualFiles.contains( expectedFile ) );
265 
266         }
267     }
268 
269     protected List buildArchiveContentFiles( final File baseDir, final List expectedDirectories )
270     {
271         final List result = new ArrayList();
272         addFiles( baseDir, result, expectedDirectories );
273 
274         return result;
275     }
276 
277     private void addFiles( final File directory, final List files, final List expectedDirectories )
278     {
279         File[] result = directory.listFiles( new FilenameFilter()
280         {
281             public boolean accept( File dir, String name )
282             {
283                 if ( name.equals( "META-INF" ) )
284                 {
285                     return false;
286                 }
287                 else
288                 {
289                     return true;
290                 }
291             }
292 
293         } );
294 
295         /*
296            Kinda complex. If we found a file, we always add it to the list
297            of files. If a directory is within the expectedDirectories short
298            list we add it but we don't add it's content. Otherwise, we don't
299            add the directory *BUT* we browse it's content
300          */
301         for ( int i = 0; i < result.length; i++ )
302         {
303             File file = result[i];
304             if ( file.isFile() )
305             {
306                 files.add( file );
307             }
308             else if ( expectedDirectories.contains( file ) )
309             {
310                 files.add( file );
311             }
312             else
313             {
314                 addFiles( file, files, expectedDirectories );
315             }
316         }
317     }
318 
319     protected File getBasedir()
320     {
321         if ( basedir != null )
322         {
323             return basedir;
324         }
325 
326         final String basedirString = System.getProperty( "basedir" );
327         if ( basedirString == null )
328         {
329             basedir = new File( "" );
330         }
331         else
332         {
333             basedir = new File( basedirString );
334         }
335         return basedir;
336     }
337 
338     protected File getTestDir( String projectName )
339         throws IOException
340     {
341         return ResourceExtractor.simpleExtractResources( getClass(), "/projects/" + projectName );
342     }
343 
344     // Generated application.xml stuff
345 
346     /**
347      * Asserts that the deployment descriptors have been generated successfully.
348      * <p/>
349      * This test assumes that deployment descriptors are located in the
350      * <tt>expected-META-INF</tt> directory of the project. Note that the
351      * <tt>MANIFEST.mf</tt> file is ignored and is not tested.
352      *
353      * @param baseDir     the directory of the tested project
354      * @param projectName the name of the project
355      */
356     protected void assertDeploymentDescriptors( final File baseDir, final String projectName )
357         throws IOException
358     {
359         final File earDirectory = getEarDirectory( baseDir, projectName );
360         final File[] actualDeploymentDescriptors = getDeploymentDescriptors( new File( earDirectory, "META-INF" ) );
361         final File[] expectedDeploymentDescriptors =
362             getDeploymentDescriptors( new File( baseDir, "expected-META-INF" ) );
363 
364         if ( expectedDeploymentDescriptors == null )
365         {
366             assertNull( "No deployment descriptor was expected", actualDeploymentDescriptors );
367         }
368         else
369         {
370             assertNotNull( "Missing deployment descriptor", actualDeploymentDescriptors );
371 
372             // Make sure we have the same number of files
373             assertEquals( "Number of Deployment descriptor(s) mismatch", expectedDeploymentDescriptors.length,
374                           actualDeploymentDescriptors.length );
375 
376             // Sort the files so that we have the same behavior here
377             Arrays.sort( expectedDeploymentDescriptors );
378             Arrays.sort( actualDeploymentDescriptors );
379 
380             for ( int i = 0; i < expectedDeploymentDescriptors.length; i++ )
381             {
382                 File expectedDeploymentDescriptor = expectedDeploymentDescriptors[i];
383                 File actualDeploymentDescriptor = actualDeploymentDescriptors[i];
384 
385                 assertEquals( "File name mismatch", expectedDeploymentDescriptor.getName(),
386                               actualDeploymentDescriptor.getName() );
387 
388                 Reader expected = null;
389                 Reader actual = null;
390                 try
391                 {
392                     expected = ReaderFactory.newXmlReader( expectedDeploymentDescriptor );
393                     actual = ReaderFactory.newXmlReader( actualDeploymentDescriptor );
394 
395                     // Make sure that it matches even if the elements are not in
396                     // the exact same order
397                     final Diff myDiff = new Diff( expected, actual );
398                     myDiff.overrideElementQualifier( new RecursiveElementNameAndTextQualifier() );
399                     XMLAssert.assertXMLEqual(
400                         "Wrong deployment descriptor generated for[" + expectedDeploymentDescriptor.getName() + "]",
401                         myDiff, true );
402                 }
403                 catch ( Exception e )
404                 {
405                     e.printStackTrace();
406                     fail( "Could not assert deployment descriptor " + e.getMessage() );
407                 }
408                 finally
409                 {
410                     if ( expected != null )
411                     {
412                         expected.close();
413                     }
414                     if ( actual != null )
415                     {
416                         actual.close();
417                     }
418                 }
419             }
420         }
421     }
422 
423     private File[] getDeploymentDescriptors( final File ddDirectory )
424     {
425         return ddDirectory.listFiles( new FilenameFilter()
426         {
427 
428             public boolean accept( File dir, String name )
429             {
430                 return !name.equalsIgnoreCase( "manifest.mf" );
431             }
432         } );
433     }
434 }