1   package org.apache.maven.artifact.resolver;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.HashSet;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.maven.artifact.AbstractArtifactComponentTestCase;
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.manager.WagonManager;
33  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
34  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
35  import org.apache.maven.artifact.metadata.ResolutionGroup;
36  import org.apache.maven.artifact.repository.ArtifactRepository;
37  import org.apache.maven.wagon.TransferFailedException;
38  import org.easymock.MockControl;
39  
40  // It would be cool if there was a hook that i could use to setup a test environment.
41  // I want to setup a local/remote repositories for testing but i don't want to have
42  // to change them when i change the layout of the repositories. So i want to generate
43  // the structure i want to test by using the artifact handler manager which dictates
44  // the layout used for a particular artifact type.
45  
46  /**
47   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
48   * @version $Id: ArtifactResolverTest.java 788791 2009-06-26 17:55:26Z jdcasey $
49   */
50  public class ArtifactResolverTest
51      extends AbstractArtifactComponentTestCase
52  {
53      private static class ArtifactMetadataSourceImplementation
54          implements ArtifactMetadataSource
55      {
56          public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
57                                           List remoteRepositories )
58              throws ArtifactMetadataRetrievalException
59          {
60              return new ResolutionGroup( artifact, Collections.EMPTY_SET, remoteRepositories );
61          }
62  
63          public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
64                                                 List remoteRepositories )
65          {
66              throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
67          }
68  
69          public Artifact retrieveRelocatedArtifact( Artifact artifact,
70                                                     ArtifactRepository localRepository,
71                                                     List remoteRepositories )
72              throws ArtifactMetadataRetrievalException
73          {
74              return artifact;
75          }
76      }
77  
78      private ArtifactResolver artifactResolver;
79  
80      private Artifact projectArtifact;
81  
82      protected void setUp()
83          throws Exception
84      {
85          super.setUp();
86  
87          artifactResolver = (ArtifactResolver) lookup( ArtifactResolver.ROLE );
88  
89          projectArtifact = createLocalArtifact( "project", "3.0", null );
90      }
91  
92      protected String component()
93      {
94          return "resolver";
95      }
96  
97      public void testResolutionOfASingleArtifactWhereTheArtifactIsPresentInTheLocalRepository()
98          throws Exception
99      {
100         Artifact a = createLocalArtifact( "a", "1.0", null );
101 
102         artifactResolver.resolve( a, remoteRepositories(), localRepository() );
103 
104         assertLocalArtifactPresent( a );
105     }
106 
107     public void testResolutionOfASingleArtifactWhereTheArtifactIsNotPresentLocallyAndMustBeRetrievedFromTheRemoteRepository()
108         throws Exception
109     {
110         Artifact b = createRemoteArtifact( "b", "1.0" );
111         deleteLocalArtifact( b );
112 
113         artifactResolver.resolve( b, remoteRepositories(), localRepository() );
114 
115         assertLocalArtifactPresent( b );
116     }
117 
118     protected Artifact createArtifact( String groupId, String artifactId, String version, String type )
119         throws Exception
120     {
121         // for the anonymous classes
122         return super.createArtifact( groupId, artifactId, version, type );
123     }
124 
125     public void testTransitiveResolutionWhereAllArtifactsArePresentInTheLocalRepository()
126         throws Exception
127     {
128         Artifact g = createLocalArtifact( "g", "1.0", null );
129 
130         Artifact h = createLocalArtifact( "h", "1.0", null );
131 
132         ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation()
133         {
134             public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
135                                              List remoteRepositories )
136                 throws ArtifactMetadataRetrievalException
137             {
138                 Set dependencies = new LinkedHashSet();
139 
140                 if ( "g".equals( artifact.getArtifactId() ) )
141                 {
142                     Artifact a = null;
143                     try
144                     {
145                         a = createArtifact( "org.apache.maven", "h", "1.0", "jar" );
146                         dependencies.add( a );
147                     }
148                     catch ( Exception e )
149                     {
150                         throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
151                     }
152                 }
153 
154                 return new ResolutionGroup( artifact, dependencies, remoteRepositories );
155             }
156         };
157 
158         ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( g ),
159                                                                                 projectArtifact, remoteRepositories(),
160                                                                                 localRepository(), mds );
161 
162         assertEquals( 2, result.getArtifacts().size() );
163 
164         assertTrue( result.getArtifacts().contains( g ) );
165 
166         assertTrue( result.getArtifacts().contains( h ) );
167 
168         assertLocalArtifactPresent( g );
169 
170         assertLocalArtifactPresent( h );
171     }
172 
173     public void testTransitiveResolutionWhereAllArtifactsAreNotPresentInTheLocalRepositoryAndMustBeRetrievedFromTheRemoteRepository()
174         throws Exception
175     {
176         Artifact i = createRemoteArtifact( "i", "1.0" );
177         deleteLocalArtifact( i );
178 
179         Artifact j = createRemoteArtifact( "j", "1.0" );
180         deleteLocalArtifact( j );
181 
182         ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation()
183         {
184             public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
185                                              List remoteRepositories )
186                 throws ArtifactMetadataRetrievalException
187             {
188                 Set dependencies = new LinkedHashSet();
189 
190                 if ( "i".equals( artifact.getArtifactId() ) )
191                 {
192                     Artifact a = null;
193                     try
194                     {
195                         a = createArtifact( "org.apache.maven", "j", "1.0", "jar" );
196                         dependencies.add( a );
197                     }
198                     catch ( Exception e )
199                     {
200                         throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
201                     }
202                 }
203 
204                 return new ResolutionGroup( artifact, dependencies, remoteRepositories );
205             }
206         };
207 
208         ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( i ),
209                                                                                 projectArtifact, remoteRepositories(),
210                                                                                 localRepository(), mds );
211 
212         assertEquals( 2, result.getArtifacts().size() );
213 
214         assertTrue( result.getArtifacts().contains( i ) );
215 
216         assertTrue( result.getArtifacts().contains( j ) );
217 
218         assertLocalArtifactPresent( i );
219 
220         assertLocalArtifactPresent( j );
221     }
222 
223     public void testResolutionFailureWhenArtifactNotPresentInRemoteRepository()
224         throws Exception
225     {
226         Artifact k = createArtifact( "k", "1.0" );
227 
228         try
229         {
230             artifactResolver.resolve( k, remoteRepositories(), localRepository() );
231             fail( "Resolution succeeded when it should have failed" );
232         }
233         catch ( ArtifactNotFoundException expected )
234         {
235             List repos = expected.getRemoteRepositories();
236             assertEquals( 1, repos.size() );
237             assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() );
238         }
239     }
240 
241     public void testResolutionFailureWhenArtifactNotPresentInRemoteRepositoryWithMirrors()
242         throws Exception
243     {
244         ArtifactRepository repository = remoteRepository();
245 
246         WagonManager wagonManager = (WagonManager) lookup( WagonManager.ROLE );
247         wagonManager.addMirror( "mirror", "test", repository.getUrl() );
248 
249         Artifact k = createArtifact( "k", "1.0" );
250 
251         try
252         {
253             artifactResolver.resolve( k, Collections.singletonList( repository ), localRepository() );
254             fail( "Resolution succeeded when it should have failed" );
255         }
256         catch ( ArtifactNotFoundException expected )
257         {
258             List repos = expected.getRemoteRepositories();
259             assertEquals( 1, repos.size() );
260             assertEquals( "mirror", ( (ArtifactRepository) repos.get( 0 ) ).getId() );
261         }
262     }
263 
264     public void testResolutionOfAnArtifactWhereOneRemoteRepositoryIsBadButOneIsGood()
265         throws Exception
266     {
267         Artifact l = createRemoteArtifact( "l", "1.0" );
268         deleteLocalArtifact( l );
269 
270         List repositories = new ArrayList();
271         repositories.add( remoteRepository() );
272         repositories.add( badRemoteRepository() );
273 
274         artifactResolver.resolve( l, repositories, localRepository() );
275 
276         assertLocalArtifactPresent( l );
277     }
278 
279     /*
280      public void testResolutionOfASingleArtifactWhereTheArtifactIsNotPresentLocallyAndMustBeRetrievedFromTheRemoteRepositoryAndLocalCannotBeCreated()
281      throws Exception
282      {
283      Artifact m = createRemoteArtifact( "m", "1.0" );
284 
285      artifactResolver.resolve( m, remoteRepositories(), badLocalRepository() );
286 
287      // TODO [failing test case]: throw and handle a more informative exception
288      }
289      */
290 
291     public void testResolutionFailureWhenMultipleArtifactsNotPresentInRemoteRepository()
292         throws Exception
293     {
294         Artifact i = createArtifact( "i", "1.0" );
295         Artifact n = createArtifact( "n", "1.0" );
296         Artifact o = createArtifact( "o", "1.0" );
297     
298         try
299         {
300             ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation();
301             artifactResolver.resolveTransitively( new HashSet( Arrays.asList( new Artifact[] { i, n, o } ) ),
302                                                   projectArtifact, remoteRepositories(), localRepository(), mds );
303             fail( "Resolution succeeded when it should have failed" );
304         }
305         catch ( MultipleArtifactsNotFoundException expected )
306         {
307             List repos = expected.getRemoteRepositories();
308             assertEquals( 1, repos.size() );
309             assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() );
310             
311             List missingArtifacts = expected.getMissingArtifacts();
312             assertEquals( 2, missingArtifacts.size() );
313             assertTrue( missingArtifacts.contains( n ) );
314             assertTrue( missingArtifacts.contains( o ) );
315             assertFalse( missingArtifacts.contains( i ) );
316         }
317     }
318 
319     /**
320      * Test deadlocking (which occurs even with a single artifact in error).
321      */
322     public void testResolveWithException()
323         throws Exception
324     {
325         ArtifactRepository repository = remoteRepository();
326         List remoteRepositories = Collections.singletonList( repository );
327 
328         Artifact a1 = createArtifact( "testGroup", "artifactId", "1.0", "jar" );
329 
330         ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation();
331 
332         DefaultArtifactResolver artifactResolver = (DefaultArtifactResolver) this.artifactResolver;
333 
334         MockControl control = MockControl.createControl( WagonManager.class );
335         WagonManager wagonManager = (WagonManager) control.getMock();
336         artifactResolver.setWagonManager( wagonManager );
337 
338         wagonManager.isOnline();
339         control.setReturnValue( true );
340         wagonManager.getArtifact( a1, remoteRepositories );
341         control.setThrowable( new TransferFailedException( "message" ) );
342         wagonManager.getMirrorRepository( repository );
343         control.setReturnValue( repository );
344 
345         control.replay();
346 
347         try
348         {
349             artifactResolver.resolveTransitively( new LinkedHashSet( Arrays.asList( new Artifact[] { a1 } ) ),
350                                                   projectArtifact, remoteRepositories, localRepository(), mds );
351             fail( "Resolution succeeded when it should have failed" );
352         }
353         catch ( ArtifactResolutionException expected )
354         {
355             List repos = expected.getRemoteRepositories();
356             assertEquals( 1, repos.size() );
357             assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() );
358 
359             assertEquals( "testGroup", expected.getGroupId() );
360         }
361 
362         control.verify();
363     }
364 
365     /**
366      * Test deadlocking in case a transfer error occurs within a group of multiple artifacts (MNG-4179).
367      */
368     public void testResolveMultipleWithException()
369         throws Exception
370     {
371         ArtifactRepository repository = remoteRepository();
372         List remoteRepositories = Collections.singletonList( repository );
373 
374         Artifact a1 = createArtifact( "testGroup", "artifactId", "1.0", "jar" );
375 
376         Artifact a2 = createArtifact( "testGroup", "anotherId", "1.0", "jar" );
377 
378         ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation();
379 
380         DefaultArtifactResolver artifactResolver = (DefaultArtifactResolver) this.artifactResolver;
381 
382         MockControl control = MockControl.createControl( WagonManager.class );
383         WagonManager wagonManager = (WagonManager) control.getMock();
384         artifactResolver.setWagonManager( wagonManager );
385 
386         wagonManager.isOnline();
387         control.setReturnValue( true );
388         wagonManager.getArtifact( a1, remoteRepositories );
389         control.setThrowable( new TransferFailedException( "message" ) );
390         wagonManager.getMirrorRepository( repository );
391         control.setReturnValue( repository );
392 
393         wagonManager.isOnline();
394         control.setReturnValue( true );
395         wagonManager.getArtifact( a2, remoteRepositories );
396         control.setThrowable( new TransferFailedException( "message" ) );
397         wagonManager.getMirrorRepository( repository );
398         control.setReturnValue( repository );
399 
400         control.replay();
401 
402         try
403         {
404             artifactResolver.resolveTransitively( new LinkedHashSet( Arrays.asList( new Artifact[] { a1, a2 } ) ),
405                                                   projectArtifact, remoteRepositories, localRepository(), mds );
406             fail( "Resolution succeeded when it should have failed" );
407         }
408         catch ( ArtifactResolutionException expected )
409         {
410             List repos = expected.getRemoteRepositories();
411             assertEquals( 1, repos.size() );
412             assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() );
413 
414             assertEquals( "testGroup", expected.getGroupId() );
415         }
416 
417         control.verify();
418     }
419     
420     public void testResolveOlderSpecificSnapshotVersionWhenNewerVersionAlreadyExistsAndBothAreInLocalRepository()
421         throws Exception
422     {
423         Artifact g1 = createLocalArtifact( "g", "1.0-20090608.090416-1", "Write something to make file length longer" );
424         
425         long expectedFileLength = g1.getFile().length();
426         
427         Artifact g3 = createLocalArtifact( "g", "1.0-SNAPSHOT", null );
428         
429         long incorrectFileLength = g3.getFile().length();
430         
431         ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation()
432         {
433             public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
434                                              List remoteRepositories )
435                 throws ArtifactMetadataRetrievalException
436             {
437                 Set dependencies = new LinkedHashSet();
438 
439                 return new ResolutionGroup( artifact, dependencies, remoteRepositories );
440             }
441         };
442 
443         ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( g1 ),
444                                                                                 projectArtifact, remoteRepositories(),
445                                                                                 localRepository(), mds );
446 
447         assertEquals( 1, result.getArtifacts().size() );
448         
449         assertTrue( result.getArtifacts().contains( g1 ) );
450 
451         assertFalse( result.getArtifacts().contains( g3 ) );
452 
453         Artifact artifact = ( (Artifact) result.getArtifacts().iterator().next() );
454         
455         assertEquals( expectedFileLength, artifact.getFile().length() );
456         
457         assertFalse( "Incorrect artifact file resolved", incorrectFileLength == artifact.getFile().length() );
458                 
459         assertLocalArtifactPresent( g1 );
460         
461         assertLocalArtifactPresent( g3 );
462     }
463 
464 }
465