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