View Javadoc
1   package org.apache.maven.wagon;
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 org.apache.maven.wagon.authentication.AuthenticationException;
23  import org.apache.maven.wagon.authentication.AuthenticationInfo;
24  import org.apache.maven.wagon.authorization.AuthorizationException;
25  import org.apache.maven.wagon.events.TransferEvent;
26  import org.apache.maven.wagon.events.TransferListener;
27  import org.apache.maven.wagon.observers.ChecksumObserver;
28  import org.apache.maven.wagon.observers.Debug;
29  import org.apache.maven.wagon.repository.Repository;
30  import org.apache.maven.wagon.repository.RepositoryPermissions;
31  import org.apache.maven.wagon.resource.Resource;
32  import org.codehaus.plexus.PlexusTestCase;
33  import org.codehaus.plexus.util.FileUtils;
34  import org.easymock.IAnswer;
35  
36  // CHECKSTYLE_OFF: AvoidStarImport
37  import static org.easymock.EasyMock.*;
38  //CHECKSTYLE_ON: AvoidStarImport
39  
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  import java.io.File;
44  import java.io.IOException;
45  import java.nio.charset.StandardCharsets;
46  import java.security.NoSuchAlgorithmException;
47  import java.text.SimpleDateFormat;
48  import java.util.ArrayList;
49  import java.util.Collections;
50  import java.util.List;
51  
52  /**
53   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
54   */
55  public abstract class WagonTestCase
56      extends PlexusTestCase
57  {
58      protected static Logger logger = LoggerFactory.getLogger( WagonTestCase.class );
59  
60  
61      static final class ProgressAnswer implements IAnswer
62      {
63          private int size;
64  
65          public Object answer() throws Throwable
66          {
67              int length = (Integer) getCurrentArguments()[2];
68              size += length;
69              return null;
70          }
71  
72          public int getSize()
73          {
74              return size;
75          }
76      }
77  
78      protected static final String TEST_CONTENT = "test-resource.txt\n";
79  
80      protected static final String TEST_CKSUM = cksum( TEST_CONTENT );
81  
82      protected static final String POM = "pom.xml";
83  
84      protected Repository localRepository;
85  
86      protected Repository testRepository;
87  
88      protected String localRepositoryPath;
89  
90      protected File sourceFile;
91  
92      protected File destFile;
93  
94      protected String resource;
95  
96      protected boolean testSkipped;
97  
98      protected File artifactSourceFile;
99  
100     protected File artifactDestFile;
101 
102     protected ChecksumObserver checksumObserver;
103 
104     protected TransferListener mockTransferListener;
105 
106     // ----------------------------------------------------------------------
107     // Constructors
108     // ----------------------------------------------------------------------
109 
110     protected void setUp()
111         throws Exception
112     {
113         checksumObserver = new ChecksumObserver();
114 
115         mockTransferListener = createMock( TransferListener.class );
116 
117         super.setUp();
118     }
119 
120     // ----------------------------------------------------------------------
121     // Methods that should be provided by subclasses for proper testing
122     // ----------------------------------------------------------------------
123 
124     /**
125      * URL of the repository. For a complete test it should point to a non existing folder so we also check for the
126      * creation of new folders in the remote site. <p/> return the URL of the repository as specified by Wagon syntax
127      */
128     protected abstract String getTestRepositoryUrl()
129         throws IOException;
130 
131     /**
132      * Protocol id of the Wagon to use, eg. <code>scp</code>, <code>ftp</code>
133      *
134      * @return the protocol id
135      */
136     protected abstract String getProtocol();
137 
138     // ----------------------------------------------------------------------
139     // 1. Create a local file repository which mimic a users local file
140     // Repository.
141     //
142     // 2. Create a test repository for the type of wagon we are testing. So,
143     // for example, for testing the file wagon we might have a test
144     // repository url of file://${basedir}/target/file-repository.
145     // ----------------------------------------------------------------------
146 
147     protected void setupRepositories()
148         throws Exception
149     {
150         resource = "test-resource";
151 
152         // ----------------------------------------------------------------------
153         // Create the test repository for the wagon we are testing.
154         // ----------------------------------------------------------------------
155 
156         testRepository = new Repository();
157 
158         testRepository.setUrl( getTestRepositoryUrl() );
159 
160         testRepository.setPermissions( getPermissions() );
161 
162         // ----------------------------------------------------------------------
163         // Create a test local repository.
164         // ----------------------------------------------------------------------
165 
166         File file = FileTestUtils.createDir( "local-repository" );
167         localRepositoryPath = file.getPath();
168 
169         localRepository = createFileRepository( file.toPath().toUri().toASCIIString() );
170 
171         message( "Local repository: " + localRepository );
172 
173         File f = new File( localRepositoryPath );
174 
175         if ( !f.exists() )
176         {
177             f.mkdirs();
178         }
179     }
180 
181     protected void customizeContext()
182         throws Exception
183     {
184         getContainer().addContextValue( "test.repository", localRepositoryPath );
185     }
186 
187     protected void setupWagonTestingFixtures()
188         throws Exception
189     {
190     }
191 
192     protected void tearDownWagonTestingFixtures()
193         throws Exception
194     {
195     }
196 
197     // ----------------------------------------------------------------------
198     //
199     // ----------------------------------------------------------------------
200 
201     protected AuthenticationInfo getAuthInfo()
202     {
203         return new AuthenticationInfo();
204     }
205 
206     protected RepositoryPermissions getPermissions()
207     {
208         return new RepositoryPermissions();
209     }
210 
211     protected Wagon getWagon()
212         throws Exception
213     {
214         Wagon wagon = (Wagon) lookup( Wagon.ROLE, getProtocol() );
215 
216         Debug debug = new Debug();
217 
218         wagon.addSessionListener( debug );
219 
220         wagon.addTransferListener( debug );
221 
222         return wagon;
223     }
224 
225     /**
226      * @param cmd the executable to run, not null.
227      * @return <code>true</code>
228      */
229     public static boolean isSystemCmd( String cmd )
230     {
231         try
232         {
233             Runtime.getRuntime().exec( cmd );
234 
235             return true;
236         }
237         catch ( IOException e )
238         {
239             return false;
240         }
241     }
242 
243     protected void message( String message )
244     {
245         logger.info( message );
246     }
247 
248     // ----------------------------------------------------------------------
249     //
250     // ----------------------------------------------------------------------
251 
252     public void testWagon()
253         throws Exception
254     {
255         setupWagonTestingFixtures();
256 
257         setupRepositories();
258 
259         fileRoundTripTesting();
260 
261         tearDownWagonTestingFixtures();
262     }
263 
264     public void testWagonGetIfNewerIsNewer()
265         throws Exception
266     {
267         if ( supportsGetIfNewer() )
268         {
269             setupWagonTestingFixtures();
270             setupRepositories();
271             int expectedSize = putFile();
272             // CHECKSTYLE_OFF: MagicNumber
273             getIfNewer( getExpectedLastModifiedOnGet( testRepository, new Resource( resource ) ) + 30000, false,
274                         expectedSize );
275             // CHECKSTYLE_ON: MagicNumber
276         }
277     }
278 
279     @Override
280     protected void runTest()
281         throws Throwable
282     {
283         if ( !testSkipped )
284         {
285             super.runTest();
286         }
287     }
288 
289     protected boolean supportsGetIfNewer()
290     {
291         return true;
292     }
293 
294 
295     public void testWagonGetIfNewerIsSame()
296         throws Exception
297     {
298         if ( supportsGetIfNewer() )
299         {
300             setupWagonTestingFixtures();
301             setupRepositories();
302             int expectedSize = putFile();
303             getIfNewer( getExpectedLastModifiedOnGet( testRepository, new Resource( resource ) ), false, expectedSize );
304         }
305     }
306 
307     public void testWagonGetIfNewerIsOlder()
308         throws Exception
309     {
310         if ( supportsGetIfNewer() )
311         {
312             setupWagonTestingFixtures();
313             setupRepositories();
314             int expectedSize = putFile();
315             getIfNewer( new SimpleDateFormat( "yyyy-MM-dd" ).parse( "2006-01-01" ).getTime(), true, expectedSize );
316         }
317     }
318 
319     private void getIfNewer( long timestamp, boolean expectedResult, int expectedSize )
320         throws Exception
321     {
322         Wagon wagon = getWagon();
323 
324         ProgressAnswer progressAnswer = setupGetIfNewerTest( wagon, expectedResult, expectedSize );
325 
326         connectWagon( wagon );
327 
328         boolean result = wagon.getIfNewer( this.resource, destFile, timestamp );
329         assertEquals( expectedResult, result );
330 
331         disconnectWagon( wagon );
332 
333         assertGetIfNewerTest( progressAnswer, expectedResult, expectedSize );
334 
335         tearDownWagonTestingFixtures();
336     }
337 
338     protected ProgressAnswer setupGetIfNewerTest( Wagon wagon, boolean expectedResult, int expectedSize )
339         throws NoSuchAlgorithmException, IOException
340     {
341         checksumObserver = new ChecksumObserver();
342 
343         destFile = FileTestUtils.createUniqueFile( getName(), getName() );
344         destFile.delete();
345         assertFalse( destFile.exists() );
346         destFile.deleteOnExit();
347 
348         ProgressAnswer progressAnswer = null;
349         if ( expectedResult )
350         {
351             progressAnswer = replaceMockForGet( wagon, expectedSize );
352         }
353         else
354         {
355             replaceMockForSkippedGetIfNewer( wagon, expectedSize );
356         }
357         return progressAnswer;
358     }
359 
360     protected void assertGetIfNewerTest( ProgressAnswer progressAnswer, boolean expectedResult,
361                                          int expectedSize )
362         throws IOException
363     {
364         if ( expectedResult )
365         {
366             verifyMock( progressAnswer, expectedSize );
367 
368             assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
369 
370             assertEquals( "compare checksums", TEST_CKSUM,
371                           checksumObserver.getActualChecksum() );
372 
373             // Now compare the contents of the artifact that was placed in
374             // the repository with the contents of the artifact that was
375             // retrieved from the repository.
376 
377             String sourceContent = FileUtils.fileRead( sourceFile );
378             String destContent = FileUtils.fileRead( destFile );
379             assertEquals( sourceContent, destContent );
380         }
381         else
382         {
383             verify( mockTransferListener );
384 
385             reset( mockTransferListener );
386 
387             assertNull( "check checksum is null", checksumObserver.getActualChecksum() );
388 
389             assertFalse( destFile.exists() );
390         }
391     }
392 
393 
394     private void replaceMockForSkippedGetIfNewer( Wagon wagon, int expectedSize )
395     {
396         Resource resource = new Resource( this.resource );
397         mockTransferListener.transferInitiated(
398             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_GET,
399                                  destFile ) );
400         resource = new Resource( this.resource );
401         resource.setContentLength( getExpectedContentLengthOnGet( expectedSize ) );
402         resource.setLastModified( getExpectedLastModifiedOnGet( testRepository, resource ) );
403         // TODO: transfer skipped event?
404         // mockTransferListener.transferSkipped( createTransferEvent( wagon, resource, TransferEvent.TRANSFER_STARTED,
405         // TransferEvent.REQUEST_GET, destFile ) );
406 
407         mockTransferListener.debug( anyString() );
408         expectLastCall().anyTimes();
409 
410         replay( mockTransferListener );
411     }
412 
413     public void testWagonPutDirectory()
414         throws Exception
415     {
416         setupWagonTestingFixtures();
417 
418         setupRepositories();
419 
420         Wagon wagon = getWagon();
421 
422         if ( wagon.supportsDirectoryCopy() )
423         {
424             sourceFile = new File( FileTestUtils.getTestOutputDir(), "directory-copy" );
425 
426             FileUtils.deleteDirectory( sourceFile );
427 
428             writeTestFile( "test-resource-1.txt" );
429             writeTestFile( "a/test-resource-2.txt" );
430             writeTestFile( "a/b/test-resource-3.txt" );
431             writeTestFile( "c/test-resource-4.txt" );
432             writeTestFile( "d/e/f/test-resource-5.txt" );
433 
434             wagon.connect( testRepository, getAuthInfo() );
435 
436             wagon.putDirectory( sourceFile, "directory-copy" );
437 
438             destFile = FileTestUtils.createUniqueFile( getName(), getName() );
439 
440             destFile.deleteOnExit();
441 
442             wagon.get( "directory-copy/test-resource-1.txt", destFile );
443             wagon.get( "directory-copy/a/test-resource-2.txt", destFile );
444             wagon.get( "directory-copy/a/b/test-resource-3.txt", destFile );
445             wagon.get( "directory-copy/c/test-resource-4.txt", destFile );
446             wagon.get( "directory-copy/d/e/f/test-resource-5.txt", destFile );
447 
448             wagon.disconnect();
449         }
450 
451         tearDownWagonTestingFixtures();
452     }
453 
454     /**
455      * Test for putting a directory with a destination that multiple directories deep, all of which haven't been
456      * created.
457      *
458      * @throws Exception
459      * @since 1.0-beta-2
460      */
461     public void testWagonPutDirectoryDeepDestination()
462         throws Exception
463     {
464         setupWagonTestingFixtures();
465 
466         setupRepositories();
467 
468         Wagon wagon = getWagon();
469 
470         if ( wagon.supportsDirectoryCopy() )
471         {
472             sourceFile = new File( FileTestUtils.getTestOutputDir(), "deep0/deep1/deep2" );
473 
474             FileUtils.deleteDirectory( sourceFile );
475 
476             writeTestFile( "test-resource-1.txt" );
477             writeTestFile( "a/test-resource-2.txt" );
478             writeTestFile( "a/b/test-resource-3.txt" );
479             writeTestFile( "c/test-resource-4.txt" );
480             writeTestFile( "d/e/f/test-resource-5.txt" );
481 
482             wagon.connect( testRepository, getAuthInfo() );
483 
484             wagon.putDirectory( sourceFile, "deep0/deep1/deep2" );
485 
486             destFile = FileTestUtils.createUniqueFile( getName(), getName() );
487 
488             destFile.deleteOnExit();
489 
490             wagon.get( "deep0/deep1/deep2/test-resource-1.txt", destFile );
491             wagon.get( "deep0/deep1/deep2/a/test-resource-2.txt", destFile );
492             wagon.get( "deep0/deep1/deep2/a/b/test-resource-3.txt", destFile );
493             wagon.get( "deep0/deep1/deep2/c/test-resource-4.txt", destFile );
494             wagon.get( "deep0/deep1/deep2/d/e/f/test-resource-5.txt", destFile );
495 
496             wagon.disconnect();
497         }
498 
499         tearDownWagonTestingFixtures();
500     }
501 
502     /**
503      * Test that when putting a directory that already exists new files get also copied
504      *
505      * @throws Exception
506      * @since 1.0-beta-1
507      */
508     public void testWagonPutDirectoryWhenDirectoryAlreadyExists()
509         throws Exception
510     {
511 
512         final String dirName = "directory-copy-existing";
513 
514         final String resourceToCreate = "test-resource-1.txt";
515 
516         final String[] resources = { "a/test-resource-2.txt", "a/b/test-resource-3.txt", "c/test-resource-4.txt" };
517 
518         setupWagonTestingFixtures();
519 
520         setupRepositories();
521 
522         Wagon wagon = getWagon();
523 
524         if ( wagon.supportsDirectoryCopy() )
525         {
526             sourceFile = new File( FileTestUtils.getTestOutputDir(), dirName );
527 
528             FileUtils.deleteDirectory( sourceFile );
529 
530             createDirectory( wagon, resourceToCreate, dirName );
531 
532             for ( String resource : resources )
533             {
534                 writeTestFile( resource );
535             }
536 
537             wagon.connect( testRepository, getAuthInfo() );
538 
539             wagon.putDirectory( sourceFile, dirName );
540 
541             List<String> resourceNames = new ArrayList<String>( resources.length + 1 );
542 
543             resourceNames.add( dirName + "/" + resourceToCreate );
544             for ( String resource : resources )
545             {
546                 resourceNames.add( dirName + "/" + resource );
547             }
548 
549             assertResourcesAreInRemoteSide( wagon, resourceNames );
550 
551             wagon.disconnect();
552         }
553 
554         tearDownWagonTestingFixtures();
555     }
556 
557     /**
558      * Test that when putting a directory that already exists new files get also copied and destination is "."
559      *
560      * @throws Exception
561      * @since 1.0-beta-1
562      */
563     public void testWagonPutDirectoryForDot()
564         throws Exception
565     {
566         final String resourceToCreate = "test-resource-1.txt";
567 
568         final String[] resources = { "a/test-resource-2.txt", "a/b/test-resource-3.txt", "c/test-resource-4.txt" };
569 
570         setupWagonTestingFixtures();
571 
572         setupRepositories();
573 
574         Wagon wagon = getWagon();
575 
576         if ( wagon.supportsDirectoryCopy() )
577         {
578             sourceFile = new File( FileTestUtils.getTestOutputDir(), "dot-repo" );
579 
580             FileUtils.deleteDirectory( sourceFile );
581 
582             createDirectory( wagon, resourceToCreate, "." );
583 
584             for ( String resource : resources )
585             {
586                 writeTestFile( resource );
587             }
588 
589             wagon.connect( testRepository, getAuthInfo() );
590 
591             wagon.putDirectory( sourceFile, "." );
592 
593             List<String> resourceNames = new ArrayList<String>( resources.length + 1 );
594 
595             resourceNames.add( resourceToCreate );
596             Collections.addAll( resourceNames, resources );
597 
598             assertResourcesAreInRemoteSide( wagon, resourceNames );
599 
600             wagon.disconnect();
601         }
602 
603         tearDownWagonTestingFixtures();
604     }
605 
606     /**
607      * Create a directory with a resource and check that the other ones don't exist
608      *
609      * @param wagon
610      * @param resourceToCreate name of the resource to be created
611      * @param dirName          directory name to create
612      * @throws Exception
613      */
614     protected void createDirectory( Wagon wagon, String resourceToCreate, String dirName )
615         throws Exception
616     {
617         writeTestFile( resourceToCreate );
618     }
619 
620     protected void assertResourcesAreInRemoteSide( Wagon wagon, List<String> resourceNames )
621         throws IOException, TransferFailedException, ResourceDoesNotExistException, AuthorizationException
622     {
623         for ( String resourceName : resourceNames )
624         {
625             File destFile = FileTestUtils.createUniqueFile( getName(), resourceName );
626 
627             destFile.deleteOnExit();
628 
629             wagon.get( resourceName, destFile );
630         }
631     }
632 
633     /**
634      * Assert that a resource does not exist in the remote wagon system
635      *
636      * @param wagon        wagon to get the resource from
637      * @param resourceName name of the resource
638      * @throws IOException             if a temp file can't be created
639      * @throws AuthorizationException
640      * @throws TransferFailedException
641      * @since 1.0-beta-1
642      */
643     protected void assertNotExists( Wagon wagon, String resourceName )
644         throws IOException, TransferFailedException, AuthorizationException
645     {
646         File tmpFile = File.createTempFile( "wagon", null );
647         try
648         {
649             wagon.get( resourceName, tmpFile );
650             fail( "Resource exists: " + resourceName );
651         }
652         catch ( ResourceDoesNotExistException e )
653         {
654             // ok
655         }
656         finally
657         {
658             tmpFile.delete();
659         }
660     }
661 
662     private void writeTestFile( String child )
663         throws IOException
664     {
665         File dir = new File( sourceFile, child );
666         dir.getParentFile().mkdirs();
667         FileUtils.fileWrite( dir.getAbsolutePath(), child );
668     }
669 
670     public void testFailedGet()
671         throws Exception
672     {
673         setupWagonTestingFixtures();
674 
675         setupRepositories();
676 
677         message( "Getting test artifact from test repository " + testRepository );
678 
679         Wagon wagon = getWagon();
680 
681         wagon.addTransferListener( checksumObserver );
682 
683         wagon.connect( testRepository, getAuthInfo() );
684 
685         destFile = FileTestUtils.createUniqueFile( getName(), getName() );
686 
687         destFile.deleteOnExit();
688 
689         try
690         {
691             wagon.get( "fubar.txt", destFile );
692             fail( "File was found when it shouldn't have been" );
693         }
694         catch ( ResourceDoesNotExistException e )
695         {
696             // expected
697             assertTrue( true );
698         }
699         finally
700         {
701             wagon.removeTransferListener( checksumObserver );
702 
703             wagon.disconnect();
704 
705             tearDownWagonTestingFixtures();
706         }
707     }
708 
709     public void testFailedGetIfNewer()
710         throws Exception
711     {
712         if ( supportsGetIfNewer() )
713         {
714             setupWagonTestingFixtures();
715             setupRepositories();
716             message( "Getting test artifact from test repository " + testRepository );
717             Wagon wagon = getWagon();
718             wagon.addTransferListener( checksumObserver );
719             wagon.connect( testRepository, getAuthInfo() );
720             destFile = FileTestUtils.createUniqueFile( getName(), getName() );
721             destFile.deleteOnExit();
722             try
723             {
724                 wagon.getIfNewer( "fubar.txt", destFile, 0 );
725                 fail( "File was found when it shouldn't have been" );
726             }
727             catch ( ResourceDoesNotExistException e )
728             {
729                 // expected
730                 assertTrue( true );
731             }
732             finally
733             {
734                 wagon.removeTransferListener( checksumObserver );
735 
736                 wagon.disconnect();
737 
738                 tearDownWagonTestingFixtures();
739             }
740         }
741     }
742 
743     /**
744      * Test {@link Wagon#getFileList(String)}.
745      *
746      * @throws Exception
747      * @since 1.0-beta-2
748      */
749     public void testWagonGetFileList()
750         throws Exception
751     {
752         setupWagonTestingFixtures();
753 
754         setupRepositories();
755 
756         String dirName = "file-list";
757 
758         String filenames[] =
759             new String[]{ "test-resource.txt", "test-resource.pom", "test-resource b.txt", "more-resources.dat",
760                 ".index.txt" };
761 
762         for ( String filename : filenames )
763         {
764             putFile( dirName + "/" + filename, dirName + "/" + filename, filename + "\n" );
765         }
766 
767         Wagon wagon = getWagon();
768 
769         wagon.connect( testRepository, getAuthInfo() );
770 
771         List<String> list = wagon.getFileList( dirName );
772         assertNotNull( "file list should not be null.", list );
773         assertTrue( "file list should contain more items (actually contains '" + list + "').",
774                     list.size() >= filenames.length );
775 
776         for ( String filename : filenames )
777         {
778             assertTrue( "Filename '" + filename + "' should be in list.", list.contains( filename ) );
779         }
780 
781         // WAGON-250
782         list = wagon.getFileList( "" );
783         assertNotNull( "file list should not be null.", list );
784         assertTrue( "file list should contain items (actually contains '" + list + "').", !list.isEmpty() );
785         assertTrue( list.contains( "file-list/" ) );
786         assertFalse( list.contains( "file-list" ) );
787         assertFalse( list.contains( "." ) );
788         assertFalse( list.contains( ".." ) );
789         assertFalse( list.contains( "./" ) );
790         assertFalse( list.contains( "../" ) );
791 
792         wagon.disconnect();
793 
794         tearDownWagonTestingFixtures();
795     }
796 
797     /**
798      * Test {@link Wagon#getFileList(String)} when the directory does not exist.
799      *
800      * @throws Exception
801      * @since 1.0-beta-2
802      */
803     public void testWagonGetFileListWhenDirectoryDoesNotExist()
804         throws Exception
805     {
806         setupWagonTestingFixtures();
807 
808         setupRepositories();
809 
810         String dirName = "file-list-unexisting";
811 
812         Wagon wagon = getWagon();
813 
814         wagon.connect( testRepository, getAuthInfo() );
815 
816         try
817         {
818             wagon.getFileList( dirName );
819             fail( "getFileList on unexisting directory must throw ResourceDoesNotExistException" );
820         }
821         catch ( ResourceDoesNotExistException e )
822         {
823             // expected
824         }
825         finally
826         {
827             wagon.disconnect();
828 
829             tearDownWagonTestingFixtures();
830         }
831     }
832 
833     /**
834      * Test for an existing resource.
835      *
836      * @throws Exception
837      * @since 1.0-beta-2
838      */
839     public void testWagonResourceExists()
840         throws Exception
841     {
842         setupWagonTestingFixtures();
843 
844         setupRepositories();
845 
846         Wagon wagon = getWagon();
847 
848         putFile();
849 
850         wagon.connect( testRepository, getAuthInfo() );
851 
852         assertTrue( sourceFile.getName() + " does not exist", wagon.resourceExists( sourceFile.getName() ) );
853 
854         wagon.disconnect();
855 
856         tearDownWagonTestingFixtures();
857     }
858 
859     /**
860      * Test for an invalid resource.
861      *
862      * @throws Exception
863      * @since 1.0-beta-2
864      */
865     public void testWagonResourceNotExists()
866         throws Exception
867     {
868         setupWagonTestingFixtures();
869 
870         setupRepositories();
871 
872         Wagon wagon = getWagon();
873 
874         wagon.connect( testRepository, getAuthInfo() );
875 
876         assertFalse( wagon.resourceExists( "a/bad/resource/name/that/should/not/exist.txt" ) );
877 
878         wagon.disconnect();
879 
880         tearDownWagonTestingFixtures();
881     }
882 
883     // ----------------------------------------------------------------------
884     // File <--> File round trip testing
885     // ----------------------------------------------------------------------
886     // We are testing taking a file, our sourcefile, and placing it into the
887     // test repository that we have setup.
888     // ----------------------------------------------------------------------
889 
890     protected void putFile( String resourceName, String testFileName, String content )
891         throws Exception
892     {
893         sourceFile = new File( FileTestUtils.getTestOutputDir(), testFileName );
894         sourceFile.getParentFile().mkdirs();
895         FileUtils.fileWrite( sourceFile.getAbsolutePath(), content );
896 
897         Wagon wagon = getWagon();
898 
899         ProgressAnswer progressAnswer = replayMockForPut( resourceName, content, wagon );
900 
901         message( "Putting test artifact: " + resourceName + " into test repository " + testRepository );
902 
903         connectWagon( wagon );
904 
905         wagon.put( sourceFile, resourceName );
906 
907         disconnectWagon( wagon );
908 
909         verifyMock( progressAnswer, content.length() );
910     }
911 
912     protected ProgressAnswer replayMockForPut( String resourceName, String content, Wagon wagon )
913     {
914         Resource resource = new Resource( resourceName );
915         mockTransferListener.transferInitiated(
916             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_PUT,
917                                  sourceFile ) );
918         resource = new Resource( resourceName );
919         resource.setContentLength( content.length() );
920         resource.setLastModified( sourceFile.lastModified() );
921         mockTransferListener.transferStarted(
922             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_PUT,
923                                  sourceFile ) );
924         mockTransferListener.transferProgress(
925             eq( createTransferEvent( wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT,
926                                  sourceFile ) ), anyObject( byte[].class ), anyInt() );
927         ProgressAnswer progressAnswer = new ProgressAnswer();
928         expectLastCall().andStubAnswer( progressAnswer );
929 
930         mockTransferListener.debug( anyString() );
931         expectLastCall().anyTimes();
932 
933         mockTransferListener.transferCompleted(
934             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_PUT,
935                                  sourceFile ) );
936 
937         replay( mockTransferListener );
938         return progressAnswer;
939     }
940 
941     protected TransferEvent createTransferEvent( Wagon wagon, Resource resource, int eventType, int requestType,
942                                                  File file )
943     {
944         TransferEvent transferEvent = new TransferEvent( wagon, resource, eventType, requestType );
945         transferEvent.setLocalFile( file );
946         return transferEvent;
947     }
948 
949     protected int putFile()
950         throws Exception
951     {
952         String content = TEST_CONTENT;
953         putFile( resource, "test-resource", content );
954         return content.length();
955     }
956 
957     protected void getFile( int expectedSize )
958         throws Exception
959     {
960         destFile = FileTestUtils.createUniqueFile( getName(), getName() );
961         destFile.deleteOnExit();
962 
963         Wagon wagon = getWagon();
964 
965         ProgressAnswer progressAnswer = replaceMockForGet( wagon, expectedSize );
966 
967         message( "Getting test artifact from test repository " + testRepository );
968 
969         connectWagon( wagon );
970 
971         wagon.get( this.resource, destFile );
972 
973         disconnectWagon( wagon );
974 
975         verifyMock( progressAnswer, expectedSize );
976     }
977 
978 
979     protected void verifyMock( ProgressAnswer progressAnswer, int length )
980     {
981         verify( mockTransferListener );
982 
983         assertEquals( length, progressAnswer.getSize() );
984 
985         reset( mockTransferListener );
986     }
987 
988     protected void disconnectWagon( Wagon wagon )
989         throws ConnectionException
990     {
991         wagon.removeTransferListener( mockTransferListener );
992 
993         wagon.removeTransferListener( checksumObserver );
994 
995         wagon.disconnect();
996     }
997 
998     protected void connectWagon( Wagon wagon )
999         throws ConnectionException, AuthenticationException
1000     {
1001         wagon.addTransferListener( checksumObserver );
1002 
1003         wagon.addTransferListener( mockTransferListener );
1004 
1005         wagon.connect( testRepository, getAuthInfo() );
1006     }
1007 
1008     /**
1009      *
1010      * some test (mock on transfertprogress call) relies on the fact that InputStream #read(byte[] b, int off, int len)
1011      * read all bytes. But javadoc says: ""
1012      */
1013     protected boolean assertOnTransferProgress()
1014     {
1015         return false;
1016     }
1017 
1018     protected ProgressAnswer replaceMockForGet( Wagon wagon, int expectedSize )
1019     {
1020         Resource resource = new Resource( this.resource );
1021         mockTransferListener.transferInitiated(
1022             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_GET,
1023                                  destFile ) );
1024         resource = new Resource( this.resource );
1025         resource.setContentLength( getExpectedContentLengthOnGet( expectedSize ) );
1026         resource.setLastModified( getExpectedLastModifiedOnGet( testRepository, resource ) );
1027         TransferEvent te =
1028             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_GET, null );
1029         mockTransferListener.transferStarted( te );
1030         mockTransferListener.transferProgress(
1031             eq( new TransferEvent( wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_GET ) ),
1032             anyObject( byte[].class ), anyInt() );
1033 
1034         ProgressAnswer progressAnswer = new ProgressAnswer();
1035 
1036         if ( assertOnTransferProgress() )
1037         {
1038             expectLastCall().andAnswer( progressAnswer );
1039         }
1040         else
1041         {
1042             expectLastCall().andAnswer( progressAnswer );
1043             expectLastCall().anyTimes();
1044         }
1045         mockTransferListener.debug( anyString() );
1046         expectLastCall().anyTimes();
1047 
1048         mockTransferListener.transferCompleted(
1049             createTransferEvent( wagon, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_GET,
1050                                  destFile ) );
1051 
1052         replay( mockTransferListener );
1053         return progressAnswer;
1054     }
1055 
1056     protected int getExpectedContentLengthOnGet( int expectedSize )
1057     {
1058         return expectedSize;
1059     }
1060 
1061     protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
1062     {
1063         // default implementation - prone to failing if the time between test file creation and completion of putFile()
1064         // cross the "second" boundary, causing the "remote" and local files to have different times.
1065 
1066         return sourceFile.lastModified();
1067     }
1068 
1069     protected void fileRoundTripTesting()
1070         throws Exception
1071     {
1072         message( "File round trip testing ..." );
1073 
1074         int expectedSize = putFile();
1075 
1076         assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
1077 
1078         assertEquals( "compare checksums", TEST_CKSUM, checksumObserver.getActualChecksum() );
1079 
1080         checksumObserver = new ChecksumObserver();
1081 
1082         getFile( expectedSize );
1083 
1084         assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
1085 
1086         assertEquals( "compare checksums", TEST_CKSUM, checksumObserver.getActualChecksum() );
1087 
1088         // Now compare the conents of the artifact that was placed in
1089         // the repository with the contents of the artifact that was
1090         // retrieved from the repository.
1091 
1092         String sourceContent = FileUtils.fileRead( sourceFile );
1093 
1094         String destContent = FileUtils.fileRead( destFile );
1095 
1096         assertEquals( sourceContent, destContent );
1097     }
1098 
1099     // ----------------------------------------------------------------------
1100     //
1101     // ----------------------------------------------------------------------
1102 
1103     protected Repository createFileRepository( String url )
1104     {
1105         File path = new File( url.substring( 7 ) );
1106 
1107         path.mkdirs();
1108 
1109         Repository repository = new Repository();
1110 
1111         repository.setUrl( url );
1112 
1113         return repository;
1114     }
1115 
1116     protected static String cksum( String content )
1117     {
1118         String checkSum;
1119         try
1120         {
1121             ChecksumObserver obs = new ChecksumObserver();
1122             byte[] buf = content.getBytes( StandardCharsets.ISO_8859_1 );
1123             obs.transferProgress( null, buf, buf.length );
1124             obs.transferCompleted( null );
1125             checkSum = obs.getActualChecksum();
1126         }
1127         catch ( Exception e )
1128         {
1129             checkSum = null;
1130         }
1131         return checkSum;
1132     }
1133 
1134 }