]> source.dussan.org Git - archiva.git/commitdiff
[MRM-138] add more proxy tests
authorBrett Porter <brett@apache.org>
Sun, 13 Aug 2006 02:22:06 +0000 (02:22 +0000)
committerBrett Porter <brett@apache.org>
Sun, 13 Aug 2006 02:22:06 +0000 (02:22 +0000)
git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@431135 13f79535-47bb-0310-9956-ffa450edef68

maven-repository-configuration/src/test/java/org/apache/maven/repository/configuration/ConfigurationStoreTest.java
maven-repository-proxy/pom.xml
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyRequestHandler.java
maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.java
maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/WagonDelegate.java [new file with mode: 0644]
maven-repository-proxy/src/test/repositories/proxied1/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar [new file with mode: 0644]
maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar [new file with mode: 0644]
maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar [new file with mode: 0644]
maven-repository-proxy/src/test/resources/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.xml [new file with mode: 0644]

index 0ab2497580056cd9175c18740332158ed922d010..34d350a686ad50cd68c0ebe9bed1802da76dc5a4 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Properties;
  * Test the configuration store.
  *
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @noinspection JavaDoc
  */
 public class ConfigurationStoreTest
     extends PlexusTestCase
@@ -130,6 +131,9 @@ public class ConfigurationStoreTest
         assertEquals( "check value", "index-path", configuration.getIndexPath() );
     }
 
+    /**
+     * @noinspection JUnitTestMethodWithNoAssertions
+     */
     public void testChangeListeners()
         throws Exception
     {
index 5c0cd45152b2c59617134aa5bf72194c1ea2eda5..1137c896eeb0b543927eb68a0357685e2eec2f9b 100644 (file)
       <groupId>org.apache.maven.wagon</groupId>\r
       <artifactId>wagon-provider-api</artifactId>\r
     </dependency>\r
+    <dependency>\r
+      <groupId>easymock</groupId>\r
+      <artifactId>easymock</artifactId>\r
+      <version>1.2_Java1.3</version>\r
+      <scope>test</scope>\r
+    </dependency>\r
   </dependencies>\r
   <build>\r
     <plugins>\r
index 3f4dc43db6476b798691882a7c47d8f9925448d4..5b000e413d9023847e22b6f2e5fd50407e4ace97 100644 (file)
@@ -17,7 +17,6 @@ package org.apache.maven.repository.proxy;
  */
 
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.manager.ChecksumFailedException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.repository.discovery.ArtifactDiscoverer;
@@ -38,8 +37,8 @@ import java.io.File;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -49,6 +48,7 @@ import java.util.Map;
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * @plexus.component
  * @todo this currently duplicates a lot of the wagon manager, and doesn't do things like snapshot resolution, etc.
+ * The checksum handling is inconsistent with that of the wagon manager.
  * Should we have a more artifact based one? This will merge metadata so should behave correctly, and it is able to
  * correct some limitations of the wagon manager (eg, it can retrieve newer SNAPSHOT files without metadata)
  */
@@ -100,7 +100,7 @@ public class DefaultProxyRequestHandler
 
     public File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository,
                            ProxyInfo wagonProxy )
-        throws ProxyException, ResourceDoesNotExistException
+        throws ResourceDoesNotExistException, ProxyException
     {
         File target = new File( managedRepository.getBasedir(), path );
 
@@ -114,68 +114,24 @@ public class DefaultProxyRequestHandler
             }
             else
             {
-                if ( path.endsWith( ".md5" ) || path.endsWith( ".sha1" ) )
-                {
-                    // always read from the managed repository, no need to make remote request
-                }
-                else if ( path.endsWith( "maven-metadata.xml" ) )
-                {
-                    // TODO: this is not always!
-                    if ( !target.exists() || isOutOfDate( repository.getRepository().getReleases(), target ) )
-                    {
-                        getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, target );
-                    }
-                }
-                else
+                try
                 {
-                    Artifact artifact = null;
-                    try
-                    {
-                        artifact = defaultArtifactDiscoverer.buildArtifact( path );
-                    }
-                    catch ( DiscovererException e )
-                    {
-                        getLogger().debug(
-                            "Failed to build artifact using default layout with message: " + e.getMessage() );
-                    }
-
-                    if ( artifact == null )
-                    {
-                        try
-                        {
-                            artifact = legacyArtifactDiscoverer.buildArtifact( path );
-                        }
-                        catch ( DiscovererException e )
-                        {
-                            getLogger().debug(
-                                "Failed to build artifact using legacy layout with message: " + e.getMessage() );
-                        }
-                    }
+                    get( path, target, repository, managedRepository, wagonProxy );
 
-                    if ( artifact != null )
+                    if ( !target.exists() )
                     {
-                        getArtifactFromRepository( artifact, repository, managedRepository, wagonProxy, target );
+                        repository.addFailure( path );
                     }
                     else
                     {
-                        // Some other unknown file in the repository, proxy as is
-                        // TODO: this is not always!
-                        if ( !target.exists() )
-                        {
-                            getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy,
-                                                   target );
-                        }
+                        // in case it previously failed and we've since found it
+                        repository.clearFailure( path );
                     }
                 }
-
-                if ( !target.exists() )
+                catch ( ProxyException e )
                 {
                     repository.addFailure( path );
-                }
-                else
-                {
-                    // in case it previously failed and we've since found it
-                    repository.clearFailure( path );
+                    throw e;
                 }
             }
         }
@@ -188,9 +144,65 @@ public class DefaultProxyRequestHandler
         return target;
     }
 
+    private void get( String path, File target, ProxiedArtifactRepository repository,
+                      ArtifactRepository managedRepository, ProxyInfo wagonProxy )
+        throws ProxyException
+    {
+        if ( path.endsWith( ".md5" ) || path.endsWith( ".sha1" ) )
+        {
+            // always read from the managed repository, no need to make remote request
+        }
+        else if ( path.endsWith( "maven-metadata.xml" ) )
+        {
+            // TODO: this is not always!
+            if ( !target.exists() || isOutOfDate( repository.getRepository().getReleases(), target ) )
+            {
+                getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, target );
+            }
+        }
+        else
+        {
+            Artifact artifact = null;
+            try
+            {
+                artifact = defaultArtifactDiscoverer.buildArtifact( path );
+            }
+            catch ( DiscovererException e )
+            {
+                getLogger().debug( "Failed to build artifact using default layout with message: " + e.getMessage() );
+            }
+
+            if ( artifact == null )
+            {
+                try
+                {
+                    artifact = legacyArtifactDiscoverer.buildArtifact( path );
+                }
+                catch ( DiscovererException e )
+                {
+                    getLogger().debug( "Failed to build artifact using legacy layout with message: " + e.getMessage() );
+                }
+            }
+
+            if ( artifact != null )
+            {
+                getArtifactFromRepository( artifact, repository, managedRepository, wagonProxy, target );
+            }
+            else
+            {
+                // Some other unknown file in the repository, proxy as is
+                // TODO: this is not always!
+                if ( !target.exists() )
+                {
+                    getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, target );
+                }
+            }
+        }
+    }
+
     private void getFileFromRepository( String path, ProxiedArtifactRepository repository, String repositoryCachePath,
                                         ProxyInfo httpProxy, File target )
-        throws ProxyException, ResourceDoesNotExistException
+        throws ProxyException
     {
         boolean connected = false;
         Map checksums = null;
@@ -222,7 +234,7 @@ public class DefaultProxyRequestHandler
                 {
                     tries++;
 
-                    getLogger().info( "Trying " + path + " from " + repository.getName() + "..." );
+                    getLogger().debug( "Trying " + path + " from " + repository.getName() + "..." );
 
                     if ( !target.exists() )
                     {
@@ -233,21 +245,21 @@ public class DefaultProxyRequestHandler
                         wagon.getIfNewer( path, temp, target.lastModified() );
                     }
 
-                    success = doChecksumCheck( checksums, path, wagon, repositoryCachePath );
+                    success = checkChecksum( checksums, path, wagon, repositoryCachePath );
 
                     if ( tries > 1 && !success )
                     {
-                        throw new ProxyException( "Checksum failures occurred while downloading " + path );
+                        //noinspection ThrowCaughtLocally
+                        throw new TransferFailedException( "Checksum failures occurred while downloading " + path );
                     }
-                }
-                while ( !success );
 
-                disconnectWagon( wagon );
-
-                if ( temp.exists() )
-                {
-                    moveTempToTarget( temp, target );
+                    // temp won't exist if we called getIfNewer and it was older, but its still a successful return
+                    if ( temp.exists() )
+                    {
+                        moveTempToTarget( temp, target );
+                    }
                 }
+                while ( !success );
             }
             //try next repository
         }
@@ -261,6 +273,11 @@ public class DefaultProxyRequestHandler
             String message = "Skipping repository " + repository.getName() + ": " + e.getMessage();
             processRepositoryFailure( repository, message, e );
         }
+        catch ( ResourceDoesNotExistException e )
+        {
+            // hard failure setting doesn't affect "not found".
+            getLogger().debug( "Artifact not found in repository: " + repository.getName() + ": " + e.getMessage() );
+        }
         finally
         {
             if ( wagon != null && checksums != null )
@@ -288,7 +305,7 @@ public class DefaultProxyRequestHandler
      */
     private Map prepareChecksumListeners( Wagon wagon )
     {
-        Map checksums = new HashMap();
+        Map checksums = new LinkedHashMap();
         try
         {
             ChecksumObserver checksum = new ChecksumObserver( "SHA-1" );
@@ -344,7 +361,7 @@ public class DefaultProxyRequestHandler
         return connected;
     }
 
-    private boolean doChecksumCheck( Map checksumMap, String path, Wagon wagon, String repositoryCachePath )
+    private boolean checkChecksum( Map checksumMap, String path, Wagon wagon, String repositoryCachePath )
         throws ProxyException
     {
         releaseChecksumListeners( wagon, checksumMap );
@@ -367,45 +384,49 @@ public class DefaultProxyRequestHandler
                     remoteChecksum = remoteChecksum.substring( 0, remoteChecksum.indexOf( ' ' ) );
                 }
 
-                boolean checksumCheck = false;
-                if ( remoteChecksum.toUpperCase().equals( checksum.getActualChecksum().toUpperCase() ) )
+                String actualChecksum = checksum.getActualChecksum().toUpperCase();
+                remoteChecksum = remoteChecksum.toUpperCase();
+
+                boolean checksumCheck;
+                if ( remoteChecksum.equals( actualChecksum ) )
                 {
                     moveTempToTarget( tempChecksumFile, checksumFile );
 
                     checksumCheck = true;
                 }
+                else
+                {
+                    getLogger().warn(
+                        "The checksum '" + actualChecksum + "' did not match the remote value: " + remoteChecksum );
+                    checksumCheck = false;
+                }
                 return checksumCheck;
             }
-            catch ( ChecksumFailedException e )
-            {
-                return false;
-            }
             catch ( TransferFailedException e )
             {
-                getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
-                                   e );
+                getLogger().warn( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
+                                  e );
                 // do nothing try the next checksum
             }
             catch ( ResourceDoesNotExistException e )
             {
-                getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
-                                   e );
+                getLogger().debug( "The checksum did not exist: " + checksumPath, e );
                 // do nothing try the next checksum
             }
             catch ( AuthorizationException e )
             {
-                getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
-                                   e );
+                getLogger().warn( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
+                                  e );
                 // do nothing try the next checksum
             }
             catch ( IOException e )
             {
-                getLogger().debug( "An error occurred while reading the temporary checksum file.", e );
+                getLogger().warn( "An error occurred while reading the temporary checksum file.", e );
                 return false;
             }
         }
 
-        getLogger().debug( "Skipping checksum validation for " + path + ": No remote checksums available." );
+        getLogger().debug( "No remote checksums available." );
 
         return true;
     }
@@ -480,13 +501,14 @@ public class DefaultProxyRequestHandler
         }
         else
         {
-            getLogger().error( message, t );
+            getLogger().warn( message );
+            getLogger().debug( message, t );
         }
     }
 
     private void getArtifactFromRepository( Artifact artifact, ProxiedArtifactRepository repository,
                                             ArtifactRepository managedRepository, ProxyInfo httpProxy, File remoteFile )
-        throws ProxyException, ResourceDoesNotExistException
+        throws ProxyException
     {
         ArtifactRepository artifactRepository = repository.getRepository();
         ArtifactRepositoryPolicy policy =
index 9e7aa538899c842fbd970ef6a94cd184c32fb1c3..c722686d0534293a9749328817e52370f37707b3 100644 (file)
@@ -20,21 +20,24 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authorization.AuthorizationException;
 import org.codehaus.plexus.PlexusTestCase;
 import org.codehaus.plexus.util.FileUtils;
+import org.easymock.MockControl;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
  * @author Brett Porter
  * @todo! tests to do vvv
- * @todo test when >1 repo has the artifact
- * @todo test when >1 repo has the artifact but one fails
- * @todo test hard failure on repo1
  * @todo test when failure is cached
+ * @todo test when failure is cached and repo is hard fail
  * @todo test when failure should be cached but caching is disabled
  * @todo test snapshots - general
  * @todo test snapshots - newer version on repo2 is pulled down
@@ -43,10 +46,18 @@ import java.util.List;
  * @todo test metadata - general
  * @todo test metadata - multiple repos are merged
  * @todo test metadata - update interval
+ * @todo test metadata - looking for an update and file has been removed remotely
  * @todo test when managed repo is m1 layout (proxy is m2), including metadata
  * @todo test when one proxied repo is m1 layout (managed is m2), including metadata
  * @todo test when one proxied repo is m1 layout (managed is m1), including metadata
  * @todo test get always
+ * @todo test get always when resource is present locally but not in any proxied repos (should fail)
+ * @todo test remote checksum only md5
+ * @todo test remote checksum only sha1
+ * @todo test remote checksum missing
+ * @todo test remote checksum present and correct
+ * @todo test remote checksum present and incorrect
+ * @todo test remote checksum transfer failed
  */
 public class ProxyRequestHandlerTest
     extends PlexusTestCase
@@ -61,6 +72,14 @@ public class ProxyRequestHandlerTest
 
     private ArtifactRepository proxiedRepository2;
 
+    private ArtifactRepositoryLayout defaultLayout;
+
+    private ArtifactRepositoryFactory factory;
+
+    private MockControl wagonMockControl;
+
+    private Wagon wagonMock;
+
     protected void setUp()
         throws Exception
     {
@@ -72,24 +91,25 @@ public class ProxyRequestHandlerTest
         FileUtils.deleteDirectory( repoLocation );
         copyDirectoryStructure( getTestFile( "src/test/repositories/managed" ), repoLocation );
 
-        ArtifactRepositoryFactory factory = (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.ROLE );
-        ArtifactRepositoryLayout defaultLayout =
-            (ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, "default" );
-        defaultManagedRepository = factory.createArtifactRepository( "managed-repository",
-                                                                     repoLocation.toURI().toURL().toExternalForm(),
-                                                                     defaultLayout, null, null );
+        defaultLayout = (ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, "default" );
+        factory = (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.ROLE );
+
+        defaultManagedRepository = createRepository( "managed-repository", repoLocation );
 
         File location = getTestFile( "src/test/repositories/proxied1" );
-        proxiedRepository1 = factory.createArtifactRepository( "proxied1", location.toURI().toURL().toExternalForm(),
-                                                               defaultLayout, null, null );
+        proxiedRepository1 = createRepository( "proxied1", location );
 
         location = getTestFile( "src/test/repositories/proxied2" );
-        proxiedRepository2 = factory.createArtifactRepository( "proxied2", location.toURI().toURL().toExternalForm(),
-                                                               defaultLayout, null, null );
+        proxiedRepository2 = createRepository( "proxied2", location );
 
         proxiedRepositories = new ArrayList( 2 );
         proxiedRepositories.add( createProxiedRepository( proxiedRepository1 ) );
         proxiedRepositories.add( createProxiedRepository( proxiedRepository2 ) );
+
+        wagonMockControl = MockControl.createNiceControl( Wagon.class );
+        wagonMock = (Wagon) wagonMockControl.getMock();
+        WagonDelegate delegate = (WagonDelegate) lookup( Wagon.ROLE, "test" );
+        delegate.setDelegate( wagonMock );
     }
 
     public void testGetDefaultLayoutNotPresent()
@@ -134,12 +154,183 @@ public class ProxyRequestHandlerTest
                       file.lastModified() );
     }
 
+    public void testGetWhenInBothProxiedRepos()
+        throws ResourceDoesNotExistException, ProxyException, IOException
+    {
+        String path = "org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path );
+
+        assertFalse( expectedFile.exists() );
+
+        File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+
+        assertEquals( "Check file matches", expectedFile, file );
+        assertTrue( "Check file created", file.exists() );
+
+        File proxiedFile = new File( proxiedRepository1.getBasedir(), path );
+        String expectedContents = FileUtils.fileRead( proxiedFile );
+        assertEquals( "Check file contents", expectedContents, FileUtils.fileRead( file ) );
+
+        proxiedFile = new File( proxiedRepository2.getBasedir(), path );
+        String unexpectedContents = FileUtils.fileRead( proxiedFile );
+        assertFalse( "Check file contents", unexpectedContents.equals( FileUtils.fileRead( file ) ) );
+    }
+
+    public void testGetInSecondProxiedRepo()
+        throws ResourceDoesNotExistException, ProxyException, IOException
+    {
+        String path = "org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path );
+
+        assertFalse( expectedFile.exists() );
+
+        File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+
+        assertEquals( "Check file matches", expectedFile, file );
+        assertTrue( "Check file created", file.exists() );
+        File proxiedFile = new File( proxiedRepository2.getBasedir(), path );
+        String expectedContents = FileUtils.fileRead( proxiedFile );
+        assertEquals( "Check file contents", expectedContents, FileUtils.fileRead( file ) );
+    }
+
+    public void testNotFoundInAnyProxies()
+        throws ResourceDoesNotExistException, ProxyException, IOException
+    {
+        String path = "org/apache/maven/test/does-not-exist/1.0/does-not-exist-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path );
+
+        assertFalse( expectedFile.exists() );
+
+        try
+        {
+            File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+            fail( "File returned was: " + file + "; should have got a not found exception" );
+        }
+        catch ( ResourceDoesNotExistException e )
+        {
+            // expected, but check file was not created
+            assertFalse( expectedFile.exists() );
+        }
+    }
+
+    public void testGetInSecondProxiedRepoFirstFails()
+        throws ResourceDoesNotExistException, ProxyException, IOException, TransferFailedException,
+        AuthorizationException
+    {
+        String path = "org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path ).getAbsoluteFile();
+
+        assertFalse( expectedFile.exists() );
+
+        proxiedRepository1 = createRepository( "proxied1", "test://..." );
+        proxiedRepositories.clear();
+        ProxiedArtifactRepository proxiedArtifactRepository = createProxiedRepository( proxiedRepository1 );
+        proxiedRepositories.add( proxiedArtifactRepository );
+        proxiedRepositories.add( createProxiedRepository( proxiedRepository2 ) );
+
+        wagonMock.get( path, new File( expectedFile.getParentFile(), expectedFile.getName() + ".tmp" ) );
+        wagonMockControl.setThrowable( new TransferFailedException( "transfer failed" ) );
+
+        wagonMockControl.replay();
+
+        File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+
+        wagonMockControl.verify();
+
+        assertEquals( "Check file matches", expectedFile, file );
+        assertTrue( "Check file created", file.exists() );
+        File proxiedFile = new File( proxiedRepository2.getBasedir(), path );
+        String expectedContents = FileUtils.fileRead( proxiedFile );
+        assertEquals( "Check file contents", expectedContents, FileUtils.fileRead( file ) );
+
+        assertTrue( "Check failure", proxiedArtifactRepository.isCachedFailure( path ) );
+    }
+
+    public void testGetButAllRepositoriesFail()
+        throws ResourceDoesNotExistException, ProxyException, IOException, TransferFailedException,
+        AuthorizationException
+    {
+        String path = "org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path ).getAbsoluteFile();
+
+        assertFalse( expectedFile.exists() );
+
+        proxiedRepository1 = createRepository( "proxied1", "test://..." );
+        proxiedRepository2 = createRepository( "proxied2", "test://..." );
+        proxiedRepositories.clear();
+        ProxiedArtifactRepository proxiedArtifactRepository1 = createProxiedRepository( proxiedRepository1 );
+        proxiedRepositories.add( proxiedArtifactRepository1 );
+        ProxiedArtifactRepository proxiedArtifactRepository2 = createProxiedRepository( proxiedRepository2 );
+        proxiedRepositories.add( proxiedArtifactRepository2 );
+
+        wagonMock.get( path, new File( expectedFile.getParentFile(), expectedFile.getName() + ".tmp" ) );
+        wagonMockControl.setThrowable( new TransferFailedException( "transfer failed" ) );
+
+        wagonMock.get( path, new File( expectedFile.getParentFile(), expectedFile.getName() + ".tmp" ) );
+        wagonMockControl.setThrowable( new TransferFailedException( "transfer failed" ) );
+
+        wagonMockControl.replay();
+
+        try
+        {
+            File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+            fail( "Found file: " + file + "; but was expecting a failure" );
+        }
+        catch ( ResourceDoesNotExistException e )
+        {
+            // as expected
+            wagonMockControl.verify();
+            assertTrue( "Check failure", proxiedArtifactRepository1.isCachedFailure( path ) );
+            assertTrue( "Check failure", proxiedArtifactRepository2.isCachedFailure( path ) );
+
+            // TODO: do we really want failures to present as a not found?
+            // TODO: How much information on each failure should we pass back to the user vs. logging in the proxy? 
+        }
+    }
+
+    public void testGetInSecondProxiedRepoFirstHardFails()
+        throws ResourceDoesNotExistException, ProxyException, IOException, TransferFailedException,
+        AuthorizationException
+    {
+        String path = "org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar";
+        File expectedFile = new File( defaultManagedRepository.getBasedir(), path ).getAbsoluteFile();
+
+        assertFalse( expectedFile.exists() );
+
+        proxiedRepository1 = createRepository( "proxied1", "test://..." );
+        proxiedRepositories.clear();
+        ProxiedArtifactRepository proxiedArtifactRepository = createHardFailProxiedRepository( proxiedRepository1 );
+        proxiedRepositories.add( proxiedArtifactRepository );
+        proxiedRepositories.add( createProxiedRepository( proxiedRepository2 ) );
+
+        wagonMock.get( path, new File( expectedFile.getParentFile(), expectedFile.getName() + ".tmp" ) );
+        TransferFailedException failedException = new TransferFailedException( "transfer failed" );
+        wagonMockControl.setThrowable( failedException );
+
+        wagonMockControl.replay();
+
+        try
+        {
+            File file = requestHandler.get( path, proxiedRepositories, defaultManagedRepository );
+            fail( "Found file: " + file + "; but was expecting a failure" );
+        }
+        catch ( ProxyException e )
+        {
+            // expect a failure
+            wagonMockControl.verify();
+
+            assertEquals( "Check cause", failedException, e.getCause() );
+            assertTrue( "Check failure", proxiedArtifactRepository.isCachedFailure( path ) );
+        }
+    }
+
     /**
      * A faster recursive copy that omits .svn directories.
      *
      * @param sourceDirectory the source directory to copy
      * @param destDirectory   the target location
-     * @throws java.io.IOException if there is a copying problemt
+     * @throws java.io.IOException if there is a copying problem
+     * @todo get back into plexus-utils, share with indexing module
      */
     private static void copyDirectoryStructure( File sourceDirectory, File destDirectory )
         throws IOException
@@ -193,6 +384,30 @@ public class ProxyRequestHandlerTest
     {
         ProxiedArtifactRepository proxiedArtifactRepository = new ProxiedArtifactRepository( repository );
         proxiedArtifactRepository.setName( repository.getId() );
+        proxiedArtifactRepository.setCacheFailures( true );
         return proxiedArtifactRepository;
     }
+
+    private static ProxiedArtifactRepository createHardFailProxiedRepository( ArtifactRepository repository )
+    {
+        ProxiedArtifactRepository proxiedArtifactRepository = createProxiedRepository( repository );
+        proxiedArtifactRepository.setHardFail( true );
+        return proxiedArtifactRepository;
+    }
+
+    private ArtifactRepository createRepository( String id, File repoLocation )
+        throws MalformedURLException
+    {
+        return createRepository( id, repoLocation.toURI().toURL().toExternalForm() );
+    }
+
+    private ArtifactRepository createRepository( String id, String url )
+    {
+        return createRepository( id, url, defaultLayout );
+    }
+
+    private ArtifactRepository createRepository( String id, String url, ArtifactRepositoryLayout repositoryLayout )
+    {
+        return factory.createArtifactRepository( id, url, repositoryLayout, null, null );
+    }
 }
diff --git a/maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/WagonDelegate.java b/maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/WagonDelegate.java
new file mode 100644 (file)
index 0000000..904d6b8
--- /dev/null
@@ -0,0 +1,157 @@
+package org.apache.maven.repository.proxy;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.ConnectionException;
+import org.apache.maven.wagon.events.SessionListener;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.authentication.AuthenticationException;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+import org.apache.maven.wagon.repository.Repository;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+
+import java.io.File;
+
+/**
+ * A dummy wagon implementation
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+public class WagonDelegate
+    implements Wagon
+{
+    private Wagon delegate;
+
+    public void get( String resourceName, File destination )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        delegate.get( resourceName, destination );
+    }
+
+    public boolean getIfNewer( String resourceName, File destination, long timestamp )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        return delegate.getIfNewer( resourceName, destination, timestamp );
+    }
+
+    public void put( File source, String destination )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        delegate.put( source, destination );
+    }
+
+    public void putDirectory( File sourceDirectory, String destinationDirectory )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        delegate.putDirectory( sourceDirectory, destinationDirectory );
+    }
+
+    public boolean supportsDirectoryCopy()
+    {
+        return delegate.supportsDirectoryCopy();
+    }
+
+    public Repository getRepository()
+    {
+        return delegate.getRepository();
+    }
+
+    public void connect( Repository source )
+        throws ConnectionException, AuthenticationException
+    {
+        delegate.connect( source );
+    }
+
+    public void connect( Repository source, ProxyInfo proxyInfo )
+        throws ConnectionException, AuthenticationException
+    {
+        delegate.connect( source, proxyInfo );
+    }
+
+    public void connect( Repository source, AuthenticationInfo authenticationInfo )
+        throws ConnectionException, AuthenticationException
+    {
+        delegate.connect( source, authenticationInfo );
+    }
+
+    public void connect( Repository source, AuthenticationInfo authenticationInfo, ProxyInfo proxyInfo )
+        throws ConnectionException, AuthenticationException
+    {
+        delegate.connect( source, authenticationInfo, proxyInfo );
+    }
+
+    public void openConnection()
+        throws ConnectionException, AuthenticationException
+    {
+        delegate.openConnection();
+    }
+
+    public void disconnect()
+        throws ConnectionException
+    {
+        delegate.disconnect();
+    }
+
+    public void addSessionListener( SessionListener listener )
+    {
+        delegate.addSessionListener( listener );
+    }
+
+    public void removeSessionListener( SessionListener listener )
+    {
+        delegate.removeSessionListener( listener );
+    }
+
+    public boolean hasSessionListener( SessionListener listener )
+    {
+        return delegate.hasSessionListener( listener );
+    }
+
+    public void addTransferListener( TransferListener listener )
+    {
+        delegate.addTransferListener( listener );
+    }
+
+    public void removeTransferListener( TransferListener listener )
+    {
+        delegate.removeTransferListener( listener );
+    }
+
+    public boolean hasTransferListener( TransferListener listener )
+    {
+        return delegate.hasTransferListener( listener );
+    }
+
+    public boolean isInteractive()
+    {
+        return delegate.isInteractive();
+    }
+
+    public void setInteractive( boolean interactive )
+    {
+        delegate.setInteractive( interactive );
+    }
+
+    public void setDelegate( Wagon delegate )
+    {
+        this.delegate = delegate;
+    }
+}
diff --git a/maven-repository-proxy/src/test/repositories/proxied1/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar b/maven-repository-proxy/src/test/repositories/proxied1/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar
new file mode 100644 (file)
index 0000000..3cc35fa
--- /dev/null
@@ -0,0 +1,3 @@
+get-in-both-proxies-1.0.jar
+(proxied 1)
+
diff --git a/maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar b/maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar
new file mode 100644 (file)
index 0000000..e46d60a
--- /dev/null
@@ -0,0 +1,3 @@
+get-in-both-proxies-1.0.jar
+(proxied 2)
+
diff --git a/maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar b/maven-repository-proxy/src/test/repositories/proxied2/org/apache/maven/test/get-in-second-proxy/1.0/get-in-second-proxy-1.0.jar
new file mode 100644 (file)
index 0000000..3460f65
--- /dev/null
@@ -0,0 +1,2 @@
+get-in-second-proxy-1.0.jar
+
diff --git a/maven-repository-proxy/src/test/resources/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.xml b/maven-repository-proxy/src/test/resources/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.xml
new file mode 100644 (file)
index 0000000..d7fa2be
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2005-2006 The Apache Software Foundation.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<component-set>
+  <components>
+    <component>
+      <role>org.apache.maven.wagon.Wagon</role>
+      <role-hint>test</role-hint>
+      <implementation>org.apache.maven.repository.proxy.WagonDelegate</implementation>
+    </component>
+  </components>
+</component-set>