1 package org.eclipse.aether.internal.impl.collect;
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.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
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
449
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 }