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 testJarWithCompileScopedTestDependency()
282             throws TestToolsException, ProjectDependencyAnalyzerException
283     {
284         compileProject( "jarWithCompileScopedTestDependency/pom.xml" );
285 
286         MavenProject project2 = getProject( "jarWithCompileScopedTestDependency/project2/pom.xml" );
287 
288         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
289 
290         Artifact artifact1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
291                 "jarWithCompileScopedTestDependency1", "jar", "1.0", "test" );
292         Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "compile" );
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 testJarWithRuntimeScopedTestDependency() throws TestToolsException, ProjectDependencyAnalyzerException
315     {
316         // We can't effectively analyze runtime dependencies at this time
317         compileProject( "jarWithRuntimeScopedTestDependency/pom.xml" );
318 
319         MavenProject project2 = getProject( "jarWithRuntimeScopedTestDependency/project2/pom.xml" );
320 
321         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
322 
323         Artifact artifact1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
324                 "jarWithRuntimeScopedTestDependency1", "jar", "1.0", "test" );
325         Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "runtime" );
326 
327         ProjectDependencyAnalysis expectedAnalysis;
328         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
329         {
330             Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) );
331             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
332                     null );
333         }
334         else
335         {
336             // With JDK 7 and earlier, not all deps are identified correctly
337             Set<Artifact> usedDeclaredArtifacts = Collections.singleton( artifact1 );
338             Set<Artifact> unUsedDeclaredArtifacts = Collections.singleton( junit );
339             expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, unUsedDeclaredArtifacts,
340                     null );
341         }
342 
343         assertEquals( expectedAnalysis, actualAnalysis );
344     }
345 
346     public void testMultimoduleProject()
347         throws TestToolsException, ProjectDependencyAnalyzerException
348     {
349         compileProject( "multimoduleProject/pom.xml" );
350 
351         // difficult to create multi-module project with Maven 2.x, so here's hacky solution
352         // to get a inter-module dependency
353         MavenProject project = getProject( "multimoduleProject/module2/pom.xml" );
354         @SuppressWarnings( "unchecked" )
355         Set<Artifact> dependencyArtifacts = project.getArtifacts();
356         for ( Artifact artifact : dependencyArtifacts )
357         {
358             if ( artifact.getArtifactId().equals( "test-module1" ) )
359             {
360                 File dir = getTestFile( "target/test-classes/", "multimoduleProject/module1/target/classes/" );
361                 artifact.setFile( dir );
362             }
363         }
364 
365         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
366 
367         Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" );
368         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( junit );
369 
370         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null,
371                 null );
372 
373         assertEquals( expectedAnalysis, actualAnalysis );
374     }
375 
376     public void testTypeUseAnnotationDependency()
377             throws TestToolsException, ProjectDependencyAnalyzerException
378     {
379         // java.lang.annotation.ElementType.TYPE_USE introduced with Java 1.8
380         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
381         {
382             return;
383         }
384 
385         Properties properties = new Properties();
386         properties.put( "maven.compiler.source", "1.8" );
387         properties.put( "maven.compiler.target", "1.8" );
388         compileProject( "typeUseAnnotationDependency/pom.xml", properties);
389 
390         MavenProject usage = getProject( "typeUseAnnotationDependency/usage/pom.xml" );
391 
392         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
393 
394         Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
395                                             "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
396         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
397         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null,
398                 null );
399 
400         assertEquals( expectedAnalysis, actualAnalysis );
401     }
402 
403     public void testTypeUseAnnotationDependencyOnLocalVariable()
404             throws TestToolsException, ProjectDependencyAnalyzerException
405     {
406         // java.lang.annotation.ElementType.TYPE_USE introduced with Java 1.8
407         if ( !SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
408         {
409             return;
410         }
411 
412         Properties properties = new Properties();
413         properties.put( "maven.compiler.source", "1.8" );
414         properties.put( "maven.compiler.target", "1.8" );
415         compileProject( "typeUseAnnotationDependency/pom.xml", properties);
416 
417         MavenProject usage = getProject( "typeUseAnnotationDependency/usageLocalVar/pom.xml" );
418 
419         ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
420 
421         Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
422                                             "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
423         Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
424         ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null,
425                 null);
426 
427         assertEquals( expectedAnalysis, actualAnalysis );
428     }
429 
430     // private methods --------------------------------------------------------
431 
432     private void compileProject( String pomPath )
433         throws TestToolsException
434     {
435         compileProject( pomPath, new Properties() );
436     }
437 
438     private void compileProject(String pomPath, Properties properties) throws TestToolsException {
439         File pom = getTestFile( "target/test-classes/", pomPath );
440         if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_9 )
441              && !properties.containsKey( "maven.compiler.source" ) )
442         {
443           properties.put( "maven.compiler.source", "1.7" );
444           properties.put( "maven.compiler.target", "1.7" );
445         }
446         
447         String httpsProtocols = System.getProperty( "https.protocols" );
448         if ( httpsProtocols != null )
449         {
450             properties.put( "https.protocols", httpsProtocols );
451         }
452 
453         List<String> goals = Arrays.asList( "clean", "install" );
454         File log = new File( pom.getParentFile(), "build.log" );
455 
456         // TODO: don't install test artifacts to local repository
457         InvocationRequest request = buildTool.createBasicInvocationRequest( pom, properties, goals, log );
458         request.setLocalRepositoryDirectory( localRepo );
459         InvocationResult result = buildTool.executeMaven( request );
460 
461         assertNull( "Error compiling test project", result.getExecutionException() );
462         assertEquals( "Error compiling test project", 0, result.getExitCode() );
463     }
464 
465     private MavenProject getProject( String pomPath )
466         throws TestToolsException
467     {
468         File pom = getTestFile( "target/test-classes/", pomPath );
469 
470         return projectTool.readProjectWithDependencies( pom );
471     }
472 
473     private Artifact createArtifact( String groupId, String artifactId, String type, String version, String scope )
474     {
475         VersionRange versionRange = VersionRange.createFromVersion( version );
476         ArtifactHandler handler = new DefaultArtifactHandler();
477 
478         return new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, handler );
479     }
480 }