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