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