001package org.apache.maven.wagon;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.wagon.authentication.AuthenticationException;
023import org.apache.maven.wagon.authentication.AuthenticationInfo;
024import org.apache.maven.wagon.authorization.AuthorizationException;
025import org.apache.maven.wagon.events.TransferEvent;
026import org.apache.maven.wagon.events.TransferListener;
027import org.apache.maven.wagon.observers.ChecksumObserver;
028import org.apache.maven.wagon.observers.Debug;
029import org.apache.maven.wagon.repository.Repository;
030import org.apache.maven.wagon.repository.RepositoryPermissions;
031import org.apache.maven.wagon.resource.Resource;
032import org.codehaus.plexus.PlexusTestCase;
033import org.codehaus.plexus.util.FileUtils;
034import org.easymock.IAnswer;
035
036// CHECKSTYLE_OFF: AvoidStarImport
037import static org.easymock.EasyMock.*;
038//CHECKSTYLE_ON: AvoidStarImport
039
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043import java.io.File;
044import java.io.IOException;
045import java.nio.charset.StandardCharsets;
046import java.security.NoSuchAlgorithmException;
047import java.text.SimpleDateFormat;
048import java.util.ArrayList;
049import java.util.Collections;
050import java.util.List;
051
052/**
053 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
054 */
055public abstract class WagonTestCase
056    extends PlexusTestCase
057{
058    protected static Logger logger = LoggerFactory.getLogger( WagonTestCase.class );
059
060
061    static final class ProgressAnswer implements IAnswer
062    {
063        private int size;
064
065        public Object answer() throws Throwable
066        {
067            int length = (Integer) getCurrentArguments()[2];
068            size += length;
069            return null;
070        }
071
072        public int getSize()
073        {
074            return size;
075        }
076    }
077
078    protected static final String TEST_CONTENT = "test-resource.txt\n";
079
080    protected static final String TEST_CKSUM = cksum( TEST_CONTENT );
081
082    protected static final String POM = "pom.xml";
083
084    protected Repository localRepository;
085
086    protected Repository testRepository;
087
088    protected String localRepositoryPath;
089
090    protected File sourceFile;
091
092    protected File destFile;
093
094    protected String resource;
095
096    protected boolean testSkipped;
097
098    protected File artifactSourceFile;
099
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}