Author: brett Date: Wed Mar 4 12:46:53 2009 New Revision: 749987 URL: http://svn.apache.org/viewvc?rev=749987&view=rev Log: [MNG-3379] avoid deadlocking on remote errors, check test coverage for the new code including exceptional cases
Modified: maven/components/branches/maven-2.1.x/maven-artifact-manager/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java maven/components/branches/maven-2.1.x/maven-artifact-manager/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java Modified: maven/components/branches/maven-2.1.x/maven-artifact-manager/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.1.x/maven-artifact-manager/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java?rev=749987&r1=749986&r2=749987&view=diff ============================================================================== --- maven/components/branches/maven-2.1.x/maven-artifact-manager/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java (original) +++ maven/components/branches/maven-2.1.x/maven-artifact-manager/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java Wed Mar 4 12:46:53 2009 @@ -333,6 +333,7 @@ nodes.add( node ); } + List resolutionExceptions = new ArrayList(); try { for ( Iterator i = nodesByGroupId.values().iterator(); i.hasNext(); ) @@ -340,7 +341,7 @@ List nodes = (List) i.next(); resolveArtifactPool.execute( new ResolveArtifactTask( resolveArtifactPool, latch, nodes, localRepository, resolvedArtifacts, - missingArtifacts ) ); + missingArtifacts, resolutionExceptions ) ); } latch.await(); } @@ -348,18 +349,12 @@ { throw new ArtifactResolutionException( "Resolution interrupted", null, e ); } - catch ( RuntimeException ex ) - { - if ( ex.getCause() instanceof ArtifactResolutionException ) - { - throw (ArtifactResolutionException) ex.getCause(); - } - else - { - throw ex; - } - } + if ( !resolutionExceptions.isEmpty() ) + { + throw (ArtifactResolutionException) resolutionExceptions.get( 0 ); + } + if ( missingArtifacts.size() > 0 ) { throw new MultipleArtifactsNotFoundException( originatingArtifact, resolvedArtifacts, missingArtifacts, @@ -413,8 +408,11 @@ private ThreadPoolExecutor pool; + private List resolutionExceptions; + public ResolveArtifactTask( ThreadPoolExecutor pool, CountDownLatch latch, List nodes, - ArtifactRepository localRepository, List resolvedArtifacts, List missingArtifacts ) + ArtifactRepository localRepository, List resolvedArtifacts, List missingArtifacts, + List resolutionExceptions ) { this.nodes = nodes; this.localRepository = localRepository; @@ -422,6 +420,7 @@ this.missingArtifacts = missingArtifacts; this.latch = latch; this.pool = pool; + this.resolutionExceptions = resolutionExceptions; } public void run() @@ -435,14 +434,17 @@ if ( i.hasNext() ) { pool.execute( new ResolveArtifactTask( pool, latch, nodes, localRepository, resolvedArtifacts, - missingArtifacts ) ); + missingArtifacts, resolutionExceptions ) ); } } catch ( ArtifactResolutionException e ) { - throw new RuntimeException( e ); + resolutionExceptions.add( e ); + } + finally + { + latch.countDown(); } - latch.countDown(); } private void resolveArtifact( ResolutionNode node ) @@ -467,4 +469,9 @@ resolveArtifactPool.setCorePoolSize( threads ); resolveArtifactPool.setMaximumPoolSize( threads ); } + + void setWagonManager( WagonManager wagonManager ) + { + this.wagonManager = wagonManager; + } } Modified: maven/components/branches/maven-2.1.x/maven-artifact-manager/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.1.x/maven-artifact-manager/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java?rev=749987&r1=749986&r2=749987&view=diff ============================================================================== --- maven/components/branches/maven-2.1.x/maven-artifact-manager/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java (original) +++ maven/components/branches/maven-2.1.x/maven-artifact-manager/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java Wed Mar 4 12:46:53 2009 @@ -19,6 +19,14 @@ * under the License. */ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + import org.apache.maven.artifact.AbstractArtifactComponentTestCase; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.manager.WagonManager; @@ -26,12 +34,8 @@ import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.metadata.ResolutionGroup; import org.apache.maven.artifact.repository.ArtifactRepository; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import org.apache.maven.wagon.TransferFailedException; +import org.easymock.MockControl; // It would be cool if there was a hook that i could use to setup a test environment. // I want to setup a local/remote repositories for testing but i don't want to have @@ -46,6 +50,31 @@ public class ArtifactResolverTest extends AbstractArtifactComponentTestCase { + private static class ArtifactMetadataSourceImplementation + implements ArtifactMetadataSource + { + public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, + List remoteRepositories ) + throws ArtifactMetadataRetrievalException + { + return new ResolutionGroup( artifact, Collections.EMPTY_SET, remoteRepositories ); + } + + public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository, + List remoteRepositories ) + { + throw new UnsupportedOperationException( "Cannot get available versions in this test case" ); + } + + public Artifact retrieveRelocatedArtifact( Artifact artifact, + ArtifactRepository localRepository, + List remoteRepositories ) + throws ArtifactMetadataRetrievalException + { + return artifact; + } + } + private ArtifactResolver artifactResolver; private Artifact projectArtifact; @@ -100,7 +129,7 @@ Artifact h = createLocalArtifact( "h", "1.0" ); - ArtifactMetadataSource mds = new ArtifactMetadataSource() + ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation() { public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories ) @@ -124,20 +153,6 @@ return new ResolutionGroup( artifact, dependencies, remoteRepositories ); } - - public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository, - List remoteRepositories ) - { - throw new UnsupportedOperationException( "Cannot get available versions in this test case" ); - } - - public Artifact retrieveRelocatedArtifact( Artifact artifact, - ArtifactRepository localRepository, - List remoteRepositories ) - throws ArtifactMetadataRetrievalException - { - return artifact; - } }; ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( g ), @@ -164,7 +179,7 @@ Artifact j = createRemoteArtifact( "j", "1.0" ); deleteLocalArtifact( j ); - ArtifactMetadataSource mds = new ArtifactMetadataSource() + ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation() { public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories ) @@ -188,20 +203,6 @@ return new ResolutionGroup( artifact, dependencies, remoteRepositories ); } - - public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository, - List remoteRepositories ) - { - throw new UnsupportedOperationException( "Cannot get available versions in this test case" ); - } - - public Artifact retrieveRelocatedArtifact( Artifact artifact, - ArtifactRepository localRepository, - List remoteRepositories ) - throws ArtifactMetadataRetrievalException - { - return artifact; - } }; ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( i ), @@ -287,5 +288,78 @@ } */ + public void testResolutionFailureWhenMultipleArtifactsNotPresentInRemoteRepository() + throws Exception + { + Artifact i = createArtifact( "i", "1.0" ); + Artifact n = createArtifact( "n", "1.0" ); + Artifact o = createArtifact( "o", "1.0" ); + + try + { + ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation(); + artifactResolver.resolveTransitively( new HashSet( Arrays.asList( new Artifact[] { i, n, o } ) ), + projectArtifact, remoteRepositories(), localRepository(), mds ); + fail( "Resolution succeeded when it should have failed" ); + } + catch ( MultipleArtifactsNotFoundException expected ) + { + List repos = expected.getRemoteRepositories(); + assertEquals( 1, repos.size() ); + assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() ); + + List missingArtifacts = expected.getMissingArtifacts(); + assertEquals( 2, missingArtifacts.size() ); + assertTrue( missingArtifacts.contains( n ) ); + assertTrue( missingArtifacts.contains( o ) ); + assertFalse( missingArtifacts.contains( i ) ); + } + } + + /** + * Test deadlocking (which occurs even with a single artifact in error). + */ + public void testResolveWithException() + throws Exception + { + ArtifactRepository repository = remoteRepository(); + List remoteRepositories = Collections.singletonList( repository ); + + Artifact a1 = createArtifact( "testGroup", "artifactId", "1.0", "jar" ); + + ArtifactMetadataSource mds = new ArtifactMetadataSourceImplementation(); + + DefaultArtifactResolver artifactResolver = (DefaultArtifactResolver) this.artifactResolver; + + MockControl control = MockControl.createControl( WagonManager.class ); + WagonManager wagonManager = (WagonManager) control.getMock(); + artifactResolver.setWagonManager( wagonManager ); + + wagonManager.isOnline(); + control.setReturnValue( true ); + wagonManager.getArtifact( a1, remoteRepositories ); + control.setThrowable( new TransferFailedException( "message" ) ); + wagonManager.getMirrorRepository( repository ); + control.setReturnValue( repository ); + + control.replay(); + + try + { + artifactResolver.resolveTransitively( new LinkedHashSet( Arrays.asList( new Artifact[] { a1 } ) ), + projectArtifact, remoteRepositories, localRepository(), mds ); + fail( "Resolution succeeded when it should have failed" ); + } + catch ( ArtifactResolutionException expected ) + { + List repos = expected.getRemoteRepositories(); + assertEquals( 1, repos.size() ); + assertEquals( "test", ( (ArtifactRepository) repos.get( 0 ) ).getId() ); + + assertEquals( "testGroup", expected.getGroupId() ); + } + + control.verify(); + } }