001package org.eclipse.aether.transport.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 static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertTrue;
024import static org.junit.Assert.fail;
025
026import java.io.File;
027import java.net.URI;
028import java.util.Map;
029import java.util.UUID;
030
031import org.apache.maven.wagon.ResourceDoesNotExistException;
032import org.apache.maven.wagon.TransferFailedException;
033import org.apache.maven.wagon.Wagon;
034import org.eclipse.aether.ConfigurationProperties;
035import org.eclipse.aether.DefaultRepositorySystemSession;
036import org.eclipse.aether.internal.test.util.TestFileUtils;
037import org.eclipse.aether.internal.test.util.TestLoggerFactory;
038import org.eclipse.aether.internal.test.util.TestUtils;
039import org.eclipse.aether.repository.Authentication;
040import org.eclipse.aether.repository.Proxy;
041import org.eclipse.aether.repository.RemoteRepository;
042import org.eclipse.aether.spi.connector.transport.GetTask;
043import org.eclipse.aether.spi.connector.transport.PeekTask;
044import org.eclipse.aether.spi.connector.transport.PutTask;
045import org.eclipse.aether.spi.connector.transport.Transporter;
046import org.eclipse.aether.spi.connector.transport.TransporterFactory;
047import org.eclipse.aether.transfer.NoTransporterException;
048import org.eclipse.aether.transfer.TransferCancelledException;
049import org.eclipse.aether.util.repository.AuthenticationBuilder;
050import org.junit.After;
051import org.junit.Before;
052import org.junit.Test;
053
054/**
055 */
056public abstract class AbstractWagonTransporterTest
057{
058
059    private DefaultRepositorySystemSession session;
060
061    private TransporterFactory factory;
062
063    private Transporter transporter;
064
065    private String id;
066
067    private Map<String, String> fs;
068
069    protected abstract Wagon newWagon();
070
071    private RemoteRepository newRepo( String url )
072    {
073        return new RemoteRepository.Builder( "test", "default", url ).build();
074    }
075
076    private void newTransporter( String url )
077        throws Exception
078    {
079        newTransporter( newRepo( url ) );
080    }
081
082    private void newTransporter( RemoteRepository repo )
083        throws Exception
084    {
085        if ( transporter != null )
086        {
087            transporter.close();
088            transporter = null;
089        }
090        transporter = factory.newInstance( session, repo );
091    }
092
093    @Before
094    public void setUp()
095        throws Exception
096    {
097        session = TestUtils.newSession();
098        factory = new WagonTransporterFactory( new WagonProvider()
099        {
100            public Wagon lookup( String roleHint )
101                throws Exception
102            {
103                if ( "mem".equalsIgnoreCase( roleHint ) )
104                {
105                    return newWagon();
106                }
107                throw new IllegalArgumentException( "Unknown wagon role: " + roleHint );
108            }
109
110            public void release( Wagon wagon )
111            {
112            }
113        }, new WagonConfigurator()
114        {
115            public void configure( Wagon wagon, Object configuration )
116                throws Exception
117            {
118                ( (Configurable) wagon ).setConfiguration( configuration );
119            }
120        }, new TestLoggerFactory() );
121        id = UUID.randomUUID().toString().replace( "-", "" );
122        fs = MemWagonUtils.getFilesystem( id );
123        fs.put( "file.txt", "test" );
124        fs.put( "empty.txt", "" );
125        fs.put( "some space.txt", "space" );
126        newTransporter( "mem://" + id );
127    }
128
129    @After
130    public void tearDown()
131    {
132        if ( transporter != null )
133        {
134            transporter.close();
135            transporter = null;
136        }
137        factory = null;
138        session = null;
139    }
140
141    @Test
142    public void testClassify()
143    {
144        assertEquals( Transporter.ERROR_OTHER, transporter.classify( new TransferFailedException( "test" ) ) );
145        assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new ResourceDoesNotExistException( "test" ) ) );
146    }
147
148    @Test
149    public void testPeek()
150        throws Exception
151    {
152        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
153    }
154
155    @Test
156    public void testPeek_NotFound()
157        throws Exception
158    {
159        try
160        {
161            transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) );
162            fail( "Expected error" );
163        }
164        catch ( ResourceDoesNotExistException e )
165        {
166            assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) );
167        }
168    }
169
170    @Test
171    public void testPeek_Closed()
172        throws Exception
173    {
174        transporter.close();
175        try
176        {
177            transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) );
178            fail( "Expected error" );
179        }
180        catch ( IllegalStateException e )
181        {
182            assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) );
183        }
184    }
185
186    @Test
187    public void testGet_ToMemory()
188        throws Exception
189    {
190        RecordingTransportListener listener = new RecordingTransportListener();
191        GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener );
192        transporter.get( task );
193        assertEquals( "test", task.getDataString() );
194        assertEquals( 0, listener.dataOffset );
195        assertEquals( 4, listener.dataLength );
196        assertEquals( 1, listener.startedCount );
197        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
198        assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) );
199    }
200
201    @Test
202    public void testGet_ToFile()
203        throws Exception
204    {
205        File file = TestFileUtils.createTempFile( "failure" );
206        RecordingTransportListener listener = new RecordingTransportListener();
207        GetTask task = new GetTask( URI.create( "file.txt" ) ).setDataFile( file ).setListener( listener );
208        transporter.get( task );
209        assertEquals( "test", TestFileUtils.readString( file ) );
210        assertEquals( 0, listener.dataOffset );
211        assertEquals( 4, listener.dataLength );
212        assertEquals( 1, listener.startedCount );
213        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
214        assertEquals( "test", listener.baos.toString( "UTF-8" ) );
215    }
216
217    @Test
218    public void testGet_EmptyResource()
219        throws Exception
220    {
221        File file = TestFileUtils.createTempFile( "failure" );
222        assertTrue( file.delete() && !file.exists() );
223        RecordingTransportListener listener = new RecordingTransportListener();
224        GetTask task = new GetTask( URI.create( "empty.txt" ) ).setDataFile( file ).setListener( listener );
225        transporter.get( task );
226        assertEquals( "", TestFileUtils.readString( file ) );
227        assertEquals( 0, listener.dataOffset );
228        assertEquals( 0, listener.dataLength );
229        assertEquals( 1, listener.startedCount );
230        assertEquals( 0, listener.progressedCount );
231        assertEquals( "", listener.baos.toString( "UTF-8" ) );
232    }
233
234    @Test
235    public void testGet_EncodedResourcePath()
236        throws Exception
237    {
238        GetTask task = new GetTask( URI.create( "some%20space.txt" ) );
239        transporter.get( task );
240        assertEquals( "space", task.getDataString() );
241    }
242
243    @Test
244    public void testGet_FileHandleLeak()
245        throws Exception
246    {
247        for ( int i = 0; i < 100; i++ )
248        {
249            File file = TestFileUtils.createTempFile( "failure" );
250            transporter.get( new GetTask( URI.create( "file.txt" ) ).setDataFile( file ) );
251            assertTrue( i + ", " + file.getAbsolutePath(), file.delete() );
252        }
253    }
254
255    @Test
256    public void testGet_NotFound()
257        throws Exception
258    {
259        try
260        {
261            transporter.get( new GetTask( URI.create( "missing.txt" ) ) );
262            fail( "Expected error" );
263        }
264        catch ( ResourceDoesNotExistException e )
265        {
266            assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) );
267        }
268    }
269
270    @Test
271    public void testGet_Closed()
272        throws Exception
273    {
274        transporter.close();
275        try
276        {
277            transporter.get( new GetTask( URI.create( "file.txt" ) ) );
278            fail( "Expected error" );
279        }
280        catch ( IllegalStateException e )
281        {
282            assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) );
283        }
284    }
285
286    @Test
287    public void testGet_StartCancelled()
288        throws Exception
289    {
290        RecordingTransportListener listener = new RecordingTransportListener();
291        listener.cancelStart = true;
292        GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener );
293        transporter.get( task );
294        assertEquals( 1, listener.startedCount );
295    }
296
297    @Test
298    public void testGet_ProgressCancelled()
299        throws Exception
300    {
301        RecordingTransportListener listener = new RecordingTransportListener();
302        listener.cancelProgress = true;
303        GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener );
304        try
305        {
306            transporter.get( task );
307            fail( "Expected error" );
308        }
309        catch ( TransferCancelledException e )
310        {
311            assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) );
312        }
313        assertEquals( 0, listener.dataOffset );
314        assertEquals( 4, listener.dataLength );
315        assertEquals( 1, listener.startedCount );
316        assertEquals( 1, listener.progressedCount );
317    }
318
319    @Test
320    public void testPut_FromMemory()
321        throws Exception
322    {
323        RecordingTransportListener listener = new RecordingTransportListener();
324        PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" );
325        transporter.put( task );
326        assertEquals( 0, listener.dataOffset );
327        assertEquals( 6, listener.dataLength );
328        assertEquals( 1, listener.startedCount );
329        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
330        assertEquals( "upload", fs.get( "file.txt" ) );
331    }
332
333    @Test
334    public void testPut_FromFile()
335        throws Exception
336    {
337        File file = TestFileUtils.createTempFile( "upload" );
338        RecordingTransportListener listener = new RecordingTransportListener();
339        PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataFile( file );
340        transporter.put( task );
341        assertEquals( 0, listener.dataOffset );
342        assertEquals( 6, listener.dataLength );
343        assertEquals( 1, listener.startedCount );
344        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
345        assertEquals( "upload", fs.get( "file.txt" ) );
346    }
347
348    @Test
349    public void testPut_EmptyResource()
350        throws Exception
351    {
352        RecordingTransportListener listener = new RecordingTransportListener();
353        PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener );
354        transporter.put( task );
355        assertEquals( 0, listener.dataOffset );
356        assertEquals( 0, listener.dataLength );
357        assertEquals( 1, listener.startedCount );
358        assertEquals( 0, listener.progressedCount );
359        assertEquals( "", fs.get( "file.txt" ) );
360    }
361
362    @Test
363    public void testPut_NonExistentParentDir()
364        throws Exception
365    {
366        RecordingTransportListener listener = new RecordingTransportListener();
367        PutTask task =
368            new PutTask( URI.create( "dir/sub/dir/file.txt" ) ).setListener( listener ).setDataString( "upload" );
369        transporter.put( task );
370        assertEquals( 0, listener.dataOffset );
371        assertEquals( 6, listener.dataLength );
372        assertEquals( 1, listener.startedCount );
373        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
374        assertEquals( "upload", fs.get( "dir/sub/dir/file.txt" ) );
375    }
376
377    @Test
378    public void testPut_EncodedResourcePath()
379        throws Exception
380    {
381        RecordingTransportListener listener = new RecordingTransportListener();
382        PutTask task = new PutTask( URI.create( "some%20space.txt" ) ).setListener( listener ).setDataString( "OK" );
383        transporter.put( task );
384        assertEquals( 0, listener.dataOffset );
385        assertEquals( 2, listener.dataLength );
386        assertEquals( 1, listener.startedCount );
387        assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 );
388        assertEquals( "OK", fs.get( "some space.txt" ) );
389    }
390
391    @Test
392    public void testPut_FileHandleLeak()
393        throws Exception
394    {
395        for ( int i = 0; i < 100; i++ )
396        {
397            File src = TestFileUtils.createTempFile( "upload" );
398            transporter.put( new PutTask( URI.create( "file.txt" ) ).setDataFile( src ) );
399            assertTrue( i + ", " + src.getAbsolutePath(), src.delete() );
400        }
401    }
402
403    @Test
404    public void testPut_Closed()
405        throws Exception
406    {
407        transporter.close();
408        try
409        {
410            transporter.put( new PutTask( URI.create( "missing.txt" ) ) );
411            fail( "Expected error" );
412        }
413        catch ( IllegalStateException e )
414        {
415            assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) );
416        }
417    }
418
419    @Test
420    public void testPut_StartCancelled()
421        throws Exception
422    {
423        RecordingTransportListener listener = new RecordingTransportListener();
424        listener.cancelStart = true;
425        PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" );
426        transporter.put( task );
427        assertEquals( 1, listener.startedCount );
428    }
429
430    @Test
431    public void testPut_ProgressCancelled()
432        throws Exception
433    {
434        RecordingTransportListener listener = new RecordingTransportListener();
435        listener.cancelProgress = true;
436        PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" );
437        try
438        {
439            transporter.put( task );
440            fail( "Expected error" );
441        }
442        catch ( TransferCancelledException e )
443        {
444            assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) );
445        }
446        assertEquals( 0, listener.dataOffset );
447        assertEquals( 6, listener.dataLength );
448        assertEquals( 1, listener.startedCount );
449        assertEquals( 1, listener.progressedCount );
450    }
451
452    @Test( expected = NoTransporterException.class )
453    public void testInit_BadProtocol()
454        throws Exception
455    {
456        newTransporter( "bad:/void" );
457    }
458
459    @Test
460    public void testInit_CaseInsensitiveProtocol()
461        throws Exception
462    {
463        newTransporter( "mem:/void" );
464        newTransporter( "MEM:/void" );
465        newTransporter( "mEm:/void" );
466    }
467
468    @Test
469    public void testInit_Configuration()
470        throws Exception
471    {
472        session.setConfigProperty( "aether.connector.wagon.config.test", "passed" );
473        newTransporter( "mem://" + id + "?config=passed" );
474        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
475    }
476
477    @Test
478    public void testInit_UserAgent()
479        throws Exception
480    {
481        session.setConfigProperty( ConfigurationProperties.USER_AGENT, "Test/1.0" );
482        newTransporter( "mem://" + id + "?userAgent=Test/1.0" );
483        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
484    }
485
486    @Test
487    public void testInit_Timeout()
488        throws Exception
489    {
490        session.setConfigProperty( ConfigurationProperties.REQUEST_TIMEOUT, "12345678" );
491        newTransporter( "mem://" + id + "?requestTimeout=12345678" );
492        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
493    }
494
495    @Test
496    public void testInit_ServerAuth()
497        throws Exception
498    {
499        String url =
500            "mem://" + id + "?serverUsername=testuser&serverPassword=testpass"
501                + "&serverPrivateKey=testkey&serverPassphrase=testphrase";
502        Authentication auth =
503            new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).addPrivateKey( "testkey",
504                                                                                                           "testphrase" ).build();
505        RemoteRepository repo =
506            new RemoteRepository.Builder( "test", "default", url ).setAuthentication( auth ).build();
507        newTransporter( repo );
508        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
509    }
510
511    @Test
512    public void testInit_Proxy()
513        throws Exception
514    {
515        String url = "mem://" + id + "?proxyHost=testhost&proxyPort=8888";
516        RemoteRepository repo =
517            new RemoteRepository.Builder( "test", "default", url ).setProxy( new Proxy( "http", "testhost", 8888 ) ).build();
518        newTransporter( repo );
519        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
520    }
521
522    @Test
523    public void testInit_ProxyAuth()
524        throws Exception
525    {
526        String url = "mem://" + id + "?proxyUsername=testuser&proxyPassword=testpass";
527        Authentication auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build();
528        RemoteRepository repo =
529            new RemoteRepository.Builder( "test", "default", url ).setProxy( new Proxy( "http", "testhost", 8888, auth ) ).build();
530        newTransporter( repo );
531        transporter.peek( new PeekTask( URI.create( "file.txt" ) ) );
532    }
533
534}