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