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