View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.repository.legacy.resolver;
20  
21  import javax.inject.Inject;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.LinkedHashSet;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Set;
32  
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.artifact.factory.ArtifactFactory;
35  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
36  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
37  import org.apache.maven.artifact.metadata.ResolutionGroup;
38  import org.apache.maven.artifact.repository.ArtifactRepository;
39  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
40  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
41  import org.apache.maven.artifact.resolver.CyclicDependencyException;
42  import org.apache.maven.artifact.resolver.ResolutionListener;
43  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
44  import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
45  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
46  import org.apache.maven.artifact.versioning.ArtifactVersion;
47  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
48  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
49  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
50  import org.apache.maven.artifact.versioning.VersionRange;
51  import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
52  import org.codehaus.plexus.testing.PlexusTest;
53  import org.junit.jupiter.api.BeforeEach;
54  import org.junit.jupiter.api.Disabled;
55  import org.junit.jupiter.api.Test;
56  
57  import static org.junit.jupiter.api.Assertions.assertEquals;
58  import static org.junit.jupiter.api.Assertions.assertNotNull;
59  import static org.junit.jupiter.api.Assertions.assertTrue;
60  import static org.junit.jupiter.api.Assertions.fail;
61  
62  /**
63   * Test the default artifact collector.
64   *
65   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
66   */
67  @PlexusTest
68  public class DefaultArtifactCollectorTest {
69      @Inject
70      private LegacyArtifactCollector artifactCollector;
71  
72      @Inject
73      private ArtifactFactory artifactFactory;
74  
75      private ArtifactSpec projectArtifact;
76  
77      private Source source;
78  
79      private static final String GROUP_ID = "test";
80  
81      @BeforeEach
82      void setUp() throws Exception {
83          source = new Source();
84          projectArtifact = createArtifactSpec("project", "1.0", null);
85      }
86  
87      // works, but we don't fail on cycles presently
88      @Test
89      @Disabled
90      public void disabledtestCircularDependencyNotIncludingCurrentProject()
91              throws ArtifactResolutionException, InvalidVersionSpecificationException {
92          ArtifactSpec a = createArtifactSpec("a", "1.0");
93          ArtifactSpec b = a.addDependency("b", "1.0");
94          b.addDependency("a", "1.0");
95          try {
96              collect(a);
97              fail("Should have failed on cyclic dependency not involving project");
98          } catch (CyclicDependencyException expected) {
99              assertTrue(true);
100         }
101     }
102 
103     // works, but we don't fail on cycles presently
104     @Test
105     @Disabled
106     public void disabledtestCircularDependencyIncludingCurrentProject()
107             throws ArtifactResolutionException, InvalidVersionSpecificationException {
108         ArtifactSpec a = createArtifactSpec("a", "1.0");
109         ArtifactSpec b = a.addDependency("b", "1.0");
110         b.addDependency("project", "1.0");
111         try {
112             collect(a);
113             fail("Should have failed on cyclic dependency involving project");
114         } catch (CyclicDependencyException expected) {
115             assertTrue(true);
116         }
117     }
118 
119     @Test
120     public void testResolveWithFilter() throws ArtifactResolutionException, InvalidVersionSpecificationException {
121         ArtifactSpec a = createArtifactSpec("a", "1.0");
122         ArtifactSpec b = a.addDependency("b", "1.0");
123         ArtifactSpec c = a.addDependency("c", "3.0");
124 
125         b.addDependency("c", "2.0");
126         ArtifactSpec d = b.addDependency("d", "4.0");
127 
128         ArtifactResolutionResult res = collect(a);
129         assertEquals(
130                 createSet(new Object[] {a.artifact, b.artifact, c.artifact, d.artifact}),
131                 res.getArtifacts(),
132                 "Check artifact list");
133 
134         ArtifactFilter filter = new ExclusionSetFilter(new String[] {"b"});
135         res = collect(a, filter);
136         assertEquals(createSet(new Object[] {a.artifact, c.artifact}), res.getArtifacts(), "Check artifact list");
137     }
138 
139     @Test
140     public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNearest()
141             throws ArtifactResolutionException, InvalidVersionSpecificationException {
142         ArtifactSpec a = createArtifactSpec("a", "1.0");
143         ArtifactSpec b = a.addDependency("b", "1.0");
144         ArtifactSpec c2 = b.addDependency("c", "2.0");
145         c2.addDependency("d", "1.0");
146 
147         ArtifactSpec e = createArtifactSpec("e", "1.0");
148         ArtifactSpec c1 = e.addDependency("c", "1.0");
149         ArtifactSpec f = c1.addDependency("f", "1.0");
150 
151         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, e.artifact}));
152         assertEquals(
153                 createSet(new Object[] {a.artifact, b.artifact, e.artifact, c1.artifact, f.artifact}),
154                 res.getArtifacts(),
155                 "Check artifact list");
156         assertEquals("1.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
157     }
158 
159     @Test
160     @Disabled
161     public void disabledtestResolveCorrectDependenciesWhenDifferentDependenciesOnNewest()
162             throws ArtifactResolutionException, InvalidVersionSpecificationException {
163         // TODO use newest conflict resolver
164         ArtifactSpec a = createArtifactSpec("a", "1.0");
165         ArtifactSpec b = a.addDependency("b", "1.0");
166         ArtifactSpec c2 = b.addDependency("c", "2.0");
167         ArtifactSpec d = c2.addDependency("d", "1.0");
168 
169         ArtifactSpec e = createArtifactSpec("e", "1.0");
170         ArtifactSpec c1 = e.addDependency("c", "1.0");
171         c1.addDependency("f", "1.0");
172 
173         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, e.artifact}));
174         assertEquals(
175                 createSet(new Object[] {a.artifact, b.artifact, e.artifact, c2.artifact, d.artifact}),
176                 res.getArtifacts(),
177                 "Check artifact list");
178         assertEquals(
179                 "Check version", "2.0", getArtifact("c", res.getArtifacts()).getVersion());
180     }
181 
182     @Test
183     @Disabled
184     public void disabledtestResolveCorrectDependenciesWhenDifferentDependenciesOnNewestVersionReplaced()
185             throws ArtifactResolutionException, InvalidVersionSpecificationException {
186         // TODO use newest conflict resolver
187         ArtifactSpec a = createArtifactSpec("a", "1.0");
188         ArtifactSpec b1 = a.addDependency("b", "1.0");
189         ArtifactSpec c = a.addDependency("c", "1.0");
190         ArtifactSpec d2 = b1.addDependency("d", "2.0");
191         d2.addDependency("h", "1.0");
192         ArtifactSpec d1 = c.addDependency("d", "1.0");
193         ArtifactSpec b2 = c.addDependency("b", "2.0");
194         ArtifactSpec e = b2.addDependency("e", "1.0");
195         ArtifactSpec g = d1.addDependency("g", "1.0");
196 
197         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact}));
198         Object[] artifacts = new Object[] {a.artifact, c.artifact, d1.artifact, b2.artifact, e.artifact, g.artifact};
199         assertEquals(createSet(artifacts), res.getArtifacts(), "Check artifact list");
200         assertEquals(
201                 "Check version", "1.0", getArtifact("d", res.getArtifacts()).getVersion());
202         assertEquals(
203                 "Check version", "2.0", getArtifact("b", res.getArtifacts()).getVersion());
204     }
205 
206     @Test
207     public void testResolveNearestNewestIsNearest()
208             throws ArtifactResolutionException, InvalidVersionSpecificationException {
209         ArtifactSpec a = createArtifactSpec("a", "1.0");
210         ArtifactSpec b = a.addDependency("b", "1.0");
211         ArtifactSpec c = a.addDependency("c", "3.0");
212 
213         b.addDependency("c", "2.0");
214 
215         ArtifactResolutionResult res = collect(a);
216         assertEquals(
217                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
218                 res.getArtifacts(),
219                 "Check artifact list");
220         assertEquals("3.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
221     }
222 
223     @Test
224     public void testResolveNearestOldestIsNearest()
225             throws ArtifactResolutionException, InvalidVersionSpecificationException {
226         ArtifactSpec a = createArtifactSpec("a", "1.0");
227         ArtifactSpec b = a.addDependency("b", "1.0");
228         ArtifactSpec c = a.addDependency("c", "2.0");
229 
230         b.addDependency("c", "3.0");
231 
232         ArtifactResolutionResult res = collect(a);
233         assertEquals(
234                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
235                 res.getArtifacts(),
236                 "Check artifact list");
237         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
238     }
239 
240     @Test
241     public void testResolveLocalNewestIsLocal()
242             throws ArtifactResolutionException, InvalidVersionSpecificationException {
243         ArtifactSpec a = createArtifactSpec("a", "1.0");
244         a.addDependency("b", "2.0");
245         ArtifactSpec b = createArtifactSpec("b", "3.0");
246 
247         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
248         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
249         assertEquals("3.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
250     }
251 
252     @Test
253     public void testResolveLocalOldestIsLocal()
254             throws ArtifactResolutionException, InvalidVersionSpecificationException {
255         ArtifactSpec a = createArtifactSpec("a", "1.0");
256         a.addDependency("b", "3.0");
257         ArtifactSpec b = createArtifactSpec("b", "2.0");
258 
259         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
260         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
261         assertEquals("2.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
262     }
263 
264     @Test
265     public void testResolveLocalWithNewerVersionButLesserScope()
266             throws ArtifactResolutionException, InvalidVersionSpecificationException {
267         ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
268         a.addDependency("junit", "3.7");
269         ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
270 
271         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
272         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
273         assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
274         assertEquals(
275                 Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
276     }
277 
278     @Test
279     public void testResolveLocalWithNewerVersionButLesserScopeResolvedFirst()
280             throws ArtifactResolutionException, InvalidVersionSpecificationException {
281         ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
282         ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
283         a.addDependency("junit", "3.7");
284 
285         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
286         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
287         assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
288         assertEquals(
289                 Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
290     }
291 
292     @Test
293     public void testResolveNearestWithRanges()
294             throws ArtifactResolutionException, InvalidVersionSpecificationException {
295         ArtifactSpec a = createArtifactSpec("a", "1.0");
296         ArtifactSpec b = a.addDependency("b", "1.0");
297         ArtifactSpec c = a.addDependency("c", "2.0");
298 
299         b.addDependency("c", "[1.0,3.0]");
300 
301         ArtifactResolutionResult res = collect(a);
302         assertEquals(
303                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
304                 res.getArtifacts(),
305                 "Check artifact list");
306         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
307     }
308 
309     @Test
310     public void testResolveRangeWithManagedVersion()
311             throws ArtifactResolutionException, InvalidVersionSpecificationException {
312         ArtifactSpec a = createArtifactSpec("a", "1.0");
313         a.addDependency("b", "[1.0,3.0]");
314 
315         ArtifactSpec managedB = createArtifactSpec("b", "5.0");
316 
317         ArtifactResolutionResult res = collect(a, managedB.artifact);
318         assertEquals(
319                 createSet(new Object[] {a.artifact, managedB.artifact}), res.getArtifacts(), "Check artifact list");
320         assertEquals("5.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
321     }
322 
323     @Test
324     public void testCompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
325         ArtifactSpec a = createArtifactSpec("a", "1.0");
326         ArtifactSpec b = a.addDependency("b", "1.0");
327         a.addDependency("c", "[2.0,2.5]");
328         b.addDependency("c", "[1.0,3.0]");
329         ArtifactSpec c = createArtifactSpec("c", "2.5");
330 
331         ArtifactResolutionResult res = collect(a);
332 
333         assertEquals(
334                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
335                 res.getArtifacts(),
336                 "Check artifact list");
337         assertEquals("2.5", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
338     }
339 
340     @Test
341     public void testIncompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
342         ArtifactSpec a = createArtifactSpec("a", "1.0");
343         ArtifactSpec b = a.addDependency("b", "1.0");
344         a.addDependency("c", "[2.4,3.0]");
345 
346         b.addDependency("c", "[1.0,2.0]");
347 
348         ArtifactResolutionResult res = collect(a);
349 
350         assertTrue(res.hasVersionRangeViolations());
351     }
352 
353     @Test
354     public void testUnboundedRangeWhenVersionUnavailable()
355             throws ArtifactResolutionException, InvalidVersionSpecificationException {
356         ArtifactSpec a = createArtifactSpec("a", "1.0");
357         ArtifactSpec b = a.addDependency("b", "1.0");
358         a.addDependency("c", "[2.0,]");
359         b.addDependency("c", "[1.0,]");
360 
361         ArtifactResolutionResult res = collect(a);
362 
363         assertTrue(res.hasVersionRangeViolations());
364     }
365 
366     @Test
367     public void testUnboundedRangeBelowLastRelease()
368             throws ArtifactResolutionException, InvalidVersionSpecificationException {
369         ArtifactSpec a = createArtifactSpec("a", "1.0");
370         createArtifactSpec("c", "1.5");
371         ArtifactSpec c = createArtifactSpec("c", "2.0");
372         createArtifactSpec("c", "1.1");
373         a.addDependency("c", "[1.0,)");
374 
375         ArtifactResolutionResult res = collect(a);
376 
377         assertEquals(createSet(new Object[] {a.artifact, c.artifact}), res.getArtifacts(), "Check artifact list");
378         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
379     }
380 
381     @Test
382     public void testUnboundedRangeAboveLastRelease()
383             throws ArtifactResolutionException, InvalidVersionSpecificationException {
384         ArtifactSpec a = createArtifactSpec("a", "1.0");
385         createArtifactSpec("c", "2.0");
386         a.addDependency("c", "[10.0,)");
387 
388         ArtifactResolutionResult res = collect(a);
389 
390         assertTrue(res.hasVersionRangeViolations());
391     }
392 
393     @Test
394     public void testResolveManagedVersion() throws ArtifactResolutionException, InvalidVersionSpecificationException {
395         ArtifactSpec a = createArtifactSpec("a", "1.0");
396         a.addDependency("b", "3.0", Artifact.SCOPE_RUNTIME);
397 
398         Artifact managedVersion = createArtifactSpec("b", "5.0").artifact;
399         Artifact modifiedB = createArtifactSpec("b", "5.0", Artifact.SCOPE_RUNTIME).artifact;
400 
401         ArtifactResolutionResult res = collect(a, managedVersion);
402         assertEquals(createSet(new Object[] {a.artifact, modifiedB}), res.getArtifacts(), "Check artifact list");
403     }
404 
405     @Test
406     public void testCollectChangesVersionOfOriginatingArtifactIfInDependencyManagementHasDifferentVersion()
407             throws ArtifactResolutionException, InvalidVersionSpecificationException {
408         ArtifactSpec a = createArtifactSpec("a", "1.0");
409 
410         Artifact artifact = projectArtifact.artifact;
411         Artifact managedVersion = createArtifactSpec(artifact.getArtifactId(), "2.0").artifact;
412 
413         ArtifactResolutionResult result = collect(a, managedVersion);
414 
415         assertEquals("1.0", artifact.getVersion(), "collect has modified version in originating artifact");
416 
417         Artifact resolvedArtifact = result.getArtifacts().iterator().next();
418 
419         assertEquals("1.0", resolvedArtifact.getVersion(), "Resolved version don't match original artifact version");
420     }
421 
422     @Test
423     public void testResolveCompileScopeOverTestScope()
424             throws ArtifactResolutionException, InvalidVersionSpecificationException {
425         ArtifactSpec a = createArtifactSpec("a", "1.0");
426         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
427 
428         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
429 
430         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
431 
432         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
433         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
434         Artifact artifact = getArtifact("c", res.getArtifacts());
435         // local wins now, and irrelevant if not local as test/provided aren't transitive
436         // assertEquals( "Check artifactScope", Artifact.SCOPE_COMPILE, artifact.getArtifactScope() );
437         assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
438     }
439 
440     @Test
441     public void testResolveRuntimeScopeOverTestScope()
442             throws ArtifactResolutionException, InvalidVersionSpecificationException {
443         ArtifactSpec a = createArtifactSpec("a", "1.0");
444         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
445 
446         a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
447 
448         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
449 
450         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
451         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
452         Artifact artifact = getArtifact("c", res.getArtifacts());
453         // local wins now, and irrelevant if not local as test/provided aren't transitive
454         // assertEquals( "Check artifactScope", Artifact.SCOPE_RUNTIME, artifact.getArtifactScope() );
455         assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
456     }
457 
458     @Test
459     public void testResolveCompileScopeOverRuntimeScope()
460             throws ArtifactResolutionException, InvalidVersionSpecificationException {
461         ArtifactSpec root = createArtifactSpec("root", "1.0");
462         ArtifactSpec a = root.addDependency("a", "1.0");
463         root.addDependency("c", "3.0", Artifact.SCOPE_RUNTIME);
464 
465         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
466 
467         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
468 
469         ArtifactResolutionResult res = collect(createSet(new Object[] {root.artifact}));
470         assertEquals(
471                 createSet(new Object[] {a.artifact, root.artifact, modifiedC}),
472                 res.getArtifacts(),
473                 "Check artifact list");
474         Artifact artifact = getArtifact("c", res.getArtifacts());
475         assertEquals(Artifact.SCOPE_COMPILE, artifact.getScope(), "Check artifactScope");
476     }
477 
478     @Test
479     public void testResolveCompileScopeOverProvidedScope()
480             throws ArtifactResolutionException, InvalidVersionSpecificationException {
481         ArtifactSpec a = createArtifactSpec("a", "1.0");
482         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
483 
484         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
485 
486         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
487 
488         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
489         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
490         Artifact artifact = getArtifact("c", res.getArtifacts());
491         // local wins now, and irrelevant if not local as test/provided aren't transitive
492         // assertEquals( "Check artifactScope", Artifact.SCOPE_COMPILE, artifact.getArtifactScope() );
493         assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
494     }
495 
496     @Test
497     public void testResolveRuntimeScopeOverProvidedScope()
498             throws ArtifactResolutionException, InvalidVersionSpecificationException {
499         ArtifactSpec a = createArtifactSpec("a", "1.0");
500         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
501 
502         a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
503 
504         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
505 
506         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
507         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
508         Artifact artifact = getArtifact("c", res.getArtifacts());
509         // local wins now, and irrelevant if not local as test/provided aren't transitive
510         // assertEquals( "Check artifactScope", Artifact.SCOPE_RUNTIME, artifact.getArtifactScope() );
511         assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
512     }
513 
514     @Test
515     public void testProvidedScopeNotTransitive()
516             throws ArtifactResolutionException, InvalidVersionSpecificationException {
517         ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_PROVIDED);
518         ArtifactSpec b = createArtifactSpec("b", "1.0");
519         b.addDependency("c", "3.0", Artifact.SCOPE_PROVIDED);
520 
521         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
522         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
523     }
524 
525     @Test
526     public void testOptionalNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
527         ArtifactSpec a = createArtifactSpec("a", "1.0");
528         ArtifactSpec b = createArtifactSpec("b", "1.0");
529         b.addDependency("c", "3.0", true);
530 
531         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
532         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
533     }
534 
535     @Test
536     public void testOptionalIncludedAtRoot() throws ArtifactResolutionException, InvalidVersionSpecificationException {
537         ArtifactSpec a = createArtifactSpec("a", "1.0");
538 
539         ArtifactSpec b = createArtifactSpec("b", "1.0", true);
540 
541         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
542         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
543     }
544 
545     @Test
546     public void testScopeUpdate() throws InvalidVersionSpecificationException, ArtifactResolutionException {
547         /* farthest = compile */
548         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
549         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE);
550         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE);
551         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE);
552         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE);
553 
554         /* farthest = provided */
555         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
556         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
557         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
558         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
559         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
560 
561         /* farthest = runtime */
562         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
563         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME);
564         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
565         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
566         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME);
567 
568         /* farthest = system */
569         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
570         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
571         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
572         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
573         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
574 
575         /* farthest = test */
576         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
577         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
578         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
579         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
580         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
581     }
582 
583     private void checkScopeUpdate(String farthestScope, String nearestScope, String expectedScope)
584             throws ArtifactResolutionException, InvalidVersionSpecificationException {
585         checkScopeUpdateDirect(farthestScope, nearestScope, expectedScope);
586         checkScopeUpdateTransitively(farthestScope, nearestScope, expectedScope);
587     }
588 
589     private void checkScopeUpdateTransitively(String farthestScope, String nearestScope, String expectedScope)
590             throws ArtifactResolutionException, InvalidVersionSpecificationException {
591         ArtifactSpec a = createArtifactSpec("a", "1.0");
592         ArtifactSpec b = createArtifactSpec("b", "1.0", nearestScope);
593         ArtifactSpec c = createArtifactSpec("c", "1.0");
594         a.addDependency(c);
595         ArtifactSpec dNearest = createArtifactSpec("d", "2.0");
596         b.addDependency(dNearest);
597         ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
598         c.addDependency(dFarthest);
599 
600         /* system and provided dependencies are not transitive */
601         if (!Artifact.SCOPE_SYSTEM.equals(nearestScope) && !Artifact.SCOPE_PROVIDED.equals(nearestScope)) {
602             checkScopeUpdate(a, b, expectedScope, "2.0");
603         }
604     }
605 
606     private void checkScopeUpdateDirect(String farthestScope, String nearestScope, String expectedScope)
607             throws ArtifactResolutionException, InvalidVersionSpecificationException {
608         ArtifactSpec a = createArtifactSpec("a", "1.0");
609         ArtifactSpec b = createArtifactSpec("b", "1.0");
610         ArtifactSpec c = createArtifactSpec("c", "1.0");
611         a.addDependency(c);
612         ArtifactSpec dNearest = createArtifactSpec("d", "2.0", nearestScope);
613         b.addDependency(dNearest);
614         ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
615         c.addDependency(dFarthest);
616 
617         checkScopeUpdate(a, b, expectedScope, "2.0");
618     }
619 
620     private void checkScopeUpdate(ArtifactSpec a, ArtifactSpec b, String expectedScope, String expectedVersion)
621             throws ArtifactResolutionException, InvalidVersionSpecificationException {
622         ScopeArtifactFilter filter;
623         if (Artifact.SCOPE_PROVIDED.equals(expectedScope)) {
624             filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
625         } else if (Artifact.SCOPE_SYSTEM.equals(expectedScope)) {
626             filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
627         } else {
628             filter = new ScopeArtifactFilter(expectedScope);
629         }
630 
631         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}), filter);
632         Artifact artifact = getArtifact("d", res.getArtifacts());
633         assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
634         assertEquals(expectedScope, artifact.getScope(), "Check artifactScope");
635         assertEquals(expectedVersion, artifact.getVersion(), "Check version");
636 
637         ArtifactSpec d = createArtifactSpec("d", "1.0");
638         res = collect(createSet(new Object[] {a.artifact, b.artifact, d.artifact}), filter);
639         artifact = getArtifact("d", res.getArtifacts());
640         assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
641         assertEquals(d.artifact.getScope(), artifact.getScope(), "Check artifactScope");
642         assertEquals("1.0", artifact.getVersion(), "Check version");
643     }
644 
645     @Test
646     @Disabled
647     public void disabledtestOptionalNotTransitiveButVersionIsInfluential()
648             throws ArtifactResolutionException, InvalidVersionSpecificationException {
649         ArtifactSpec a = createArtifactSpec("a", "1.0");
650         ArtifactSpec b = createArtifactSpec("b", "1.0");
651         b.addDependency("c", "3.0", true);
652         ArtifactSpec d = a.addDependency("d", "1.0");
653         ArtifactSpec e = d.addDependency("e", "1.0");
654         e.addDependency("c", "2.0");
655 
656         ArtifactSpec c = createArtifactSpec("c", "3.0");
657 
658         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
659         assertEquals(
660                 createSet(new Object[] {a.artifact, b.artifact, c.artifact, d.artifact, e.artifact}),
661                 res.getArtifacts(),
662                 "Check artifact list");
663         Artifact artifact = getArtifact("c", res.getArtifacts());
664         assertEquals("3.0", artifact.getVersion(), "Check version");
665     }
666 
667     @Test
668     public void testTestScopeNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
669         ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_TEST);
670         ArtifactSpec b = createArtifactSpec("b", "1.0");
671         b.addDependency("c", "3.0", Artifact.SCOPE_TEST);
672 
673         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
674         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
675     }
676 
677     @Test
678     public void testSnapshotNotIncluded() throws ArtifactResolutionException, InvalidVersionSpecificationException {
679         ArtifactSpec a = createArtifactSpec("a", "1.0");
680         a.addDependency("b", "[1.0,)");
681         createArtifactSpec("b", "1.0-SNAPSHOT");
682 
683         ArtifactResolutionResult res = collect(a);
684 
685         assertTrue(res.hasVersionRangeViolations());
686 
687         /*
688          * try { ArtifactResolutionResult res = collect( a ); fail( "Expected b not to resolve: " + res ); } catch (
689          * OverConstrainedVersionException e ) { assertTrue( e.getMessage().indexOf( "[1.0-SNAPSHOT]" ) <
690          * e.getMessage().indexOf( "[1.0,)" ) ); }
691          */
692     }
693 
694     @Test
695     public void testOverConstrainedVersionException()
696             throws ArtifactResolutionException, InvalidVersionSpecificationException {
697         ArtifactSpec a = createArtifactSpec("a", "1.0");
698         a.addDependency("b", "[1.0, 2.0)");
699         a.addDependency("c", "[3.3.0,4.0.0)");
700 
701         ArtifactSpec b = createArtifactSpec("b", "1.0.0");
702         b.addDependency("c", "3.3.0-v3346");
703 
704         // ArtifactSpec c = createArtifactSpec("c", "3.2.1-v3235e");
705 
706         try {
707             collect(createSet(new Object[] {a.artifact}));
708         } catch (OverConstrainedVersionException e) {
709             assertTrue(e.getMessage().contains("[3.2.1-v3235e, 3.3.0-v3346]"), "Versions unordered");
710             assertTrue(e.getMessage().contains("Path to dependency:"), "DependencyTrail unresolved");
711         }
712     }
713 
714     private Artifact getArtifact(String id, Set artifacts) {
715         for (Object artifact : artifacts) {
716             Artifact a = (Artifact) artifact;
717             if (a.getArtifactId().equals(id) && a.getGroupId().equals(GROUP_ID)) {
718                 return a;
719             }
720         }
721         return null;
722     }
723 
724     private ArtifactResolutionResult collect(Set<Artifact> artifacts) throws ArtifactResolutionException {
725         return collect(artifacts, null);
726     }
727 
728     private ArtifactResolutionResult collect(Set<Artifact> artifacts, ArtifactFilter filter)
729             throws ArtifactResolutionException {
730         return artifactCollector.collect(
731                 artifacts,
732                 projectArtifact.artifact,
733                 null,
734                 null,
735                 null,
736                 source,
737                 filter,
738                 Collections.<ResolutionListener>emptyList(),
739                 null);
740     }
741 
742     private ArtifactResolutionResult collect(ArtifactSpec a) throws ArtifactResolutionException {
743         return artifactCollector.collect(
744                 Collections.singleton(a.artifact),
745                 projectArtifact.artifact,
746                 null,
747                 null,
748                 null,
749                 source,
750                 null,
751                 Collections.<ResolutionListener>emptyList(),
752                 null);
753     }
754 
755     private ArtifactResolutionResult collect(ArtifactSpec a, ArtifactFilter filter) throws ArtifactResolutionException {
756         return artifactCollector.collect(
757                 Collections.singleton(a.artifact),
758                 projectArtifact.artifact,
759                 null,
760                 null,
761                 null,
762                 source,
763                 filter,
764                 Collections.<ResolutionListener>emptyList(),
765                 null);
766     }
767 
768     private ArtifactResolutionResult collect(ArtifactSpec a, Artifact managedVersion)
769             throws ArtifactResolutionException {
770         Map managedVersions = Collections.singletonMap(managedVersion.getDependencyConflictId(), managedVersion);
771         return artifactCollector.collect(
772                 Collections.singleton(a.artifact),
773                 projectArtifact.artifact,
774                 managedVersions,
775                 null,
776                 null,
777                 source,
778                 null,
779                 Collections.<ResolutionListener>emptyList(),
780                 null);
781     }
782 
783     private ArtifactSpec createArtifactSpec(String id, String version) throws InvalidVersionSpecificationException {
784         return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE);
785     }
786 
787     private ArtifactSpec createArtifactSpec(String id, String version, boolean optional)
788             throws InvalidVersionSpecificationException {
789         return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE, null, optional);
790     }
791 
792     private ArtifactSpec createArtifactSpec(String id, String version, String scope)
793             throws InvalidVersionSpecificationException {
794         return createArtifactSpec(id, version, scope, null, false);
795     }
796 
797     private ArtifactSpec createArtifactSpec(
798             String id, String version, String scope, String inheritedScope, boolean optional)
799             throws InvalidVersionSpecificationException {
800         VersionRange versionRange = VersionRange.createFromVersionSpec(version);
801         Artifact artifact = artifactFactory.createDependencyArtifact(
802                 GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope, optional);
803         ArtifactSpec spec = null;
804         if (artifact != null) {
805             spec = new ArtifactSpec();
806             spec.artifact = artifact;
807             source.addArtifact(spec);
808         }
809         return spec;
810     }
811 
812     @SuppressWarnings("unchecked")
813     private static Set<Artifact> createSet(Object[] x) {
814         return new LinkedHashSet(Arrays.asList(x));
815     }
816 
817     private class ArtifactSpec {
818         private Artifact artifact;
819 
820         private Set<Artifact> dependencies = new HashSet<>();
821 
822         public ArtifactSpec addDependency(String id, String version) throws InvalidVersionSpecificationException {
823             return addDependency(id, version, Artifact.SCOPE_COMPILE);
824         }
825 
826         public ArtifactSpec addDependency(String id, String version, String scope)
827                 throws InvalidVersionSpecificationException {
828             return addDependency(id, version, scope, false);
829         }
830 
831         private ArtifactSpec addDependency(ArtifactSpec dep) throws InvalidVersionSpecificationException {
832             if (dep != null) {
833                 dependencies.add(dep.artifact);
834             }
835             return dep;
836         }
837 
838         private ArtifactSpec addDependency(String id, String version, String scope, boolean optional)
839                 throws InvalidVersionSpecificationException {
840             ArtifactSpec dep = createArtifactSpec(id, version, scope, artifact.getScope(), optional);
841             return addDependency(dep);
842         }
843 
844         public ArtifactSpec addDependency(String id, String version, boolean optional)
845                 throws InvalidVersionSpecificationException {
846             return addDependency(id, version, Artifact.SCOPE_COMPILE, optional);
847         }
848     }
849 
850     private class Source implements ArtifactMetadataSource {
851         private Map<String, ArtifactSpec> artifacts = new HashMap<>();
852 
853         private Map<String, List<ArtifactVersion>> versions = new HashMap<>();
854 
855         public ResolutionGroup retrieve(
856                 Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
857                 throws ArtifactMetadataRetrievalException {
858             String key = getKey(artifact);
859 
860             ArtifactSpec a = (ArtifactSpec) artifacts.get(key);
861             try {
862                 return new ResolutionGroup(
863                         artifact,
864                         createArtifacts(
865                                 artifactFactory, a.dependencies, artifact.getScope(), artifact.getDependencyFilter()),
866                         Collections.EMPTY_LIST);
867             } catch (InvalidVersionSpecificationException e) {
868                 throw new ArtifactMetadataRetrievalException("Invalid version creating artifacts", e, artifact);
869             }
870         }
871 
872         private String getKey(Artifact artifact) {
873             return artifact.getDependencyConflictId();
874         }
875 
876         private Set<Artifact> createArtifacts(
877                 ArtifactFactory artifactFactory,
878                 Set<Artifact> dependencies,
879                 String inheritedScope,
880                 ArtifactFilter dependencyFilter)
881                 throws InvalidVersionSpecificationException {
882             Set<Artifact> projectArtifacts = new HashSet<>();
883 
884             for (Artifact d : dependencies) {
885                 VersionRange versionRange;
886                 if (d.getVersionRange() != null) {
887                     versionRange = d.getVersionRange();
888                 } else {
889                     versionRange = VersionRange.createFromVersionSpec(d.getVersion());
890                 }
891                 Artifact artifact;
892                 if (d.getScope().equals(Artifact.SCOPE_TEST) || d.getScope().equals(Artifact.SCOPE_PROVIDED)) {
893                     /* don't call createDependencyArtifact as it'll ignore test and provided scopes */
894                     artifact = artifactFactory.createArtifact(
895                             d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(), d.getType());
896                 } else {
897                     artifact = artifactFactory.createDependencyArtifact(
898                             d.getGroupId(),
899                             d.getArtifactId(),
900                             versionRange,
901                             d.getType(),
902                             d.getClassifier(),
903                             d.getScope(),
904                             inheritedScope,
905                             d.isOptional());
906                 }
907 
908                 if (artifact != null && (dependencyFilter == null || dependencyFilter.include(artifact))) {
909                     artifact.setDependencyFilter(dependencyFilter);
910 
911                     projectArtifacts.add(artifact);
912                 }
913             }
914 
915             return projectArtifacts;
916         }
917 
918         public void addArtifact(ArtifactSpec spec) {
919             artifacts.put(getKey(spec.artifact), spec);
920 
921             String key = spec.artifact.getDependencyConflictId();
922             List<ArtifactVersion> artifactVersions = versions.get(key);
923             if (artifactVersions == null) {
924                 artifactVersions = new ArrayList<>();
925                 versions.put(key, artifactVersions);
926             }
927             if (spec.artifact.getVersion() != null) {
928                 artifactVersions.add(new DefaultArtifactVersion(spec.artifact.getVersion()));
929             }
930         }
931 
932         public List<ArtifactVersion> retrieveAvailableVersions(
933                 Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
934                 throws ArtifactMetadataRetrievalException {
935             return retrieveAvailableVersions(artifact);
936         }
937 
938         public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
939                 Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
940                 throws ArtifactMetadataRetrievalException {
941             return retrieveAvailableVersions(artifact);
942         }
943 
944         private List<ArtifactVersion> retrieveAvailableVersions(Artifact artifact) {
945             List<ArtifactVersion> artifactVersions = versions.get(artifact.getDependencyConflictId());
946             if (artifactVersions == null) {
947                 artifactVersions = Collections.emptyList();
948             }
949             return artifactVersions;
950         }
951 
952         public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
953             return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
954         }
955 
956         public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
957                 throws ArtifactMetadataRetrievalException {
958             return retrieveAvailableVersions(
959                     request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
960         }
961     }
962 }