View Javadoc
1   package org.eclipse.aether.internal.impl.collect;
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 static org.junit.Assert.*;
23  
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.LinkedList;
32  import java.util.List;
33  import java.util.Map;
34  
35  import org.eclipse.aether.DefaultRepositorySystemSession;
36  import org.eclipse.aether.RepositorySystemSession;
37  import org.eclipse.aether.artifact.Artifact;
38  import org.eclipse.aether.artifact.ArtifactProperties;
39  import org.eclipse.aether.artifact.DefaultArtifact;
40  import org.eclipse.aether.collection.CollectRequest;
41  import org.eclipse.aether.collection.CollectResult;
42  import org.eclipse.aether.collection.DependencyCollectionContext;
43  import org.eclipse.aether.collection.DependencyCollectionException;
44  import org.eclipse.aether.collection.DependencyManagement;
45  import org.eclipse.aether.collection.DependencyManager;
46  import org.eclipse.aether.graph.Dependency;
47  import org.eclipse.aether.graph.DependencyCycle;
48  import org.eclipse.aether.graph.DependencyNode;
49  import org.eclipse.aether.graph.Exclusion;
50  import org.eclipse.aether.impl.ArtifactDescriptorReader;
51  import org.eclipse.aether.internal.impl.IniArtifactDescriptorReader;
52  import org.eclipse.aether.internal.impl.StubRemoteRepositoryManager;
53  import org.eclipse.aether.internal.impl.StubVersionRangeResolver;
54  import org.eclipse.aether.internal.test.util.DependencyGraphParser;
55  import org.eclipse.aether.internal.test.util.TestUtils;
56  import org.eclipse.aether.repository.RemoteRepository;
57  import org.eclipse.aether.resolution.ArtifactDescriptorException;
58  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
59  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
60  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
61  import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
62  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
63  import org.eclipse.aether.util.graph.version.HighestVersionFilter;
64  import org.junit.Before;
65  import org.junit.Test;
66  
67  /**
68   */
69  public class DefaultDependencyCollectorTest
70  {
71  
72      private DefaultDependencyCollector collector;
73  
74      private DefaultRepositorySystemSession session;
75  
76      private DependencyGraphParser parser;
77  
78      private RemoteRepository repository;
79  
80      private IniArtifactDescriptorReader newReader( String prefix )
81      {
82          return new IniArtifactDescriptorReader( "artifact-descriptions/" + prefix );
83      }
84  
85      private Dependency newDep( String coords )
86      {
87          return newDep( coords, "" );
88      }
89  
90      private Dependency newDep( String coords, String scope )
91      {
92          return new Dependency( new DefaultArtifact( coords ), scope );
93      }
94  
95      @Before
96      public void setup()
97          throws IOException
98      {
99          session = TestUtils.newSession();
100 
101         collector = new DefaultDependencyCollector();
102         collector.setArtifactDescriptorReader( newReader( "" ) );
103         collector.setVersionRangeResolver( new StubVersionRangeResolver() );
104         collector.setRemoteRepositoryManager( new StubRemoteRepositoryManager() );
105 
106         parser = new DependencyGraphParser( "artifact-descriptions/" );
107 
108         repository = new RemoteRepository.Builder( "id", "default", "file:///" ).build();
109     }
110 
111     private static void assertEqualSubtree( DependencyNode expected, DependencyNode actual )
112     {
113         assertEqualSubtree( expected, actual, new LinkedList<DependencyNode>() );
114     }
115 
116     private static void assertEqualSubtree( DependencyNode expected, DependencyNode actual,
117                                             LinkedList<DependencyNode> parents )
118     {
119         assertEquals( "path: " + parents, expected.getDependency(), actual.getDependency() );
120 
121         if ( actual.getDependency() != null )
122         {
123             Artifact artifact = actual.getDependency().getArtifact();
124             for ( DependencyNode parent : parents )
125             {
126                 if ( parent.getDependency() != null && artifact.equals( parent.getDependency().getArtifact() ) )
127                 {
128                     return;
129                 }
130             }
131         }
132 
133         parents.addLast( expected );
134 
135         assertEquals( "path: " + parents + ", expected: " + expected.getChildren() + ", actual: "
136                           + actual.getChildren(), expected.getChildren().size(), actual.getChildren().size() );
137 
138         Iterator<DependencyNode> iterator1 = expected.getChildren().iterator();
139         Iterator<DependencyNode> iterator2 = actual.getChildren().iterator();
140 
141         while ( iterator1.hasNext() )
142         {
143             assertEqualSubtree( iterator1.next(), iterator2.next(), parents );
144         }
145 
146         parents.removeLast();
147     }
148 
149     private Dependency dep( DependencyNode root, int... coords )
150     {
151         return path( root, coords ).getDependency();
152     }
153 
154     private DependencyNode path( DependencyNode root, int... coords )
155     {
156         try
157         {
158             DependencyNode node = root;
159             for ( int coord : coords )
160             {
161                 node = node.getChildren().get( coord );
162             }
163 
164             return node;
165         }
166         catch ( IndexOutOfBoundsException e )
167         {
168             throw new IllegalArgumentException( "illegal coordinates for child", e );
169         }
170         catch ( NullPointerException e )
171         {
172             throw new IllegalArgumentException( "illegal coordinates for child", e );
173         }
174     }
175 
176     @Test
177     public void testSimpleCollection()
178         throws IOException, DependencyCollectionException
179     {
180         Dependency dependency = newDep( "gid:aid:ext:ver", "compile" );
181         CollectRequest request = new CollectRequest( dependency, Arrays.asList( repository ) );
182         CollectResult result = collector.collectDependencies( session, request );
183 
184         assertEquals( 0, result.getExceptions().size() );
185 
186         DependencyNode root = result.getRoot();
187         Dependency newDependency = root.getDependency();
188 
189         assertEquals( dependency, newDependency );
190         assertEquals( dependency.getArtifact(), newDependency.getArtifact() );
191 
192         assertEquals( 1, root.getChildren().size() );
193 
194         Dependency expect = newDep( "gid:aid2:ext:ver", "compile" );
195         assertEquals( expect, root.getChildren().get( 0 ).getDependency() );
196     }
197 
198     @Test
199     public void testMissingDependencyDescription()
200         throws IOException
201     {
202         CollectRequest request =
203             new CollectRequest( newDep( "missing:description:ext:ver" ), Arrays.asList( repository ) );
204         try
205         {
206             collector.collectDependencies( session, request );
207             fail( "expected exception" );
208         }
209         catch ( DependencyCollectionException e )
210         {
211             CollectResult result = e.getResult();
212             assertSame( request, result.getRequest() );
213             assertNotNull( result.getExceptions() );
214             assertEquals( 1, result.getExceptions().size() );
215 
216             assertTrue( result.getExceptions().get( 0 ) instanceof ArtifactDescriptorException );
217 
218             assertEquals( request.getRoot(), result.getRoot().getDependency() );
219         }
220     }
221 
222     @Test
223     public void testDuplicates()
224         throws IOException, DependencyCollectionException
225     {
226         Dependency dependency = newDep( "duplicate:transitive:ext:dependency" );
227         CollectRequest request = new CollectRequest( dependency, Arrays.asList( repository ) );
228 
229         CollectResult result = collector.collectDependencies( session, request );
230 
231         assertEquals( 0, result.getExceptions().size() );
232 
233         DependencyNode root = result.getRoot();
234         Dependency newDependency = root.getDependency();
235 
236         assertEquals( dependency, newDependency );
237         assertEquals( dependency.getArtifact(), newDependency.getArtifact() );
238 
239         assertEquals( 2, root.getChildren().size() );
240 
241         Dependency dep = newDep( "gid:aid:ext:ver", "compile" );
242         assertEquals( dep, dep( root, 0 ) );
243 
244         dep = newDep( "gid:aid2:ext:ver", "compile" );
245         assertEquals( dep, dep( root, 1 ) );
246         assertEquals( dep, dep( root, 0, 0 ) );
247         assertEquals( dep( root, 1 ), dep( root, 0, 0 ) );
248     }
249 
250     @Test
251     public void testEqualSubtree()
252         throws IOException, DependencyCollectionException
253     {
254         DependencyNode root = parser.parseResource( "expectedSubtreeComparisonResult.txt" );
255         Dependency dependency = root.getDependency();
256         CollectRequest request = new CollectRequest( dependency, Arrays.asList( repository ) );
257 
258         CollectResult result = collector.collectDependencies( session, request );
259         assertEqualSubtree( root, result.getRoot() );
260     }
261 
262     @Test
263     public void testCyclicDependencies()
264         throws Exception
265     {
266         DependencyNode root = parser.parseResource( "cycle.txt" );
267         CollectRequest request = new CollectRequest( root.getDependency(), Arrays.asList( repository ) );
268         CollectResult result = collector.collectDependencies( session, request );
269         assertEqualSubtree( root, result.getRoot() );
270     }
271 
272     @Test
273     public void testCyclicDependenciesBig()
274         throws Exception
275     {
276         CollectRequest request = new CollectRequest( newDep( "1:2:pom:5.50-SNAPSHOT" ), Arrays.asList( repository ) );
277         collector.setArtifactDescriptorReader( newReader( "cycle-big/" ) );
278         CollectResult result = collector.collectDependencies( session, request );
279         assertNotNull( result.getRoot() );
280         // we only care about the performance here, this test must not hang or run out of mem
281     }
282 
283     @Test
284     public void testCyclicProjects()
285         throws Exception
286     {
287         CollectRequest request = new CollectRequest( newDep( "test:a:2" ), Arrays.asList( repository ) );
288         collector.setArtifactDescriptorReader( newReader( "versionless-cycle/" ) );
289         CollectResult result = collector.collectDependencies( session, request );
290         DependencyNode root = result.getRoot();
291         DependencyNode a1 = path( root, 0, 0 );
292         assertEquals( "a", a1.getArtifact().getArtifactId() );
293         assertEquals( "1", a1.getArtifact().getVersion() );
294         for ( DependencyNode child : a1.getChildren() )
295         {
296             assertFalse( "1".equals( child.getArtifact().getVersion() ) );
297         }
298 
299         assertEquals( 1, result.getCycles().size() );
300         DependencyCycle cycle = result.getCycles().get( 0 );
301         assertEquals( Arrays.asList(), cycle.getPrecedingDependencies() );
302         assertEquals( Arrays.asList( root.getDependency(), path( root, 0 ).getDependency(), a1.getDependency() ),
303                       cycle.getCyclicDependencies() );
304     }
305 
306     @Test
307     public void testCyclicProjects_ConsiderLabelOfRootlessGraph()
308         throws Exception
309     {
310         Dependency dep = newDep( "gid:aid:ver", "compile" );
311         CollectRequest request =
312             new CollectRequest().addDependency( dep ).addRepository( repository ).setRootArtifact( dep.getArtifact() );
313         CollectResult result = collector.collectDependencies( session, request );
314         DependencyNode root = result.getRoot();
315         DependencyNode a1 = root.getChildren().get( 0 );
316         assertEquals( "aid", a1.getArtifact().getArtifactId() );
317         assertEquals( "ver", a1.getArtifact().getVersion() );
318         DependencyNode a2 = a1.getChildren().get( 0 );
319         assertEquals( "aid2", a2.getArtifact().getArtifactId() );
320         assertEquals( "ver", a2.getArtifact().getVersion() );
321 
322         assertEquals( 1, result.getCycles().size() );
323         DependencyCycle cycle = result.getCycles().get( 0 );
324         assertEquals( Arrays.asList(), cycle.getPrecedingDependencies() );
325         assertEquals( Arrays.asList( new Dependency( dep.getArtifact(), null ), a1.getDependency() ),
326                       cycle.getCyclicDependencies() );
327     }
328 
329     @Test
330     public void testPartialResultOnError()
331         throws IOException
332     {
333         DependencyNode root = parser.parseResource( "expectedPartialSubtreeOnError.txt" );
334 
335         Dependency dependency = root.getDependency();
336         CollectRequest request = new CollectRequest( dependency, Arrays.asList( repository ) );
337 
338         CollectResult result;
339         try
340         {
341             result = collector.collectDependencies( session, request );
342             fail( "expected exception " );
343         }
344         catch ( DependencyCollectionException e )
345         {
346             result = e.getResult();
347 
348             assertSame( request, result.getRequest() );
349             assertNotNull( result.getExceptions() );
350             assertEquals( 1, result.getExceptions().size() );
351 
352             assertTrue( result.getExceptions().get( 0 ) instanceof ArtifactDescriptorException );
353 
354             assertEqualSubtree( root, result.getRoot() );
355         }
356     }
357 
358     @Test
359     public void testCollectMultipleDependencies()
360         throws IOException, DependencyCollectionException
361     {
362         Dependency root1 = newDep( "gid:aid:ext:ver", "compile" );
363         Dependency root2 = newDep( "gid:aid2:ext:ver", "compile" );
364         List<Dependency> dependencies = Arrays.asList( root1, root2 );
365         CollectRequest request = new CollectRequest( dependencies, null, Arrays.asList( repository ) );
366         CollectResult result = collector.collectDependencies( session, request );
367 
368         assertEquals( 0, result.getExceptions().size() );
369         assertEquals( 2, result.getRoot().getChildren().size() );
370         assertEquals( root1, dep( result.getRoot(), 0 ) );
371 
372         assertEquals( 1, path( result.getRoot(), 0 ).getChildren().size() );
373         assertEquals( root2, dep( result.getRoot(), 0, 0 ) );
374 
375         assertEquals( 0, path( result.getRoot(), 1 ).getChildren().size() );
376         assertEquals( root2, dep( result.getRoot(), 1 ) );
377     }
378 
379     @Test
380     public void testArtifactDescriptorResolutionNotRestrictedToRepoHostingSelectedVersion()
381         throws Exception
382     {
383         RemoteRepository repo2 = new RemoteRepository.Builder( "test", "default", "file:///" ).build();
384 
385         final List<RemoteRepository> repos = new ArrayList<RemoteRepository>();
386 
387         collector.setArtifactDescriptorReader( new ArtifactDescriptorReader()
388         {
389             public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
390                                                                     ArtifactDescriptorRequest request )
391                 throws ArtifactDescriptorException
392             {
393                 repos.addAll( request.getRepositories() );
394                 return new ArtifactDescriptorResult( request );
395             }
396         } );
397 
398         List<Dependency> dependencies = Arrays.asList( newDep( "verrange:parent:jar:1[1,)", "compile" ) );
399         CollectRequest request = new CollectRequest( dependencies, null, Arrays.asList( repository, repo2 ) );
400         CollectResult result = collector.collectDependencies( session, request );
401 
402         assertEquals( 0, result.getExceptions().size() );
403         assertEquals( 2, repos.size() );
404         assertEquals( "id", repos.get( 0 ).getId() );
405         assertEquals( "test", repos.get( 1 ).getId() );
406     }
407 
408     @Test
409     public void testManagedVersionScope()
410         throws IOException, DependencyCollectionException
411     {
412         Dependency dependency = newDep( "managed:aid:ext:ver" );
413         CollectRequest request = new CollectRequest( dependency, Arrays.asList( repository ) );
414 
415         session.setDependencyManager( new ClassicDependencyManager() );
416 
417         CollectResult result = collector.collectDependencies( session, request );
418 
419         assertEquals( 0, result.getExceptions().size() );
420 
421         DependencyNode root = result.getRoot();
422 
423         assertEquals( dependency, dep( root ) );
424         assertEquals( dependency.getArtifact(), dep( root ).getArtifact() );
425 
426         assertEquals( 1, root.getChildren().size() );
427         Dependency expect = newDep( "gid:aid:ext:ver", "compile" );
428         assertEquals( expect, dep( root, 0 ) );
429 
430         assertEquals( 1, path( root, 0 ).getChildren().size() );
431         expect = newDep( "gid:aid2:ext:managedVersion", "managedScope" );
432         assertEquals( expect, dep( root, 0, 0 ) );
433     }
434 
435     @Test
436     public void testDependencyManagement()
437         throws IOException, DependencyCollectionException
438     {
439         collector.setArtifactDescriptorReader( newReader( "managed/" ) );
440 
441         DependencyNode root = parser.parseResource( "expectedSubtreeComparisonResult.txt" );
442         TestDependencyManager depMgmt = new TestDependencyManager();
443         depMgmt.add( dep( root, 0 ), "managed", null, null );
444         depMgmt.add( dep( root, 0, 1 ), "managed", "managed", null );
445         depMgmt.add( dep( root, 1 ), null, null, "managed" );
446         session.setDependencyManager( depMgmt );
447 
448         // collect result will differ from expectedSubtreeComparisonResult.txt
449         // set localPath -> no dependency traversal
450         CollectRequest request = new CollectRequest( dep( root ), Arrays.asList( repository ) );
451         CollectResult result = collector.collectDependencies( session, request );
452 
453         DependencyNode node = result.getRoot();
454         assertEquals( "managed", dep( node, 0, 1 ).getArtifact().getVersion() );
455         assertEquals( "managed", dep( node, 0, 1 ).getScope() );
456 
457         assertEquals( "managed", dep( node, 1 ).getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) );
458         assertEquals( "managed", dep( node, 0, 0 ).getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) );
459     }
460 
461     @Test
462     public void testDependencyManagement_VerboseMode()
463         throws Exception
464     {
465         String depId = "gid:aid2:ext";
466         TestDependencyManager depMgmt = new TestDependencyManager();
467         depMgmt.version( depId, "managedVersion" );
468         depMgmt.scope( depId, "managedScope" );
469         depMgmt.optional( depId, Boolean.TRUE );
470         depMgmt.path( depId, "managedPath" );
471         depMgmt.exclusions( depId, new Exclusion( "gid", "aid", "*", "*" ) );
472         session.setDependencyManager( depMgmt );
473         session.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE );
474 
475         CollectRequest request = new CollectRequest().setRoot( newDep( "gid:aid:ver" ) );
476         CollectResult result = collector.collectDependencies( session, request );
477         DependencyNode node = result.getRoot().getChildren().get( 0 );
478         assertEquals( DependencyNode.MANAGED_VERSION | DependencyNode.MANAGED_SCOPE | DependencyNode.MANAGED_OPTIONAL
479             | DependencyNode.MANAGED_PROPERTIES | DependencyNode.MANAGED_EXCLUSIONS, node.getManagedBits() );
480         assertEquals( "ver", DependencyManagerUtils.getPremanagedVersion( node ) );
481         assertEquals( "compile", DependencyManagerUtils.getPremanagedScope( node ) );
482         assertEquals( Boolean.FALSE, DependencyManagerUtils.getPremanagedOptional( node ) );
483     }
484 
485     @Test
486     public void testVersionFilter()
487         throws Exception
488     {
489         session.setVersionFilter( new HighestVersionFilter() );
490         CollectRequest request = new CollectRequest().setRoot( newDep( "gid:aid:1" ) );
491         CollectResult result = collector.collectDependencies( session, request );
492         assertEquals( 1, result.getRoot().getChildren().size() );
493     }
494 
495     static class TestDependencyManager
496         implements DependencyManager
497     {
498 
499         private Map<String, String> versions = new HashMap<String, String>();
500 
501         private Map<String, String> scopes = new HashMap<String, String>();
502 
503         private Map<String, Boolean> optionals = new HashMap<String, Boolean>();
504 
505         private Map<String, String> paths = new HashMap<String, String>();
506 
507         private Map<String, Collection<Exclusion>> exclusions = new HashMap<String, Collection<Exclusion>>();
508 
509         public void add( Dependency d, String version, String scope, String localPath )
510         {
511             String id = toKey( d );
512             version( id, version );
513             scope( id, scope );
514             path( id, localPath );
515         }
516 
517         public void version( String id, String version )
518         {
519             versions.put( id, version );
520         }
521 
522         public void scope( String id, String scope )
523         {
524             scopes.put( id, scope );
525         }
526 
527         public void optional( String id, Boolean optional )
528         {
529             optionals.put( id, optional );
530         }
531 
532         public void path( String id, String path )
533         {
534             paths.put( id, path );
535         }
536 
537         public void exclusions( String id, Exclusion... exclusions )
538         {
539             this.exclusions.put( id, exclusions != null ? Arrays.asList( exclusions ) : null );
540         }
541 
542         public DependencyManagement manageDependency( Dependency d )
543         {
544             String id = toKey( d );
545             DependencyManagement mgmt = new DependencyManagement();
546             mgmt.setVersion( versions.get( id ) );
547             mgmt.setScope( scopes.get( id ) );
548             mgmt.setOptional( optionals.get( id ) );
549             String path = paths.get( id );
550             if ( path != null )
551             {
552                 mgmt.setProperties( Collections.singletonMap( ArtifactProperties.LOCAL_PATH, path ) );
553             }
554             mgmt.setExclusions( exclusions.get( id ) );
555             return mgmt;
556         }
557 
558         private String toKey( Dependency dependency )
559         {
560             return ArtifactIdUtils.toVersionlessId( dependency.getArtifact() );
561         }
562 
563         public DependencyManager deriveChildManager( DependencyCollectionContext context )
564         {
565             return this;
566         }
567 
568     }
569 
570 }