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