View Javadoc
1   package org.apache.maven.shared.dependency.analyzer;
2   
3   import java.io.File;
4   import java.util.Arrays;
5   import java.util.Collections;
6   import java.util.HashSet;
7   import java.util.List;
8   import java.util.Properties;
9   import java.util.Set;
10  
11  import org.apache.commons.lang3.JavaVersion;
12  import org.apache.commons.lang3.SystemUtils;
13  
14  /*
15   * Licensed to the Apache Software Foundation (ASF) under one
16   * or more contributor license agreements.  See the NOTICE file
17   * distributed with this work for additional information
18   * regarding copyright ownership.  The ASF licenses this file
19   * to you under the Apache License, Version 2.0 (the
20   * "License"); you may not use this file except in compliance
21   * with the License.  You may obtain a copy of the License at
22   *
23   *  http://www.apache.org/licenses/LICENSE-2.0
24   *
25   * Unless required by applicable law or agreed to in writing,
26   * software distributed under the License is distributed on an
27   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
28   * KIND, either express or implied.  See the License for the
29   * specific language governing permissions and limitations
30   * under the License.
31   */
32  
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.artifact.DefaultArtifact;
35  import org.apache.maven.artifact.handler.ArtifactHandler;
36  import org.apache.maven.artifact.handler.DefaultArtifactHandler;
37  import org.apache.maven.artifact.versioning.VersionRange;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.shared.invoker.InvocationRequest;
40  import org.apache.maven.shared.invoker.InvocationResult;
41  import org.apache.maven.shared.test.plugin.BuildTool;
42  import org.apache.maven.shared.test.plugin.ProjectTool;
43  import org.apache.maven.shared.test.plugin.RepositoryTool;
44  import org.apache.maven.shared.test.plugin.TestToolsException;
45  import org.codehaus.plexus.PlexusTestCase;
46  
47  /**
48   * Tests <code>DefaultProjectDependencyAnalyzer</code>.
49   *
50   * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
51   * @version $Id$
52   * @see DefaultProjectDependencyAnalyzer
53   */
54  public class DefaultProjectDependencyAnalyzerTest
55      extends PlexusTestCase
56  {
57      // fields -----------------------------------------------------------------
58  
59      private BuildTool buildTool;
60  
61      private ProjectTool projectTool;
62  
63      private ProjectDependencyAnalyzer analyzer;
64  
65      private static File localRepo;
66  
67      // TestCase methods -------------------------------------------------------
68  
69      /*
70       * @see org.codehaus.plexus.PlexusTestCase#setUp()
71       */
72      protected void setUp()
73          throws Exception
74      {
75          super.setUp();
76  
77          buildTool = (BuildTool) lookup( BuildTool.ROLE );
78  
79          projectTool = (ProjectTool) lookup( ProjectTool.ROLE );
80  
81          if ( localRepo == null )
82          {
83              RepositoryTool repositoryTool = (RepositoryTool) lookup( RepositoryTool.ROLE );
84              localRepo = repositoryTool.findLocalRepositoryDirectory();
85              System.out.println( "Local repository: " + localRepo );
86          }
87  
88          analyzer = (ProjectDependencyAnalyzer) lookup( ProjectDependencyAnalyzer.ROLE );
89      }
90  
91      // tests ------------------------------------------------------------------
92  
93      public void testPom()
94          throws TestToolsException, ProjectDependencyAnalyzerException
95      {
96          compileProject( "pom/pom.xml" );
97  
98          MavenProject project = getProject( "pom/pom.xml" );
99  
100         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
101 
102         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis();
103 
104         assertEquals( expectedAnalysis, actualAnalysis );
105     }
106 
107     public void testJarWithNoDependencies()
108         throws TestToolsException, ProjectDependencyAnalyzerException
109     {
110         compileProject( "jarWithNoDependencies/pom.xml" );
111 
112         MavenProject project = getProject( "jarWithNoDependencies/pom.xml" );
113 
114         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
115 
116         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis();
117 
118         assertEquals( expectedAnalysis, actualAnalysis );
119     }
120 
121     public void testJava8methodRefs()
122         throws TestToolsException, ProjectDependencyAnalyzerException
123     {
124         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
125         {
126             return;
127         }
128 
129         // Only visible through constant pool analysis (supported for JDK8+)
130         compileProject( "java8methodRefs/pom.xml" );
131 
132         MavenProject project = getProject( "java8methodRefs/pom.xml" );
133 
134         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
135 
136         Artifact project1 = createArtifact( "commons-io", "commons-io", "jar", "2.4", "compile" );
137         Artifact project2 = createArtifact( "commons-lang", "commons-lang", "jar", "2.6", "compile" );
138         Set<Artifact> usedDeclaredArtifacts = new HashSet<Artifact>( Arrays.asList( project1, project2 ) );
139 
140         ProjectDependencyAnalysis expectedAnalysis =
141             new ProjectDependencyAnalysis( usedDeclaredArtifacts, new HashSet<Artifact>(), new HashSet<Artifact>() );
142 
143         assertEquals( expectedAnalysis, actualAnalysis );
144     }
145 
146     public void testInlinedStaticReference()
147         throws TestToolsException, ProjectDependencyAnalyzerException
148     {
149         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
150         {
151             return;
152         }
153 
154         // Only visible through constant pool analysis (supported for JDK8+)
155         compileProject( "inlinedStaticReference/pom.xml" );
156 
157         MavenProject project = getProject( "inlinedStaticReference/pom.xml" );
158 
159         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
160 
161         Artifact project1 = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
162         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
163 
164         ProjectDependencyAnalysis expectedAnalysis =
165             new ProjectDependencyAnalysis( usedDeclaredArtifacts, new HashSet<Artifact>(), new HashSet<Artifact>() );
166 
167         assertEquals( expectedAnalysis, actualAnalysis );
168     }
169 
170     public void testJarWithCompileDependency()
171         throws TestToolsException, ProjectDependencyAnalyzerException
172     {
173         compileProject( "jarWithCompileDependency/pom.xml" );
174 
175         MavenProject project2 = getProject( "jarWithCompileDependency/project2/pom.xml" );
176 
177         if ( project2.getBuild().getOutputDirectory().contains( "${" ) )
178         {
179             // if Maven version used as dependency is upgraded to >= 2.2.0
180             throw new TestToolsException( "output directory was not interpolated: "
181                 + project2.getBuild().getOutputDirectory() );
182         }
183 
184         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
185 
186         Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
187                                             "jarWithCompileDependency1", "jar", "1.0", "compile" );
188         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
189         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null );
190 
191         assertEquals( expectedAnalysis, actualAnalysis );
192     }
193 
194     public void testForceDeclaredDependenciesUsage()
195         throws TestToolsException, ProjectDependencyAnalyzerException
196     {
197         compileProject( "jarWithTestDependency/pom.xml" );
198 
199         MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
200 
201         ProjectDependencyAnalysis analysis = analyzer.analyze( project2 );
202 
203         try
204         {
205             analysis.forceDeclaredDependenciesUsage( new String[] {
206                 "org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1" } );
207             fail( "failure expected since junit dependency is declared-used" );
208         }
209         catch ( ProjectDependencyAnalyzerException pdae )
210         {
211             assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
212                 + "declared but already detected as used: "
213                 + "[org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1]" ) );
214         }
215 
216         try
217         {
218             analysis.forceDeclaredDependenciesUsage( new String[] { "undefined:undefined" } );
219             fail( "failure expected since undefined dependency is not declared" );
220         }
221         catch ( ProjectDependencyAnalyzerException pdae )
222         {
223             assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
224                 + "not declared: [undefined:undefined]" ) );
225         }
226     }
227 
228     public void testJarWithTestDependency()
229         throws TestToolsException, ProjectDependencyAnalyzerException
230     {
231         compileProject( "jarWithTestDependency/pom.xml" );
232 
233         MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
234 
235         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
236 
237         Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
238                                             "jarWithTestDependency1", "jar", "1.0", "test" );
239         Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "test" );
240 
241         ProjectDependencyAnalysis expectedAnalysis;
242         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
243         {
244             Set<Artifact> usedDeclaredArtifacts = new HashSet<Artifact>( Arrays.asList( project1, junit ) );
245             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null );
246         }
247         else
248         {
249             // With JDK 7 and earlier, not all deps are identified correctly
250             Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
251             Set<Artifact> unusedDeclaredArtifacts = Collections.singleton( junit );
252             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, unusedDeclaredArtifacts );
253         }
254 
255         assertEquals( expectedAnalysis, actualAnalysis );
256     }
257 
258     public void testJarWithXmlTransitiveDependency()
259         throws TestToolsException, ProjectDependencyAnalyzerException
260     {
261         compileProject( "jarWithXmlTransitiveDependency/pom.xml" );
262 
263         MavenProject project = getProject( "jarWithXmlTransitiveDependency/pom.xml" );
264 
265         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
266 
267         Artifact jdom = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
268         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( jdom );
269 
270         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null );
271 
272         // MSHARED-47: usedUndeclaredArtifacts=[xml-apis:xml-apis:jar:1.0.b2:compile]
273         // assertEquals( expectedAnalysis, actualAnalysis );
274     }
275 
276     public void testMultimoduleProject()
277         throws TestToolsException, ProjectDependencyAnalyzerException
278     {
279         compileProject( "multimoduleProject/pom.xml" );
280 
281         // difficult to create multi-module project with Maven 2.x, so here's hacky solution
282         // to get a inter-module dependency
283         MavenProject project = getProject( "multimoduleProject/module2/pom.xml" );
284         @SuppressWarnings( "unchecked" )
285         Set<Artifact> dependencyArtifacts = project.getArtifacts();
286         for ( Artifact artifact : dependencyArtifacts )
287         {
288             if ( artifact.getArtifactId().equals( "test-module1" ) )
289             {
290                 File dir = getTestFile( "target/test-classes/", "multimoduleProject/module1/target/classes/" );
291                 artifact.setFile( dir );
292             }
293         }
294 
295         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
296 
297         Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" );
298         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( junit );
299 
300         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null );
301 
302         assertEquals( expectedAnalysis, actualAnalysis );
303     }
304 
305     public void testTypeUseAnnotationDependency()
306             throws TestToolsException, ProjectDependencyAnalyzerException
307     {
308         // java.lang.annotation.ElementType.TYPE_USE introduced with Java 1.8
309         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
310         {
311             return;
312         }
313 
314         Properties properties = new Properties();
315         properties.put( "maven.compiler.source", "1.8" );
316         properties.put( "maven.compiler.target", "1.8" );
317         compileProject( "typeUseAnnotationDependency/pom.xml", properties);
318 
319         MavenProject usage = getProject( "typeUseAnnotationDependency/usage/pom.xml" );
320 
321         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
322 
323         Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
324                                             "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
325         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
326         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null);
327 
328         assertEquals( expectedAnalysis, actualAnalysis );
329     }
330 
331     // private methods --------------------------------------------------------
332 
333     private void compileProject( String pomPath )
334         throws TestToolsException
335     {
336         compileProject( pomPath, new Properties() );
337     }
338 
339     private void compileProject(String pomPath, Properties properties) throws TestToolsException {
340         File pom = getTestFile( "target/test-classes/", pomPath );
341         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_9 )
342              && !properties.containsKey( "maven.compiler.source" ) )
343         {
344           properties.put( "maven.compiler.source", "1.6" );
345           properties.put( "maven.compiler.target", "1.6" );
346         }
347 
348         List<String> goals = Arrays.asList( "clean", "install" );
349         File log = new File( pom.getParentFile(), "build.log" );
350 
351         // TODO: don't install test artifacts to local repository
352         InvocationRequest request = buildTool.createBasicInvocationRequest( pom, properties, goals, log );
353         request.setLocalRepositoryDirectory( localRepo );
354         InvocationResult result = buildTool.executeMaven( request );
355 
356         assertNull( "Error compiling test project", result.getExecutionException() );
357         assertEquals( "Error compiling test project", 0, result.getExitCode() );
358     }
359 
360     private MavenProject getProject( String pomPath )
361         throws TestToolsException
362     {
363         File pom = getTestFile( "target/test-classes/", pomPath );
364 
365         return projectTool.readProjectWithDependencies( pom );
366     }
367 
368     private Artifact createArtifact( String groupId, String artifactId, String type, String version, String scope )
369     {
370         VersionRange versionRange = VersionRange.createFromVersion( version );
371         ArtifactHandler handler = new DefaultArtifactHandler();
372 
373         return new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, handler );
374     }
375 }