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                     new HashSet<Artifact>() );
143 
144         assertEquals( expectedAnalysis, actualAnalysis );
145     }
146 
147     public void testInlinedStaticReference()
148         throws TestToolsException, ProjectDependencyAnalyzerException
149     {
150         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
151         {
152             return;
153         }
154 
155         // Only visible through constant pool analysis (supported for JDK8+)
156         compileProject( "inlinedStaticReference/pom.xml" );
157 
158         MavenProject project = getProject( "inlinedStaticReference/pom.xml" );
159 
160         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
161 
162         Artifact project1 = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
163         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
164 
165         ProjectDependencyAnalysis expectedAnalysis =
166             new ProjectDependencyAnalysis( usedDeclaredArtifacts, new HashSet<Artifact>(), new HashSet<Artifact>(),
167                     new HashSet<Artifact>() );
168 
169         assertEquals( expectedAnalysis, actualAnalysis );
170     }
171 
172     public void testJarWithCompileDependency()
173         throws TestToolsException, ProjectDependencyAnalyzerException
174     {
175         compileProject( "jarWithCompileDependency/pom.xml" );
176 
177         MavenProject project2 = getProject( "jarWithCompileDependency/project2/pom.xml" );
178 
179         if ( project2.getBuild().getOutputDirectory().contains( "${" ) )
180         {
181             // if Maven version used as dependency is upgraded to >= 2.2.0
182             throw new TestToolsException( "output directory was not interpolated: "
183                 + project2.getBuild().getOutputDirectory() );
184         }
185 
186         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
187 
188         Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
189                                             "jarWithCompileDependency1", "jar", "1.0", "compile" );
190         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
191         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
192                 null );
193 
194         assertEquals( expectedAnalysis, actualAnalysis );
195     }
196 
197     public void testForceDeclaredDependenciesUsage()
198         throws TestToolsException, ProjectDependencyAnalyzerException
199     {
200         compileProject( "jarWithTestDependency/pom.xml" );
201 
202         MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
203 
204         ProjectDependencyAnalysis analysis = analyzer.analyze( project2 );
205 
206         try
207         {
208             analysis.forceDeclaredDependenciesUsage( new String[] {
209                 "org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1" } );
210             fail( "failure expected since junit dependency is declared-used" );
211         }
212         catch ( ProjectDependencyAnalyzerException pdae )
213         {
214             assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
215                 + "declared but already detected as used: "
216                 + "[org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1]" ) );
217         }
218 
219         try
220         {
221             analysis.forceDeclaredDependenciesUsage( new String[] { "undefined:undefined" } );
222             fail( "failure expected since undefined dependency is not declared" );
223         }
224         catch ( ProjectDependencyAnalyzerException pdae )
225         {
226             assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
227                 + "not declared: [undefined:undefined]" ) );
228         }
229     }
230 
231     public void testJarWithTestDependency()
232         throws TestToolsException, ProjectDependencyAnalyzerException
233     {
234         compileProject( "jarWithTestDependency/pom.xml" );
235 
236         MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
237 
238         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
239 
240         Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
241                                             "jarWithTestDependency1", "jar", "1.0", "test" );
242         Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "test" );
243 
244         ProjectDependencyAnalysis expectedAnalysis;
245         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
246         {
247             Set<Artifact> usedDeclaredArtifacts = new HashSet<Artifact>( Arrays.asList( project1, junit ) );
248             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, null );
249         }
250         else
251         {
252             // With JDK 7 and earlier, not all deps are identified correctly
253             Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
254             Set<Artifact> unusedDeclaredArtifacts = Collections.singleton( junit );
255             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, unusedDeclaredArtifacts,
256                     null );
257         }
258 
259         assertEquals( expectedAnalysis, actualAnalysis );
260     }
261 
262     public void testJarWithXmlTransitiveDependency()
263         throws TestToolsException, ProjectDependencyAnalyzerException
264     {
265         compileProject( "jarWithXmlTransitiveDependency/pom.xml" );
266 
267         MavenProject project = getProject( "jarWithXmlTransitiveDependency/pom.xml" );
268 
269         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
270 
271         Artifact jdom = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
272         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( jdom );
273 
274         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
275                 null );
276 
277         // MSHARED-47: usedUndeclaredArtifacts=[xml-apis:xml-apis:jar:1.0.b2:compile]
278         // assertEquals( expectedAnalysis, actualAnalysis );
279     }
280 
281     public void testJarWithNonTestScopedTestDependency()
282             throws TestToolsException, ProjectDependencyAnalyzerException
283     {
284         compileProject( "jarWithNonTestScopedTestDependency/pom.xml" );
285 
286         MavenProject project2 = getProject( "jarWithNonTestScopedTestDependency/project2/pom.xml" );
287 
288         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
289 
290         Artifact artifact1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
291                 "jarWithNonTestScopedTestDependency1", "jar", "1.0", "test" );
292         Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "test" );
293 
294         ProjectDependencyAnalysis expectedAnalysis;
295         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
296         {
297             Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) );
298             Set<Artifact> nonTestScopedTestArtifacts = Collections.singleton( junit );
299             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
300                     nonTestScopedTestArtifacts );
301         }
302         else
303         {
304             // With JDK 7 and earlier, not all deps are identified correctly
305             Set<Artifact> usedDeclaredArtifacts = Collections.singleton( artifact1 );
306             Set<Artifact> unUsedDeclaredArtifacts = Collections.singleton( junit );
307             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, unUsedDeclaredArtifacts,
308                     null );
309         }
310 
311         assertEquals( expectedAnalysis, actualAnalysis );
312     }
313 
314     public void testMultimoduleProject()
315         throws TestToolsException, ProjectDependencyAnalyzerException
316     {
317         compileProject( "multimoduleProject/pom.xml" );
318 
319         // difficult to create multi-module project with Maven 2.x, so here's hacky solution
320         // to get a inter-module dependency
321         MavenProject project = getProject( "multimoduleProject/module2/pom.xml" );
322         @SuppressWarnings( "unchecked" )
323         Set<Artifact> dependencyArtifacts = project.getArtifacts();
324         for ( Artifact artifact : dependencyArtifacts )
325         {
326             if ( artifact.getArtifactId().equals( "test-module1" ) )
327             {
328                 File dir = getTestFile( "target/test-classes/", "multimoduleProject/module1/target/classes/" );
329                 artifact.setFile( dir );
330             }
331         }
332 
333         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
334 
335         Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" );
336         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( junit );
337 
338         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
339                 null );
340 
341         assertEquals( expectedAnalysis, actualAnalysis );
342     }
343 
344     public void testTypeUseAnnotationDependency()
345             throws TestToolsException, ProjectDependencyAnalyzerException
346     {
347         // java.lang.annotation.ElementType.TYPE_USE introduced with Java 1.8
348         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
349         {
350             return;
351         }
352 
353         Properties properties = new Properties();
354         properties.put( "maven.compiler.source", "1.8" );
355         properties.put( "maven.compiler.target", "1.8" );
356         compileProject( "typeUseAnnotationDependency/pom.xml", properties);
357 
358         MavenProject usage = getProject( "typeUseAnnotationDependency/usage/pom.xml" );
359 
360         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
361 
362         Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
363                                             "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
364         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
365         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null,
366                 null );
367 
368         assertEquals( expectedAnalysis, actualAnalysis );
369     }
370 
371     public void testTypeUseAnnotationDependencyOnLocalVariable()
372             throws TestToolsException, ProjectDependencyAnalyzerException
373     {
374         // java.lang.annotation.ElementType.TYPE_USE introduced with Java 1.8
375         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
376         {
377             return;
378         }
379 
380         Properties properties = new Properties();
381         properties.put( "maven.compiler.source", "1.8" );
382         properties.put( "maven.compiler.target", "1.8" );
383         compileProject( "typeUseAnnotationDependency/pom.xml", properties);
384 
385         MavenProject usage = getProject( "typeUseAnnotationDependency/usageLocalVar/pom.xml" );
386 
387         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
388 
389         Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
390                                             "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
391         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
392         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null,
393                 null);
394 
395         assertEquals( expectedAnalysis, actualAnalysis );
396     }
397 
398     // private methods --------------------------------------------------------
399 
400     private void compileProject( String pomPath )
401         throws TestToolsException
402     {
403         compileProject( pomPath, new Properties() );
404     }
405 
406     private void compileProject(String pomPath, Properties properties) throws TestToolsException {
407         File pom = getTestFile( "target/test-classes/", pomPath );
408         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_9 )
409              && !properties.containsKey( "maven.compiler.source" ) )
410         {
411           properties.put( "maven.compiler.source", "1.7" );
412           properties.put( "maven.compiler.target", "1.7" );
413         }
414         
415         String httpsProtocols = System.getProperty( "https.protocols" );
416         if ( httpsProtocols != null )
417         {
418             properties.put( "https.protocols", httpsProtocols );
419         }
420 
421         List<String> goals = Arrays.asList( "clean", "install" );
422         File log = new File( pom.getParentFile(), "build.log" );
423 
424         // TODO: don't install test artifacts to local repository
425         InvocationRequest request = buildTool.createBasicInvocationRequest( pom, properties, goals, log );
426         request.setLocalRepositoryDirectory( localRepo );
427         InvocationResult result = buildTool.executeMaven( request );
428 
429         assertNull( "Error compiling test project", result.getExecutionException() );
430         assertEquals( "Error compiling test project", 0, result.getExitCode() );
431     }
432 
433     private MavenProject getProject( String pomPath )
434         throws TestToolsException
435     {
436         File pom = getTestFile( "target/test-classes/", pomPath );
437 
438         return projectTool.readProjectWithDependencies( pom );
439     }
440 
441     private Artifact createArtifact( String groupId, String artifactId, String type, String version, String scope )
442     {
443         VersionRange versionRange = VersionRange.createFromVersion( version );
444         ArtifactHandler handler = new DefaultArtifactHandler();
445 
446         return new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, handler );
447     }
448 }